Stencil Web Components 编译框架技术调研 logo

Stencil Web Components 编译框架技术调研

面向跨框架设计系统的 Web Components 编译器

Web Components编译器组件库TypeScript

Stencil 使用 JSX、TypeScript 和装饰器编写组件,再编译为标准 Custom Elements,并可自动生成 React、Vue、Angular 包装器。

Stencil Web Components 编译框架技术调研

Stencil 是由 Ionic 团队创建的开源 Web Components 编译器,使用类 JSX + TypeScript + 装饰器编写组件,编译为标准 Custom Elements,并可自动生成 React、Vue、Angular 等多框架包装器。Stencil 的核心定位是跨框架组件库编译器,而非运行时框架。2025 年,Ionic 宣布 Stencil 过渡为社区驱动项目("Stencil Reframed"),标志着其从 Ionic 独立出来,进入更开放的治理模式。2026 年,Stencil 4.43.x 持续稳定维护,v5 版本正在社区规划中。


一、 基本信息

维度关键指标 / 描述
技术方向Web Components 编译器 / 跨框架组件库 / JSX + TypeScript / 多框架包装器
开源协议MIT License
官方网站https://stenciljs.com/
GitHub 仓库stenciljs/core(原 ionic-team/stencil)
GitHub Stars12,000+
主要维护者Ionic 团队创建;2025 年 4 月起过渡为社区驱动治理
首次发布2017 年(为 Ionic Framework 4+ 构建底层技术)
最新版本Stencil 4.43.5(2026 年 5 月 28 日)
生态成熟度中高(Ionic 持续使用,社区治理转型,v5 规划中)
运行要求Node.js 18+ / 现代浏览器(支持 Custom Elements 和 Shadow DOM)

二、 版本历史与 2026 年现状

版本发布时间关键里程碑
Stencil 4.43.52026 年 5 月当前稳定版,持续高频发布补丁和 bug 修复。
Stencil 4.02023 年进一步性能优化、构建改进、移除部分废弃 API。
Stencil 3.02022 年支持现代构建工具,改进 TypeScript 支持。
Stencil 2.02020 年引入更好 SSR 支持、测试框架集成。
Stencil 1.02018 年首个稳定版本,为 Ionic 4 提供底层组件编译能力。

2026 年核心趋势

  1. 社区治理转型:"Stencil Reframed" 项目从 Ionic 独立,社区参与度提升,治理更加开放透明。
  2. v5 版本规划中:社区正在讨论 v5 的潜在变更,可能包括更好的 Vite 集成、性能优化等。
  3. Ionic 持续使用:Ionic Framework 8.8(2026 年 3 月)仍使用 Stencil 作为组件编译基础,确保实际应用价值。
  4. Lit 竞争:在 Web Components 领域,Stencil 面临 Lit 的强力竞争。Lit 更注重标准,Stencil 更注重编译器便利性。
  5. 跨框架组件库定位:Stencil 在跨框架组件库和设计系统领域仍有独特价值,特别是需要自动生成多框架包装器的场景。

三、 技术定位与简介

Stencil 的定位是 Web Components 编译器,而非前端 UI 框架或应用框架:

  • 开发者使用类 JSX + TypeScript + 装饰器 编写组件。
  • 编译器输出标准 Custom Elements,可在任何 HTML 环境中使用。
  • 自动生成多框架包装器,包括 React、Vue、Angular 等。
  • 提供懒加载、SSR、测试、构建优化等工程化能力

Stencil 的核心理念:

  • 一次编写,到处运行:组件库只需编写一次,即可在多个框架和平台中使用。
  • 编译器驱动:通过编译时优化生成高效、标准的 Web Components。
  • 企业级组件库:特别适合构建企业设计系统和跨框架组件库。

Stencil 与 Lit 的主要区别:

  • Stencil 是编译器:提供完整的组件库工程化工具链(构建、测试、多框架输出)。
  • Lit 是组件库:更轻量,更贴近 Web 标准,需要自己搭建组件库工程化。

