你不知道的 Web Components - 现状

这篇文章会重点关注 Web Components 在生态、行业应用方面的现状,也会涉及一些 Web Components 之外的技术,为你做 Web Components 技术应用选型提供一些参考。关于具体 API 介绍示例代码,官方文档很全,本文不会提太多。

简介

Web Components 是一套技术,让我们可以创建封装功能的定制元素,在任何地方重用且不产生冲突影响。 Web Components 现阶段主要包括三部分,在社区里也经常被提到:

  • Custom elements: 实现自定义 HTML elements 的 一组JS API。
  • Shadow DOM: 在常规 DOM 元素上附加一个独立隐藏的特殊类型 DOM 元素,提供了把 Custom elements 的内容封装并隐藏嵌入 document 中的方法,这也是整个 Web Components 中最重要也是最难 polyfill 的部分。
  • Templates 和 Slots: 用来灵活复用、动态使用 HTML 片段。

其实还有两个在 Web Components 历史上出现但逐渐不再被提到的名词:

注意 Web Components 自己本身不是一个规范,二是一套整体技术,他包含的三部分内容是独立规范。 比如 Shadow DOM ,本质是一组 JS API,其实浏览器一直依赖都用它来封装一些元素的内部结构。比如 Element.attachShadow()

也许你会问既然已经存在,ShadowDOM 的推进还有什么难度?难度在于用于Web Components 的 ShadowDOM 需要把内部机制通过合适的 API 暴露给开发者用,同时要考虑相关的兼容问题。

同样的,可以只用 Custom Elements 来扩展 HTML。 只用 Template 也可以动态生成 DOM。

但依照这些规范结合在一起用,用Shodwo dom 结合 HTML Template、Slot 操控 Custom Elements 中的子元素应该放到 ShadowTree 的什么位置,我们就能够构建独立的、可重用的组件,并像内置的 HTML Elements 一样无缝集成到现有应用。

如果想了解  Web Components 的历史和更多技术细节可以转到  👉  《你不知道的Web Components - 过去和未来》

优点

  • 原生支持,无三方依赖

  • 使用简单,适合很多特殊场景,比如架构升级、跨框架融合等

  • 自定义组件名语义性好

  • 性能优势。

    • 尽管有关性能测试显示 ShadowDOM 因为包含更多信息,创建起来会比原生 DOM节点慢很多,API 命令式调用更会增加时间消耗。但  CustomElement 的 upgrade 机制和 HTML Templates 保证了组件内部逻辑并不需要立即执行,相比于普通的 React 组件需要走完所有必要节点逻辑,Web Components 的真实渲染性能是更好的。
    • 同时结合异步渲染、SSR,Web Components 可以轻松完成各种性能优化。
    • Template 相比 JSX 会产生更小的内存占用,更少的 CPU 运算负担。
  • 组件隔离,ShadowDOM带来的天然隔离。

  • 技术栈无关,无论跟什么后端语言都能方便结合。

  • 在商业场景下更小的迭代迁移成本,利于复用和分享,

缺点

  • 需要 polyfill 才能覆盖全部主流浏览器,ie11 之前的低版本浏览器不支持
  • SEO 需要很多额外处理
  • SSR 方案还不够完善

业内使用现状

主要有几类方向:

  • 开发基础组件库,通过标准化降低开发者的接入门槛
  • 作为应用框架或打造设计系统,改造优化自己的应用架构、统一多产品线的体验
  • 渐进式的技术升级迭代,跨框架组件共享,降低风险
  • 新商业模式探索,利用组件共享,探索新的软件开发、商业服务模式

Twitter

Twitter 2016 年开始将自己的嵌入式推文  从 iframe 切换成  ShadowDOM,减少了内存消耗、加快了渲染速度,并批量渲染的时候保持丝滑。Upcoming Change to Embedded Tweet Display on Web

Youtube

Youtube 作为 google 系的产品,很早就在全站用上了 Web Cmponents,并且开源了自己播放器组件 GitHub - GoogleWebComponents/google-youtube: YouTube video playback web component 此外 google 开源的 Web Components 还是很多的,Google Web Components · GitHub ,包括地图、drive、日历等等。

EA

EA 的游戏工作室分布在全球各地,为了保证不同团队和工作室的设计开发体验统一,EA 基于 Web Components 构建了自己的 Network Design System,同时也支持这自己的 UIaaS。

Github

