@stencil/core、lit 和 svelte 都是现代前端开发中用于构建用户界面的重要工具,但它们的定位和产出物有所不同。@stencil/core 是一个编译器工具链,专门用于生成标准的 Web 组件,适合构建企业级设计系统。lit 是一个轻量级库,基于标准 Web 组件构建,强调小巧和性能,适合需要高度互操作性的场景。svelte 主要是一个应用框架,通过编译器将代码转换为高效的 JavaScript,虽然它也能编译为 Web 组件,但其核心优势在于构建完整的 Svelte 应用。
@stencil/core、lit 和 svelte 都致力于解决前端组件化的问题,但它们的实现路径和适用场景有明显区别。Stencil 和 Lit 专注于生成标准 Web 组件,而 Svelte 主要是一个应用框架,虽然具备编译为 Web 组件的能力。让我们从架构师的角度深入对比它们如何处理核心工程问题。
@stencil/core 使用 TypeScript 类和装饰器来定义组件。
@Component 装饰器配置标签名。// stencil: 类与装饰器
import { Component, Prop } from '@stencil/core';
@Component({ tag: 'my-component' })
export class MyComponent {
@Prop() name: string;
}
lit 同样使用 TypeScript 类,但继承自 LitElement。
@property 装饰器定义响应式属性。// lit: 继承 LitElement
import { LitElement, property } from 'lit';
export class MyElement extends LitElement {
@property() name = '';
}
svelte 使用独立的 .svelte 文件,通过编译器指令处理。
customElements 选项。<!-- svelte: 文件组件 -->
<script>
export let name;
</script>
<div>{name}</div>
@stencil/core 使用 @State 和 @Prop 装饰器追踪变化。
// stencil: 状态装饰器
import { State } from '@stencil/core';
@Component({ tag: 'counter' })
export class Counter {
@State() count = 0;
increment() { this.count++; }
}
lit 使用 @state 装饰器管理内部状态。
@property 类似,但专用于内部私有状态。// lit: 内部状态
import { state } from 'lit/decorators.js';
export class Counter extends LitElement {
@state() count = 0;
increment() { this.count++; }
}
svelte 使用普通的 let 变量,编译器自动注入更新逻辑。
<!-- svelte: 普通变量 -->
<script>
let count = 0;
function increment() { count += 1; }
</script>
<button on:click={increment}>{count}</button>
@stencil/core 支持 JSX,类似 React。
render() 方法中返回 JSX。// stencil: JSX 渲染
render() {
return <div>Hello {this.name}</div>;
}
lit 使用模板字面量 html 标签函数。
render() 方法中返回模板。// lit: 模板字面量
render() {
return html`<div>Hello ${this.name}</div>`;
}
svelte 使用类 HTML 模板,逻辑直接嵌入。
render 函数,模板即组件主体。{} 插值,{#if} 处理逻辑。<!-- svelte: 模板嵌入 -->
<div>Hello {name}</div>
@stencil/core 编译为标准 Web 组件(Custom Elements)。
// stencil: 输出配置
{ "build": { "targets": ["dist"] } }
// 生成标准的 customElements.define()
lit 本身就是构建 Web 组件的库。
// lit: 注册组件
customElements.define('my-element', MyElement);
svelte 默认产出 Svelte 应用组件。
compilerOptions.customElements: true 才能生成 Web 组件。// svelte: 配置开启 Web 组件
// svelte.config.js
export default {
compilerOptions: { customElements: true }
};
尽管实现方式不同,这三个工具在某些核心理念上是相通的。
// 所有工具都致力于只更新变化的部分
// Lit/Svelte: 直接操作 DOM 节点
// Stencil: 智能 diff 算法
/* 所有工具都支持 :host 选择器 */
:host { display: block; }
// 所有工具都支持 TypeScript 接口定义
interface Props { name: string; }
// 所有工具都支持标准 DOM 事件
element.addEventListener('click', handler);
// 所有工具都支持动态导入
const module = await import('./component');
| 特性 | @stencil/core | lit | svelte |
|---|---|---|---|
| 核心定位 | 🏭 Web 组件编译器 | 🧩 Web 组件库 | 🚀 应用框架 |
| 组件写法 | 📝 类 + 装饰器 | 📝 类 + 装饰器 | 📄 独立文件 |
| 渲染语法 | ⚛️ JSX | 📝 模板字面量 | 🌐 类 HTML |
| 状态管理 | 🔔 装饰器驱动 | 🔔 装饰器驱动 | 🔄 编译时赋值 |
| 主要场景 | 🏢 企业设计系统 | 🌍 跨框架组件 | 📱 Svelte 应用 |
| 构建配置 | ⚙️ 较复杂 | ✅ 简单 | ✅ 简单 |
@stencil/core 就像是一个重型工业机床 🏭——适合需要严格规范、复杂构建优化和跨框架分发的大型设计系统团队。如果你需要确保组件在所有旧浏览器和框架中表现一致,它是稳妥的选择。
lit 就像是一把精密的手术刀 🔪——轻量、标准、快速。适合现代 Web 项目,尤其是微前端或需要极致加载性能的场景。它是构建标准 Web 组件的当前首选。
svelte 就像是一个全能的工作室 🎨——主要用于构建完整的 Svelte 应用。虽然它能输出 Web 组件,但如果你不是为了 Svelte 生态而构建,可能会觉得配置有些迂回。
核心结论:如果目标是纯粹的跨框架 Web 组件库,优先在 lit 和 @stencil/core 之间选择。如果目标是构建单页应用,svelte 是极佳的选择,但不要仅仅为了 Web 组件功能而选用它。
选择 @stencil/core 如果你需要构建一个供多个框架(如 React、Vue、Angular)共用的设计系统。它提供了强大的构建优化和原生 Web 组件支持,适合大型企业项目,但需要接受其特定的构建配置和类组件写法。
选择 lit 如果你希望使用标准的 Web 组件技术栈,同时拥有轻量级的运行时和 Google 背后的生态支持。它非常适合需要快速加载、高互操作性且不依赖特定构建框架的项目,尤其是微前端架构。
选择 svelte 如果你的主要目标是构建一个完整的 Svelte 应用,并且偶尔需要将部分组件导出为 Web 组件。它的开发体验极佳,语法简洁,但如果主要目的是跨框架共享组件,其配置复杂度可能高于 Lit 或 Stencil。
A compiler for generating Web Components using technologies like TypeScript and JSX, built by the Ionic team.
Start a new project by following our quick Getting Started guide. We would love to hear from you! If you have any feedback or run into issues using Stencil, please file an issue on this repository.
A Stencil component looks a lot like a class-based React component, with the addition of TypeScript decorators:
import { Component, Prop, h } from '@stencil/core';
@Component({
tag: 'my-component', // the name of the component's custom HTML tag
styleUrl: 'my-component.css', // css styles to apply to the component
shadow: true, // this component uses the ShadowDOM
})
export class MyComponent {
// The component accepts two arguments:
@Prop() first: string;
@Prop() last: string;
//The following HTML is rendered when our component is used
render() {
return (
<div>
Hello, my name is {this.first} {this.last}
</div>
);
}
}
The component above can be used like any other HTML element:
<my-component first="Stencil" last="JS"></my-component>
Since Stencil generates web components, they work in any major framework or with no framework at all. In many cases, Stencil can be used as a drop in replacement for traditional frontend framework, though using it as such is certainly not required.
Thanks for your interest in contributing! Please take a moment to read up on our guidelines for contributing. We've created comprehensive technical documentation for contributors that explains Stencil's internal architecture, including the compiler, runtime, build system, and other core components in the /docs directory. Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.