四、 快速上手安装说明

1. 创建 Stencil 组件库项目

npm init stencil
# 选择 component 模板
 
cd my-stencil-components
npm install
npm run start

2. 标准项目结构

my-stencil-components/
├── src/
│   ├── components/             # 组件目录
│   │   ├── my-counter/
│   │   │   ├── my-counter.tsx  # 组件实现
│   │   │   ├── my-counter.css  # 组件样式
│   │   │   └── my-counter.e2e.ts # E2E 测试
│   │   └── my-button/
│   ├── components.d.ts         # 自动生成的组件类型
│   ├── index.ts                # 公共导出
│   └── utils/                  # 工具函数
├── stencil.config.ts           # Stencil 配置文件
├── package.json
├── tsconfig.json
└── www/                        # 开发预览目录

3. 核心开发命令

npm run start     # 启动开发服务器,带热更新
npm run build     # 生产构建,生成 Custom Elements 和框架包装器
npm run test      # 运行 Jest 单元测试和 E2E 测试
npm run test.watch # 持续运行测试
npm run generate  # 生成新组件

4. stencil.config.ts 推荐配置

// stencil.config.ts
import { Config } from '@stencil/core'
import { reactOutputTarget } from '@stencil/react-output-target'
import { vueOutputTarget } from '@stencil/vue-output-target'
import { angularOutputTarget } from '@stencil/angular-output-target'
 
export const config: Config = {
  namespace: 'my-components',
  buildDist: true,
  outputTargets: [
    // 标准 Web Components 输出
    {
      type: 'dist',
      esmExternalNodeBuiltins: true,
      externalRuntime: true
    },
    // 单文件输出
    {
      type: 'dist-custom-elements',
      externalRuntime: true
    },
    // 文档生成
    {
      type: 'docs-readme'
    },
    // 框架包装器
    reactOutputTarget({
      componentCorePackage: 'my-stencil-components',
      proxiesFile: '../react-components/src/components.ts'
    }),
    vueOutputTarget({
      componentCorePackage: 'my-stencil-components',
      proxiesFile: '../vue-components/src/components.ts'
    }),
    angularOutputTarget({
      componentCorePackage: 'my-stencil-components',
      directivesProxyFile: '../angular-components/src/directives/proxies.ts'
    })
  ]
}

5. 第一个 Stencil 组件

// src/components/my-counter/my-counter.tsx
import { Component, Prop, State, h } from '@stencil/core'
 
@Component({
  tag: 'my-counter',
  styleUrl: 'my-counter.css',
  shadow: true
})
export class MyCounter {
  // 外部可设置的属性
  @Prop() initialValue: number = 0
 
  // 内部状态
  @State() count: number
 
  componentWillLoad() {
    this.count = this.initialValue
  }
 
  private increment() {
    this.count += 1
  }
 
  render() {
    return (
      <div>
        <p>Count: {this.count}</p>
        <button onClick={() => this.increment()}>+1</button>
      </div>
    )
  }
}
/* src/components/my-counter/my-counter.css */
:host {
  display: block;
  font-family: sans-serif;
}
 
button {
  background: #007bff;
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  cursor: pointer;
}
<!-- 使用组件 -->
<my-counter initial-value="10"></my-counter>

五、 核心特性

1. 编译器而非框架

Stencil 是编译器,不是运行时框架。开发者使用类 JSX + TypeScript 编写组件,编译器输出标准 Web Components。运行时不需要加载 Stencil 框架代码。

2. JSX + TypeScript

Stencil 使用 JSX 作为模板语法,与 React 类似,但编译为 Custom Elements。提供完整的 TypeScript 类型支持和编辑器体验。

3. 多框架包装器生成

Stencil 可以自动生成 React、Vue、Angular 等框架的组件包装器,实现"一次编写,到处运行":

  • @stencil/react-output-target
  • @stencil/vue-output-target
  • @stencil/angular-output-target