github 对 Web Components 的使用很早,具体可以看:  How we use Web Components at GitHub | The GitHub Blog 2014 年 Custom Elements v0 specification 出现的时候 github 就开始关注:Search · topic:web-components org:github · GitHub,并且开源了其中一系列 Web Components GitHub - github/github-elements: GitHub’s Web Component collection. 2017 年 Custom Elements v1 版本在 chrome 和 safari 上相继实现之后,github 开始大范围使用

要知道 github 2018 年才刚刚完全移除 jquery Removing jQuery from GitHub.com frontend | The GitHub Blog 这既得益于 github 自身项目组件化的架构,也 Web Components 本身与框架无关的特性非常识合作老项目升级。

github 还开源了 用于开发Web Components 的库 Catalyst:GitHub - github/catalyst: Catalyst is a set of patterns and techniques for developing components within a complex application.

而他的思路借鉴了  Stimulus  和  LitElement

  • 既然提到了 Stimulus,就叉开讲讲这个东西,Stimulus 很适合对老项目改造,尤其是 ruby on rails、jsp 服务端渲染、没有 webpack 之类的前端工具链,技术栈多且混乱的项目。Stimulus 的思路就是通过 MutationObserver 监控元素的变化, 然后取元素、补绑事件或者修改引用。他的定位就很轻盈,就是配合HTML页面,提供动态交互支持,不像现在的很多框架,动辄就是整站重写。

同时 github 还开源了一个 View Component 框架用来在 ruby on rails 里面构建同构应用 GitHub - github/view_component: A framework for building reusable, testable & encapsulated view components in Ruby on Rails.

SalesForce

SalesForce 作为一家 ToB 服务的公司,面对各种不同技术栈的客户,选择 Web Components 原因有两点,一是需要一套统一的通用组件面向所有客户,二是在很多特定领域,很多客户很难对他们的传统技术体系做大规模升级,而引入 Web Components 可以避免这类技术改造风险。

他们开源了自己的 Web Components 组件库 Component Library,并提供一整套基于 的企业级研发工具 GitHub - salesforce/lwc: LWC - A Blazing Fast, Enterprise-Grade Web Components Foundation 除了通过 LWC,让客户可以在自己的环境中基于组件库配置、开发、部署应用,SalesForce 还开放了自己的 SalesForce 工作平台 ,平台为所有客户提供一站式配置、部署和升级的能力。

Oracle

Oracle 在 2017 年开始在自己的  GitHub - oracle/oraclejet: Oracle JET is a modular JavaScript Extension Toolkit for developers working on client-side applications. 构建工具中增加了对 CustomElement 的支持,在此之前是用的是 jQueryUI。Oracle 对 WebComponents 对态度其实很值得 ToB 同行学习,他并没有刻意想拜托 jQuery,而是让 WebComponents 与现有的 jQuery、Knockout 并行使用,只在新功能上推进 WebComponents ,保持老项目稳定,在历史遗留和新技术之间保持了合理的平衡。 而在 jet 的生态方面,他们也在持续建设 Web Component 驱动的共享组件中心 Building the future of Oracle JET Ecosystem | by João Tiago | Digital Transformation Research Group | Medium

生态支持-如何实现 Web Components

基础/组件库

Web Components 的社区说起来有几种阵营,也跟早期 Web Components 发展曲折有关,一些基础库在某个时间点提出,随后诞生出一系列周边生态库。主要包括:

Polymer/Lit

这应该还是大家比较熟悉的,Google 从 2013 年开始一直在持续推进的基于 Web Components 封装的类库,同时还开放了基于 Polymer 开发的组件集合 PolymerElements · GitHub 和开发周边。 2015 年 Google 正式发布 Polymer 1.0 ,注意时间点,当时还是Custom Elements v0 版标准 2017年Custom Elements v1 版标准在各大浏览器落地,Polymer 发布了 2.0,并且不再封装 Custom Elements API,不再默认使用shadowDOM、目标兼容各种框架,开始变成轻量级类库。

  • 由于起步几乎最早以及 google 背书,可能到现在也是影响用户数最大的 Web Components 基础库,Youtube 基于Polymer 对整站做了重构,Google 很多产品包括 Android 和 ChromeOS 平台也都用了 Polymer。

