“不要重复自己。” 每个程序员在第一次学习编码时都会把这个概念付诸实践。 每当您发现代码在多个地方重复时,就该将代码抽象为类或函数了。 但这如何适用于用户界面? 如何避免一遍又一遍地重写相同HTML和CSS?
如果您使用的是像Angular这样的UI框架或像React这样的UI库,那么答案很简单:构建一个组件。 组件是HTML,CSS和JavaScript的一部分,以易于重用的方式组合在一起。
但是,如果您不使用Angular,React,Vue或其他最新最好JavaScript框架怎么办? 如果您要编写普通HTML,CSS和JavaScript,该怎么办? 或者,如果您想编写一个与框架无关的组件,并且无论其编写内容如何,都可以在任何Web应用程序中使用该组件怎么办?

Web组件 (Web Components)

Web组件使您可以创建具有封装功能的自定义元素,这些功能可以在任何地方重复使用。 它们是使用模板插槽创建的,并在shadow DOM中定义,该shadow DOM将元素的样式和脚本与DOM的其余部分隔离开来,以避免发生冲突。
可以使用大多数主要浏览器提供的本机浏览器API来构建Web组件,也可以使用所谓的Web组件库来创建Web组件:这些解决方案可以作为浏览器API之上的抽象来帮助简化Web组件的编写。
在本文中,我们将比较几种不同的Web组件解决方案:Web ComponentsSvelteStencilLitELementLightning Web Components(LWC)

准则 (The Criteria)