4. 标准输出

编译产物是标准 Custom Elements,可在任何 HTML 环境中使用,无需依赖任何框架。

5. Shadow DOM 样式隔离

默认使用 Shadow DOM 实现样式隔离,组件样式不影响外部,外部样式不影响组件内部。

6. 编译时虚拟 DOM

Stencil 在编译时使用轻量级虚拟 DOM diffing,生成高效的 DOM 更新代码。

7. 懒加载

组件按需加载,减少初始 bundle 体积。Stencil 会自动拆分和懒加载组件。

8. 开箱即用工具链

Stencil 提供完整的组件库工程化能力:

  • 开发服务器和热更新。
  • Jest 测试集成。
  • 文档自动生成。
  • 生产构建优化。
  • SSR 支持。

9. Ionic 基础

Stencil 最初是为 Ionic Framework 4+ 构建的底层技术。Ionic 的移动/Web 组件由 Stencil 编译生成。

10. 装饰器语法

Stencil 使用装饰器简化组件定义:

  • @Component():组件元数据(tag、样式、Shadow DOM)。
  • @Prop():外部属性。
  • @State():内部状态。
  • @Event():自定义事件。
  • @Method():公共方法。
  • @Watch():监听属性变化。
  • @Element():获取宿主元素。

六、 适用场景

1. 黄金适用场景

  • 跨框架组件库:构建一次,在 React、Vue、Angular 中都能使用。
  • 设计系统:企业设计系统——组件库需要跨团队、跨框架复用。
  • 微前端基础设施:作为跨应用的组件基础设施。
  • Ionic 应用开发:构建基于 Ionic 的跨平台移动/Web 应用。
  • CMS 和编辑器组件:需要跨框架使用的富文本编辑器、表单组件。
  • 遗留系统迁移:在迁移过程中保持组件在不同框架中可用。
  • 嵌入式 Widget:需要独立分发的交互式组件。

2. 局限适用场景

  • 复杂单页应用:Stencil 是组件编译器,不是应用框架。复杂路由、状态管理需要配合其他框架。
  • 快速原型开发:相比 React/Vue 的完整生态,Stencil 缺少路由、状态管理等开箱即用能力。
  • 小型独立组件:如果只是几个简单组件,Lit 可能更轻量和直接。

七、 技术亮点

1. 编译器 vs 框架

Stencil 最关键的区别是它是编译器而非框架。开发者使用类 JSX + TypeScript 编写组件,编译器输出标准 Web Components 和多框架包装器。这提供了:

  • 标准兼容性。
  • 多框架复用。
  • 运行时轻量。

2. 多框架包装器自动化

Stencil 的输出目标插件可以自动生成 React、Vue、Angular 的包装组件。开发者无需手动维护多个框架的组件版本,大幅降低跨框架组件库的维护成本。

3. 完整的组件库工程化

Stencil 提供组件库开发所需的完整工具链:构建、测试、文档、懒加载、SSR。这使得团队可以专注于组件本身,而非工程化基础设施。

4. Ionic 生产验证

Stencil 是 Ionic Framework 的底层技术。Ionic 的广泛应用验证了 Stencil 在跨平台移动/Web 组件中的可靠性和性能。

5. 社区驱动治理(Stencil Reframed)

2025 年 Stencil 过渡为社区驱动项目,意味着:

  • 更开放的治理结构。
  • 社区参与决策和贡献。
  • 独立性增强,不再完全依赖 Ionic 的商业决策。

6. v5 规划

社区正在讨论 Stencil v5 的潜在变更,包括更好的 Vite 集成、性能优化等,表明项目仍有长期发展计划。


八、 核心概念与架构

1. Stencil 编译流程

