🧩 Web Components

一句话定性

Web Components 是浏览器试图把”组件化”从框架手里收编为平台原生标准的一次努力。它的理念近乎完美——跨框架、零运行时、永久兼容,正是 Web平台能力演进史 母题的标准剧本。但它也是整条母题里最刺眼的反例:标准赢了理念,却输掉了生态。它没能像 React/Vue 那样统治应用层,最终退守为”设计系统与跨框架基础库的底层管道”。


一、它是什么 & 出现的时代

Web Components 不是一个 API,而是三个相互独立、可组合的浏览器标准:

标准作用类比框架里的什么
Custom Elements自定义 HTML 标签 <my-card>,带生命周期回调组件定义、mounted/componentDidMount
Shadow DOM给组件一个封装的、样式隔离的子 DOM 树CSS Modules / Vue scoped 样式
HTML Templates (<template>)声明可复用、不立即渲染的 DOM 片段JSX / 模板

时间线:概念由 Google 团队在 2011 年前后提出(随 Polymer 项目),但第一版规范(v0)设计有缺陷、各厂商分歧大,迟迟无法统一。真正可用的是 Custom Elements v1 / Shadow DOM v1,约 2016 年定稿、2018 年前后四大浏览器普及——这个时间点至关重要(见第五节)。


二、为什么会出现(解决上一代什么痛点)

Web Components 要解决的,是 2013-2018 SPA时代 框架割裂带来的两个真实痛点:

痛点一:框架私有组件模型,彼此不通

React 的组件是 React 的,Vue 的组件是 Vue 的,Angular-2+ 的又是另一套。一个用 React 写的日期选择器,无法直接塞进 Vue 项目。大公司内部多技术栈并存时,UI 组件被迫为每个框架各写一遍。

Web Components 的设想很美:用浏览器原生标准定义组件,任何框架都能用 <my-datepicker> 直接消费。一次编写,处处运行——这正是平台收编框架功能的经典动机。

痛点二:没有真正的样式/DOM 封装

在原生世界里,全局 CSS 会泄漏、互相覆盖,催生了 BEMCSS-in-JS 等一堆社区方案来”假装”有封装。Shadow DOM 提供了浏览器级别的真封装:组件内部的样式和 DOM 对外部完全不可见,反之亦然。这是 CSS 方法论们梦寐以求、却只能用约定模拟的能力。

母题视角:组件化、样式封装,都是框架/社区先跑通(React 组件、scoped CSS),平台事后用 Custom Elements / Shadow DOM 追认。和 ES-Modules 追认 CommonJS 是同一个故事。


三、核心机制 & 为什么重要

class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' }); // ← Shadow DOM:样式隔离
    shadow.innerHTML = `<style>p{color:red}</style><p>原生组件</p>`;
  }
  connectedCallback() { /* 挂载时,类似 mounted */ }
  disconnectedCallback() { /* 卸载时 */ }
}
customElements.define('my-card', MyCard); // ← Custom Elements:注册标签

之后在任何框架或纯 HTML 里写 <my-card></my-card> 都能用。

为什么这在理念上是"正确"的

  • 跨框架:它是 HTML 标准,不属于任何框架 → 天然可复用。
  • 零运行时:不需要加载 React/Vue 运行时,浏览器直接认。
  • 永久兼容:符合 Web 向后兼容铁律,今天写的 Custom Element,十年后浏览器依然认(对比:框架大版本升级常带破坏性变更)。

从第一性原理看,Web Components 几乎是组件化的”理论最优解”。这恰恰让它的失败更值得深究。


四、带来的新问题 / 局限

Web Components 的硬伤,不在理念,而在它只提供了”原语”,却没提供”开发体验和配套”:

致命的能力缺口

缺口框架早已解决,Web Components 当年没有
声明式数据绑定React/Vue 有响应式;原生 Custom Element 要手写 attributeChangedCallback + DOM 操作,退回命令式
状态管理框架有完整状态方案;Web Components 标准对此只字不提
SSR(服务端渲染)Shadow DOM 长期无法在服务端序列化(Declarative Shadow DOM 直到 2023 才落地),对 SEO/首屏是灾难
属性 vs 特性(prop vs attribute)HTML attribute 只能传字符串,传对象/数组要绕弯,与框架的 props 心智冲突
开发体验没有 JSX/SFC 那样的模板语法糖,写起来啰嗦;调试工具滞后

二阶效应:它给了"原语",却把"造体验"的活又丢回给了社区