In evaluating these solutions, it’s helpful to have a defined set of criteria. We’ll look at each solution while keeping an eye out for the following:
在评估这些解决方案时,定义一组标准会很有帮助。 我们将研究每种解决方案,同时注意以下几点:

  • year released 发行年份
  • popularity 人气
  • license 许可
  • syntax style (declarative vs. imperative) 语法样式(声明式与命令式)
  • compiler or runtime required 需要编译器或运行时
  • browser support 浏览器支持
  • testing strategy 测试策略
  • quality of documentation 文件质量
  • relative bundle size 打包后bundle大小

    Web Components(Native Web Components)

    让我们首先从Web Components开始-即使用浏览器API构建的Web组件,而不使用其他框架或库。
    Web组件于2011年首次引入。与每种新技术一样,Web浏览器需要时间来赶上并实现新提议的API和标准,因此Web组件花了一些时间才能吸引人。 如今,大多数常绿浏览器都支持Web组件。 Chrome,Firefox,Edge和Opera均支持Web组件。 Safari提供了部分支持。 在Internet Explorer中,不支持Web组件
    由于这是我们正在讨论的本机Web功能,因此该文档非常出色。 您可以在MDN上找到有关如何构建和实现Web组件的规范和教程的资源
    使用香草Web组件的另一个优点是您不需要引入其他库,编译器,运行时或任何其他构建工具。 WebComponents可以正常工作(只要浏览器支持它们)。
    除了缺乏完整的浏览器支持外,本机Web组件的一个缺点是它们使用命令式样式编写。 换句话说,您必须告诉组件如何执行每个步骤,包括重新呈现或更新DOM中的内容。 那些喜欢以声明式风格编写React组件的人可能会对WebComponents感到沮丧。
    为了减轻这种痛苦,已经出现了许多Web组件库以提供对本机浏览器API的抽象。 这些库在创建新的Web组件时提供了更好的开发人员体验,并且通常包含polyfill,这些填充使Web组件可以在不支持即装即用的浏览器中工作。 我们将在本文的后几节中考虑其中一些Web组件库。
    您可以在此处找到WebComponents实现示例 。 该代码完整复制如下:
    首先,通过扩展HTMLElement类来定义自定义Web组件。 HTML和CSS是在类主体中内联定义的,然后通过修改shadowRootHTML内容将其插入到影子DOM中。 由于代码是强制性的,因此可以看到定义了一个update方法,该方法在必要时可以处理DOM内容的更新。 生命周期回调方法也可用于设置和拆卸,您可以在connectedCallback和disconnectedCallback方法中附加和删除事件侦听器时看到。 最后,使用customElements.define方法将该组件注册到应用程序的其余部分,该方法允许您提供HTML标记名称并将其链接到您的类。

    svelte

    Svelte于2016年发布,是一种简单,优雅的Web组件编写方法。 它允许您以声明性的样式编写组件,并处理有关为您更新DOM的命令性逐步说明。 Svelte组件写入以.svelte扩展名结尾的文件中, .svelte扩展名是一种自定义文件类型,允许您将HTML,CSS和JavaScript都包含在同一文件中。 Svelte不包含任何运行时,这意味着它将在编译时将组件构建为浏览器可以理解的代码。 这提供了几乎没有开销添加到应用程序包大小的好处。
    在撰写本文时,Svelte每周从NPM拥有65,043次下载,使其成为当前最受欢迎的Web组件库之一。 它的文档也很出色,包括交互式教程 ,它们会带您逐步了解所有您想知道的内容。 Svelte甚至带有自己的动画实用程序!
    Svelte的社区在不断发展,这意味着有很多人学习Svelte并创建第三方组件和插件供他人使用。 您可以在此处找到Svelte开源项目的列表。
    尽管有很多好处,Svelte确实有一些薄弱之处需要解决,如其常见问题解答所述 。 在IDE中使用.svelte文件突出显示语法仍然不完美。 他们还没有提供推荐的测试策略-当前的方法是本质上编译每个组件,然后使用您选择的测试库将其安装到DOM。 此外, Svelte不会宣传其支持的浏览器 。 看来您需要自己解决这个问题,并提供最终需要的任何填充料,尤其是如果您计划支持IE11。
    您可以在此处找到Svelte WebComponents实现示例 。 该代码完整复制如下:
    如前所述,所有HTML,CSS和JavaScript都包含在同一个.svelte文件中,并且看起来非常像普通HTML,而不是类似JSX的语法。 组件标签名称在第一行定义。 事件处理程序使用on:event-name语法附加到HTML元素,并且状态发生变化时,UI会进行响应式更新(既好又声明)!

    Stencil

    Stencil是UI / UX设计师常用的在线图形设计工具。 2017年, Ionic Framework团队为开发人员发布了@stencil/core工具。 与Svelte一样,Stencil只是一个编译器,因此不需要运行时。 编译器会创建浏览器可以理解的Web组件,并根据需要甚至包括polyfill,以便您的代码可以在每个主要的浏览器(包括IE11)中运行。
    模具组件是用TypeScript编写的,这可能会让您激动不已,或者您可能会大失所望,具体取决于您对向JavaScript添加类型的看法。 它们也是使用JSX和声明性风格编写的,因此感觉很像在React中编写组件。
    Stencil当前每周显示NPM的下载量为25,568,这使其不如Svelte受欢迎,但仍是受欢迎的选择。 Stencil吹嘘苹果,亚马逊和微软等公司都在使用它,这暗示着这是一个经过验证的解决方案。 Stencil的文档也非常出色,甚至提供了有关如何将Stencil生成的组件合并到Angular,React或Vue应用程序中的说明。
    测试Stencil组件 ,他们的文档建议使用@stencil/core/testing包中的Jest和Stencil测试实用工具方法。
    您可以在此处找到Stencil Web组件实现示例 。 该代码完整复制如下:
    Web元素是通过类定义的,但是它没有像本地Web组件实现那样扩展任何基类。 而是使用@Component装饰器,该装饰器提供标记名称,可以在其中找到样式的标记以及是否应将组件放置在影子DOM中。 组件状态是使用@State装饰器实现的,HTML内容是在render方法中编写的。

    LitElement (LitElement)

    接下来,让我们看一下LitElement ,它是Google的Polymer Project提供的产品。 LitElement于2018年发布,目前每周从NPM进行95,643次下载-对于仅提供两年的产品而言,这是一个令人印象深刻的统计数据-使其比Svelte和Stencil结合使用得更广泛。
    LitElement具有许多我们之前讨论过的相同优点,例如使用声明性语法,编译为符合Web组件标准的代码以及在包括IE11在内的所有主要浏览器中均可使用。
    缺点之一是LitElement是在BSD-3-Clause下获得许可的,该许可是引发争议的同一许可,直到Facebook在2017年将React的许可更改为MIT许可为止。
    还需要注意的是,与Svelte和Stencil不同,LitElement本身不是编译器。 该文档将LitElement描述为一个使用lit-html模板构建Web组件的库( lit-html是Polymer Project的另一项产品,用作HTML模板库)。 因此,为了使用由LitElement创建的Web组件,您首先需要使用Babel和Rollup或Webpack对其进行编译
    对于测试,LitElement文档建议使用Open WC测试库 ,该库是用于测试Web组件的通用库。
    您可以在此处找到LitElement Web组件实现示例 。 该代码完整复制如下:
    这里的代码样式看起来像本机Web组件和Stencil组件之间的交叉。 定义了一个扩展基础LitElement类的类。 HTML内容以render方法提供,并包装在lit-html包使用的模板文字中。 使用@event-name语法附加事件处理程序。 最后,就像本机Web组件一样,新组件通过customElements.define方法进行注册。

    Lightning Web Components (LWC))

    最后,让我们考虑一下闪电Web组件或LWC。 LWC是该领域的新手,这是Salesforce在2019年开源的产品 。 LWC较新,每周仅从NPM进行1383次下载,远远少于我们到目前为止考虑的其他Web组件解决方案。
    LWC看起来与我们探索的其他解决方案相似,因为代码是以声明性方式编写的。 它还支持所有主要浏览器的最新版本,包括IE11。
    与其他库的不同之处在于LWC包含一个运行时,这意味着您在页面上运行了一个附加脚本来帮助您的应用程序工作,类似于您需要在浏览器中将React库与React应用程序一起包括在内。 这意味着您的用户可以下载额外的代码,但是LWC的运行时间只有7kB,非常小。
    他们的文档带有一些出色的解释,并明确说明了如何测试LWC应用程序 ,这非常有用。 它们还包括有关辅助功能指南。 虽然不是必需的,但很高兴看到LWC开发团队重视可访问性,并认为在他们的文档中值得注意。 总体而言,对于寻求稳定Web组件库的组织来说,LWC似乎是一个不错的选择。 随着时间的流逝,看看采用率以及LWC是否可以赶上其他Web组件解决方案的流行将是很有趣的。
    您可以在此处找到LWC Web组件实现示例 。 该代码完整复制如下:
    请注意,HTML,CSS和JavaScript使用了三个单独的文件。 这些文件在任何地方都没有明确地相互引用。 相反,LWC具有隐式协定,该协定具有相同名称但具有不同扩展名的文件一起使用。 HTML包装在template标记中,事件处理程序使用常规HTML中使用的全小写的oneventname语法编写。 JavaScript定义了一个扩展LightningElement的类,然后实现状态和任何方法。 有趣的是,没有render方法,因为HTML神奇地链接到了JavaScript。 就像本机Web组件和LitElement一样,然后使用文件底部的customElements.define方法注册LWC Web组件。

    结论 (Conclusion)

    那么您应该使用哪种Web组件解决方案? 在组织需求的背景下,自己评估这些解决方案很重要。
    在比较这些Web组件库时, Svelte感觉现在更像是一个实验库,可能还没有为企业应用程序准备。 Stencil,LitElement和LWC都将自己呈现为更适合企业使用的解决方案,它们在编写单元测试时侧重于跨浏览器支持和推荐的测试策略。
    LitElement
    除非您担心BSD-3-Clause许可证,否则LitElement似乎是一个不错的选择。 (谁知道呢?也许社区的强烈反对将导致这种情况在未来发生改变。)
    Stencil
    看起来与LitElement相当,但是没有许可证问题,这将是一个不错的选择,尤其是如果您已经在使用Stencil进行设计或喜欢使用TypeScript。
    最后,如果您将来使用或可能使用Salesforce, LWC是显而易见的选择,因为它易于与其他Salesforce工作流和框架集成,例如使用Lightning App Builder构建UI或使用Lightning Locker实现安全性。 LWC对于企业来说也是一个不错的选择,因为它是开源的,但也得到了大公司的强大支持。 如果您喜欢早日采用新的Web组件技术趋势,不喜欢JSX语法或偏爱将HTML,CSS和JavaScript代码保存在单独的文件中,则也可以考虑使用LWC。
    一件事似乎很清楚:使用Web组件库而不是本机浏览器API将提供更好的开发体验以及更健壮和跨浏览器友好的解决方案。

    最后

    在研究每种解决方案时,我尝试使用预定义的一组标准来评估每个方案,尽可能做到公正。 为了快速参考,我在下面提供了一个图表,总结了我的发现。
    如果您想探索更多Web组件解决方案, 此博客文章提供了对三十种Web组件实现的深入了解。

    Web组件解决方案比较 (Web Component Solution Comparisons)

    web component框架对比 - 图1
    Web component solution comparisons tableWeb组件解决方案比较表
    https://webcomponents.dev/blog/all-the-ways-to-make-a-web-component-april2020/
    https//webcomponents.dev/blog/all-the-ways-to-make-a-web-component-april2020/
    https://levelup.gitconnected.com/web-component-solutions-a-comparison-e2fa25c34730
    https://www.webcomponents.org/introduction

    现有的web component框架汇总

    https://components.studio/
    image.png