digraph Stencil_Compile {
  rankdir=LR
  node [shape=box, style="rounded,filled", fillcolor="#f0f9ff"]
  Source [label="TSX + Decorators Source", fillcolor="#bae6fd"]
  Compiler [label="Stencil Compiler"]
  CustomElements [label="Custom Elements"]
  React [label="React Wrappers"]
  Vue [label="Vue Wrappers"]
  Angular [label="Angular Wrappers"]
  Docs [label="Auto-generated Docs"]
 
  Source -> Compiler
  Compiler -> CustomElements
  Compiler -> React
  Compiler -> Vue
  Compiler -> Angular
  Compiler -> Docs
}

2. 组件生命周期

Stencil 组件继承标准的 Custom Elements 生命周期,并增加框架级回调:

  • connectedCallback() / disconnectedCallback():标准生命周期。
  • componentWillLoad():组件加载前。
  • componentDidLoad():组件加载后。
  • componentWillRender() / componentDidRender():渲染前后。
  • componentWillUpdate() / componentDidUpdate():更新前后。
  • render():返回 JSX 模板。
digraph Stencil_Lifecycle {
  rankdir=TB
  node [shape=box, style="rounded,filled", fillcolor="#fef3c7"]
  WillLoad [label="componentWillLoad()"]
  Render1 [label="render()"]
  DidLoad [label="componentDidLoad()"]
  PropChange [label="Prop/State Change"]
  WillUpdate [label="componentWillUpdate()"]
  Render2 [label="render()"]
  DidUpdate [label="componentDidUpdate()"]
 
  WillLoad -> Render1 -> DidLoad -> PropChange -> WillUpdate -> Render2 -> DidUpdate
}

3. 属性与状态

  • @Prop():外部传入的属性,会触发重新渲染。
  • @State():内部状态,外部不可访问,变化触发重新渲染。
  • @Watch():监听属性变化,执行副作用。

4. 事件与插槽

  • @Event():触发自定义事件。
  • &lt;slot&gt;:标准 Web Components 插槽,支持内容分发。

5. 多框架输出目标

Stencil 的输出目标(Output Targets)是编译器的核心扩展点:

  • dist:标准 npm 包输出。
  • dist-custom-elements:单个 Custom Elements 输出。
  • www:开发服务器和预览。
  • docs-readme / docs-vscode:文档生成。
  • react-output-target / vue-output-target / angular-output-target:框架包装器。

九、 技术局限与边界

  1. 学习曲线: Stencil 需要理解 TypeScript 装饰器、JSX、Shadow DOM、Custom Elements 生命周期等多个概念,对新手团队有一定学习成本。

  2. 不是应用框架: Stencil 是组件编译器,不是完整的应用框架。复杂应用需要配合 React、Vue、Angular 等框架使用。

  3. 与 Lit 的竞争: Lit 更轻量、更贴近 Web 标准,社区规模更大。Stencil 的多框架工程化能力是其优势,但 Lit 在简单场景下更直接。

  4. 社区治理转型不确定性: 虽然社区治理转型带来开放性,但也可能伴随短期资源分配和发展方向的不确定性。

  5. v5 尚未发布: v5 仍在规划中,部分预期改进(如更好的 Vite 集成)尚未落地。

  6. Shadow DOM 的表单限制: 与 Lit 类似,Stencil 组件中的表单元素需要 ElementInternals 参与外部表单,增加了表单组件的复杂度。

  7. 装饰器依赖: Stencil 依赖 TypeScript 实验性装饰器,未来 ECMAScript 装饰器标准变化可能带来迁移成本。


十、 生态地图

Stencil 生态围绕 Ionic、多框架输出和 Web Components 工具构建:

digraph Stencil_Ecosystem {
  rankdir=TB
  node [shape=box, style="rounded,filled", fillcolor="#f0f9ff"]
  Stencil [label="Stencil Compiler", fillcolor="#bae6fd"]
 
  Stencil -> Ionic [label="Ionic Framework"]
  Stencil -> React [label="React Wrappers"]
  Stencil -> Vue [label="Vue Wrappers"]
  Stencil -> Angular [label="Angular Wrappers"]
  Stencil -> Jest [label="Jest Tests"]
  Stencil -> Storybook [label="Storybook"]
  Stencil -> OpenWC [label="Open WC"]
 
  Ionic -> Mobile [label="Mobile/Web Apps"]
  React -> ReactApps [label="React Apps"]
  Vue -> VueApps [label="Vue Apps"]
  Angular -> AngularApps [label="Angular Apps"]
}