Web Components 是一套底层积木,不是一个能直接盖房子的框架。结果是:开发者想用它做真实应用,还得自己补响应式、状态、路由——这不就是又要造一个框架吗? 于是 Google 自己出了 Polymer,后来演进为 Lit(一个轻量库,给 Web Components 补上响应式与模板)。这恰恰证明了:光有标准原语不够,你仍然需要一层框架。


五、为什么没有彻底成功 / 现状(客观)

这是本篇的核心。Web Components 输给 React/Vue,输的不是理念,是时机和生态:

三个致命的"晚了一步"

  1. 生态窗口期已关闭:Custom Elements v1 到 2018 年才普及。而 React(2013)、Vue(2014)早已占领开发者心智、建好全家桶。当平台姗姗来迟,开发者的家已经在框架里安好了——生态有网络效应和迁移成本,搬不动
  2. DX 差了一个数量级:同一时期,React 有 JSX、Hooks、DevTools、海量教程和组件库;Web Components 还在让你手写 attributeChangedCallback。开发者用脚投票。
  3. 关键能力补齐太晚:SSR(Declarative Shadow DOM)拖到 2023 才像样,而那几年正是 SSR/SSG 回归(渲染模式演进史)的大潮——错过了最需要它的时间窗。
理念:跨框架 / 零运行时 / 永久兼容  ────►  几乎完美
                                              │
实践:DX 差 + 缺状态/SSR + 来得太晚  ────►  应用层全面败给 [[React]]/[[Vue]]
                                              │
                                              ↓
                            退守:不做"应用框架",做"底层管道"

现状:它没死,而是"沉"到了底层

Web Components 没有统治应用开发,但在一个领域赢得很彻底——跨框架的设计系统与基础组件库:

  • Lit(原 Polymer):用最薄的一层把 Web Components 变好用,是当下写 WC 的主流方式。
  • 大厂设计系统:Adobe Spectrum、SAP UI5、GitHub(部分 UI)、微软 FAST/Fluent 等,都用 Web Components 做框架无关的组件底座——因为它们要同时服务 React/Vue/Angular/纯 HTML 的消费方,跨框架正是它唯一不可替代的杀手锏
  • shadcn/ui 路线的反面:对比 shadcn-ui 把组件源码塞进你的 React 项目,Web Components 走的是”框架无关的运行时分发”——两种哲学,各有其位。

一句话:Web Components 没赢得开发者的日常,但赢得了”必须跨框架”的那个利基。 它从”组件化的未来”降级为”组件化的最大公约数”。


六、对后续技术的影响(因果链)

框架割裂:[[React]]/[[Vue]] 组件互不相通 + 全局 CSS 泄漏
        │
        ↓
平台收编:Web Components 三件套(Custom Elements + Shadow DOM + Templates)
        │  理念完美:跨框架 / 零运行时 / 永久兼容
        │
        ├──► 但缺响应式/状态/SSR,DX 差,且 v1 普及(2018)晚于 React/Vue 心智占领
        │         │
        │         └──► 应用层之争:全面败给框架(标准赢理念,输生态)
        │
        ├──► Polymer → Lit:补一层薄框架,让 WC 真正可用
        │
        └──► 沉为底层:大厂"框架无关设计系统"的标准底座(Adobe/SAP/微软…)
                  │
                  ↓
        与 [[ES-Modules]]、原生 CSS 能力一起,构成"平台原生能力反哺框架"的潮汐
                  │
                  ↓
        指向 [[未来5到10年前端发展方向]]:平台越来越强,框架越来越薄
              (但 DX 与生态惯性,决定框架不会消失)

历史地位:一面照出"标准 ≠ 胜利"的镜子

Web Components 是 Web平台能力演进史 里最深刻的教训:技术先进性从来不是胜利的充分条件。它在每一条第一性原则上都赢了 React/Vue——跨框架、零运行时、永久兼容——却因为晚了几年、DX 差一截、配套缺一块,被生态惯性挡在了应用层之外。这和 ECMAScript演进史 反复证明的道理一致:Web 上真正决定成败的,不是”谁更对”,而是”谁先到、谁更好用、谁的生态更厚”


🔗 本组:Web平台能力演进史 | PWA | WebAssembly | Service-Worker与离线能力 🔗 同一母题:ECMAScript演进史 | ES-Modules 🔗 框架对照:React | Vue | Svelte | 前端框架演进史 | shadcn-ui 🔗 时代:2013-2018 SPA时代 | 2018-2023 工程化时代 🔗 浏览器/趋势:Chrome | 浏览器演进史 | 未来5到10年前端发展方向