但个人觉得总体上相比与彼时流行的其他框架 Polymer 还是不温不火,Google 似乎也有同感、随着 Polymer 的轻量化升级,于是在 2018 年又发布了更现代化的 lit GitHub - lit/lit: Lit is a simple library for building fast, lightweight web components. 包括 lit-html 模板渲染库 lit/packages/lit-html at main · lit/lit · GitHub 和基于 lit-html 的 lit-element  lit/packages/lit-element at main · lit/lit · GitHub 创建 Web Component 的 base class 。 Lit-html 基于 ES 的模板自变量和 template 标签,用注释节点去动态填充,没有JSX 转换虚拟 dom的过程,把大部分模板创建渲染的事都交给浏览器去做,提供了轻量的 api 让我们可以在 JS 中写 HTML-Templates。 Lit-Element 的 Reactive properties 、Scoped styles 等面向现代化 JS 语法的特点让他现在很受欢迎。 Google 推荐新用户使用 lit,但也将 Polymer 推到了 3.0 版本,放弃了 HTML Imports 转向 JS modules,并且支持 Polymer 跟 lit 混用,目前持续又维护和支持,Slack Channel 上一直很活跃。

除了 Google 自己, 微软的 PWA stater GitHub - pwa-builder/pwa-starter: Welcome to the PWABuilder pwa-starter! Looking to build a new Progressive Web App and not sure where to get started? This is what you are looking for!,选择 lit 框架和 封装的 Web Components 作为基础库。 Adobe 基于 LitElement 封装并开放了 Spectrum Web Components Sap 基于 Lit-html 封装并开源了 ui5-webcomponents/02-custom-UI5-Web-Components.md at master · SAP/ui5-webcomponents · GitHub Red hat  GitHub - 1-Platform/op-components: One platform component library. 等众多公司使用了 lit 开发自己的组件库或平台。

另一个类库 GitHub - skatejs/skatejs: Effortless custom elements powered by modern view libraries. 也是基于 lit-html 的。

Stencil

Stencil: 2019 年6月正式发布第一版,官方定义是一个Web Component 编译器, Ionic 团队开发,把现在流行的虚拟 dom、异步渲染、响应式、JSX 等概念都做了支持,并且自己只是一个构建时工具。用 Stencil 开发的框架可以独立运行、也可以运行在主流框架,毕竟是 ionic 团队的产物。Stencil 可以开发 ionic 框架需要的组件库,其实也就成了整个 ionic 体系的核心之一,Ionic 基于 Stencil 也开源了他们的跨三端、支持框架的组件研发工具 UI Toolkit  GitHub - ionic-team/ionic-framework: A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript. 所以我理解他非常适合用来探索如何把 Web Components 跟 其他框架、应用混合,甚至是构建跨框架的组件系统。

Fast

FAST 微软 2020 年发布的标准化解决方案,可以用来创建组件和设计系统。组件核心是基于 Web Components 做到 框架无关,并把它成为可以通用适配的  adaptive UI 。 由于 Fast 出自微软 Edge 团队,Edge 也在 settings 页面使用了 Fast 。而出自微软 office 团队的 Fluent 组件库起初定位是 React 组件库,随后也支持了 Web Components fluentui/packages/web-components at master · microsoft/fluentui · GitHub 。 Fast 在跟其他框架集成方面也做得比较好,包括三大框架甚至,以及微软自己的 Blazor,近两年尤其对于 ASP.net 等开发路线的用户有很好的吸引力。

  • 我们听惯了 hybrids 架构、hybrids应用,你可能不知道还有个 hybrids 框架 hybrids - npm。他的特点是用纯函数和对象创建各种 Web Components 组件,而不是想通常见到的 Class 的形式,从而避免组件函数逻辑耦合度高的问题,思路上来说跟 hooks 的方向很像。 在 Gitter 上他们也会试试讨论相关问题,虽然不是很活跃 hybridsjs/hybrids - Gitter

研发工具

现有的浏览器 devetools 还没发完全支持 Web Components 的研发,于是有了Web Component DevTools,目前支持了 Chrome 和 FireFox 的插件,可以帮助监听、过滤展示 Custom Elements,修改属性、监听事件、调用函数等等。 这套工具其实也是 Lit 开发团队做的,在 slack 上同样能看到相关的讨论进度

Eslint 和 prettier 都已经有了相应的支持, @open-wc/eslint-config - npm 则集成一些默认的最佳配置。

在lint 工具的基础上, VSCode/IDEA/Atom 等 IDE 也都支持了 Web Components 相关的语法高亮和插件,可以在各自插件市场找到。

框架支持

2022 年几乎所有的主流框架都支持了 Web Components Custom Elements Everywhere

  • Vue 3.0 开始支持 Web Components,Vue3.2 开始支持单文件组件创建 CustomElements
  • React 在实验版本中支持了 CustomElements
  • Angular 的支持比前两位更好。
  • Svelte 则是生来就支持 CustomElements ,并提供了编译 API
  • 其他之前提到的 Polymer\Skate\Lit|\Stencil 更是生来就支持

实现方式