十一、 生态集成

领域推荐方案集成说明
移动/Web 组件Ionic FrameworkStencil 的主要消费者,Ionic 组件由 Stencil 编译。
React 包装器@stencil/react-output-target自动生成 React 组件包装器。
Vue 包装器@stencil/vue-output-target自动生成 Vue 组件包装器。
Angular 包装器@stencil/angular-output-target自动生成 Angular 指令包装器。
测试Jest / PuppeteerStencil 内置 Jest 和 Puppeteer E2E 测试。
构建工具Rollup(Stencil 内置)/ Vite(社区插件)Stencil 底层使用 Rollup;v5 可能增强 Vite 集成。
样式Shadow DOM / CSS Variables默认 Shadow DOM 样式隔离。
文档docs-readme / StorybookStencil 自动生成 README 文档;Storybook 支持 Web Components。
SSRStencil Hydrate提供 SSR 和水合能力。
组件库Shoelace / Ionic基于 Stencil 或 Lit 的主流 Web Components 库。
状态管理外部框架(React/Vue/Angular 生态)Stencil 组件本身不管理应用状态。
表单ElementInternals使用标准 API 让自定义元素参与表单。

十二、 开发与工程化

1. TypeScript 严格模式

Stencil 完全使用 TypeScript,建议开启严格模式:

{
  "compilerOptions": {
    "strict": true,
    "experimentalDecorators": true,
    "jsx": "react",
    "jsxFactory": "h",
    "moduleResolution": "node"
  }
}

2. 组件库 Monorepo 结构

my-design-system/
├── packages/
│   ├── core/                    # Stencil 核心组件
│   │   ├── src/components/
│   │   ├── stencil.config.ts
│   │   └── package.json
│   ├── react/                   # React 包装器
│   ├── vue/                     # Vue 包装器
│   └── angular/                 # Angular 包装器
├── package.json
└── tsconfig.json

3. 输出目标配置

stencil.config.ts 中配置多框架输出目标:

outputTargets: [
  { type: 'dist' },
  { type: 'dist-custom-elements' },
  reactOutputTarget({ /* ... */ }),
  vueOutputTarget({ /* ... */ }),
  angularOutputTarget({ /* ... */ })
]

4. 测试策略

  • 单元测试:Jest(Stencil 内置)。
  • E2E 测试:Puppeteer(Stencil 内置)或 Playwright。
  • 跨框架测试:在每个框架包装器包中运行对应测试。

5. 文档自动生成

Stencil 可以自动生成 README 文档:

{ type: 'docs-readme' }

这会根据组件的 @Prop()@Event()@Method() 装饰器生成 Markdown 文档。


十三、 性能与安全

1. 编译时优化

Stencil 在编译时优化组件模板,生成高效的 DOM 操作代码。懒加载机制确保只有需要的组件才会被下载。

2. 懒加载策略

Stencil 自动为组件生成懒加载 chunk。对于大型组件库,应合理分组组件,避免过多小 chunk:

// stencil.config.ts
export const config: Config = {
  buildDist: true,
  outputTargets: [
    { type: 'dist' }
  ]
}

3. 避免不必要的属性反射

@Prop(&#123; reflect: true &#125;) 会将属性同步回 DOM,增加 DOM 操作。只在需要 attribute 选择器或外部样式时启用。

4. 安全:XSS 与模板注入

Stencil 的 JSX 模板默认对插值进行转义,防御 XSS。但需注意:

  • 避免使用 innerHTML 渲染未过滤的用户输入。
  • 对动态 URL 和属性进行校验。

5. 安全:Shadow DOM 与 CSP

配置合理的 Content-Security-Policy,避免在 Shadow DOM 中执行内联脚本。对于样式内联,确保 CSP 允许 style-srcunsafe-inline 或使用 nonce。

6. 表单集成安全

Stencil 组件中的表单元素默认不参与外部表单。使用 ElementInternals 让自定义元素参与表单验证和提交:

import { Component, Element, h } from '@stencil/core'
 
@Component({
  tag: 'my-input',
  shadow: true,
  formAssociated: true
})
export class MyInput {
  @Element() el: HTMLElement
  internals: ElementInternals
 
  componentWillLoad() {
    this.internals = this.el.attachInternals()
  }
 
  setValue(value: string) {
    this.internals.setFormValue(value)
  }
}

十四、 技术对比

特性维度StencilLitReact 19Vue 3
核心定位Web Components 编译器Web Components 库UI 渲染库渐进式框架
输出Custom Elements + 框架包装器Custom Elements框架组件框架组件
编译器无(或使用 Compiler)
多框架包装器自动生成需手动/官方包装器需包装需包装
运行时体积轻量约 5KB40KB+22KB
Shadow DOM默认启用默认启用不使用可选
工程化工具链完整需自行搭建依赖外部工具较完整
学习曲线中等平缓中等平缓
最适合场景跨框架组件库、设计系统跨框架组件、嵌入式高交互应用中后台应用

十五、 最佳实践

  1. 将 Stencil 定位为组件编译器: 不要试图用 Stencil 构建完整 SPA。它是组件库和设计系统的工具,应配合 React/Vue/Angular 使用。

  2. 配置多框架输出目标: 从项目开始就配置 React、Vue、Angular 包装器,避免后期手动迁移。

  3. 使用 Shadow DOM 实现封装: 默认启用 Shadow DOM,通过 CSS 自定义属性暴露可定制样式。

  4. 属性设计遵循 Web 标准: 使用 @Prop() 声明属性时,遵循 HTML attribute 命名习惯(kebab-case 映射)。

  5. 组件职责单一: 每个 Stencil 组件只做一件事,避免组件过于复杂。复杂组件拆分为子组件。

  6. 测试覆盖多框架包装器: 除了 Stencil 组件本身,还要在 React/Vue/Angular 包装器包中运行集成测试。

  7. 使用 ElementInternals 参与表单: 表单控件组件必须使用 ElementInternals 参与父表单验证和提交。

  8. 避免在组件中管理应用状态: Stencil 组件只管理自身状态和属性。应用级状态交给上层框架(React Context、Vue Pinia、Angular Services)。

  9. 合理配置懒加载: 利用 Stencil 的自动懒加载,但不要将组件拆分得过细,避免过多网络请求。

  10. 关注 Stencil Reframed 和 v5 进展: 社区治理转型后,积极参与或关注 v5 规划,及时了解 Vite 集成等重大改进。

  11. 文档自动化: 使用 docs-readme 输出目标自动生成组件文档,保持文档与代码同步。

  12. 提交前运行完整测试: 在 CI 中运行 stencil buildstencil test,确保所有输出目标和测试通过。


十六、 学习与社区资源

1. 官方核心资源

2. 视频与教程

  • Ionic 官方 YouTube:Stencil + Ionic 相关教程。
  • Josh Morony 教程:深入的 Stencil 开发教程。
  • Stencil 社区视频:GitHub Discussions 和 YouTube 上的社区分享。

3. 社区与治理

  • Stencil GitHub Discussions:技术讨论和功能提案。
  • Stencil Reframed:社区治理转型后的官方讨论渠道。
  • Ionic 社区:Stencil 最活跃的使用群体。
  • Reddit r/stenciljs / r/webcomponents:社区讨论。

4. 推荐书籍

  • 《Stencil.js: Building Cross-Framework Components》— 系统学习 Stencil 组件库开发。
  • 《Ionic 6+ with Stencil》— 结合 Ionic 的 Stencil 实战。