在这么多框架类库支持的情况下,我们可以看下开发实现 Web Components 的方式有哪几种类型:

基于基础库开发

最直接的方式是基于基础库开发,目前支持 Web Components 的基础库主要分位一下几种类型:

  • HTML Element based:写法还是 template 片段和 JS 逻辑分离的方式,比如最直接的裸写 HTML + ES next,以及 HTML + Lit 2.0、HTML + Lit html。
  • Class Component: 之前提到的 Fast,Lit 2.0 本身也支持完全的 Class 写法,还有之前提到的 SkateJS、腾讯的 Tencent/omi,还有支持 CSS-in-JS 写法的 tw-in-js/twind + Lit Element (把 Tailwind CSS 用在 Web Components 上)。
  • Function Component:支持 function Component 的基础库也有不少,比如 支持  hooks  的 atomicojs/atomico、前面提到支持对象 + function 的 Hybirds。
运行时封装

老牌流行框架由于发展较早,对 Web Components 的支持主要一运行时封装为主:

  • react 要借助 react-to-webcomponent
  • preact 要借助 @wcd/preact-custom-element
  • vue2 需要 vue-custom-element
  • vue3.2+ 则可以用 defineCustomElement,然后将组件在构建时编译成 Web Components  (其实我认为 Vue 的 Template 语法形式早应该支持)。
构建时编译

新兴前端框架/库很多支持了构建时编译:

  • Svelte,我被他吸引就是因为他非常适合/能编译成 Web Components
  • Stencil,前面提到他本身就是为了编译 Web Components
  • LWC,前面提到 salesforce 的 Web Components 编译工具库
  • Solid,集合了各种框架特性的框架,也支持编译 Web Components
  • Angular 11 + 也支持了通过 @angular/elements 构建 Web Components

有实验统计了用这些方式实现 30 个 Web Components 的体积尺寸上的情况: webcomponent-build-size.png

可以看到基于原生或基础库开发的方式体积最小,而运行时封装的方式、由于框架/库自身运行时存在,体积最大。 而另一个50个组件的渲染性能统计则可以看到,构建时编译 Web Components 和基于基础库开发并没有太大差别,甚至有的逼近原生: webcomponent-render-performance.png 运行时封装的方式思路在各方面表现都不行,但它确有最小的研发改造成本。所以对于具体的实现方式可以总结下:

实现 Web Components 的方式 渲染性能 资源体积 研发/改造成本
运行时封装 A B框架自身运行时过大 A++ 无需对现有组件改造
构建时编译 A++ 接近原生 A+ 与原生略有差距,但可以接受 A 需要通过工具链转换,有开发工具链的成本
基于原生/基础库开发 A++ A++ A 现有组件只能重写

兼容性

现阶段的 Safari 和 Chrome 已经都原生支持了 Web Components 的规范标准。Firefox,Edge 和 IE11 在 Polyfill 的支持下也都能很好的支持 Web Components。

性能

在 Chromium 中,有实验表示 ShadowDOM 相比常规 DOM 节点创建的开销大约是 3 倍。 原因在于 Shdaow Host 比普通 DOM 节点携带更多的状态信息,包括 Shadow Tree 的 DocumentFragment、CSS Scope 信息等,因此解析和附加 Shdaow Host 所需的时间大约是解析添加常规 DOM 节点的三倍。 这个测试使用的还是实验阶段的 declarative Shadow DOM,所以纯命令式 Shadow DOM 的开销会更高,因为需要解析和执行 Javascript 来调用 attachShadow。

我理解这并不表示使用 Web Components 的页面会慢三倍 ,页面的加载时间受到网络、样式和布局、资源规模、框架等多方面影响。在实践中如果跟 React  组件相比, CustomElement 的 upgrade 机制和 HTML templates,可以让组件在加载时不使用,而在运行时实例化,而普通的 React 组件需要走完所有必要节点逻辑, 同时有实验  Web Components Basics and Performance Benefits | by Sheeshpaul Kamboj | Medium  测试 React 会消耗更多(7倍)的 CPU 成本用来做 JSX 解析、CSS-in-JS 转换、协调调度、虚拟 DOM比较,而 Web Components 不产生框架带来的附加成本,Web Components 的真实渲染性能是更好的。

数据现状

Chorme 的数据显示, 目前有 17% 的网站至少使用过一个 CustomElements,而这个数据在2019 年之前几乎为 0。 同时 Web Componnents 在 PC 和移动端上也没有偏好差异, 两端的增长速度都很快:

如果想了解  Web Components 的历史和更多技术细节可以转到  👉  《你不知道的Web Components - 过去和未来》

参考