@stencil/core vs lit vs svelte
构建跨框架 Web 组件的三种核心方案
@stencil/corelitsvelte类似的npm包:

构建跨框架 Web 组件的三种核心方案

@stencil/corelitsvelte 都是现代前端开发中用于构建用户界面的重要工具,但它们的定位和产出物有所不同。@stencil/core 是一个编译器工具链,专门用于生成标准的 Web 组件,适合构建企业级设计系统。lit 是一个轻量级库,基于标准 Web 组件构建,强调小巧和性能,适合需要高度互操作性的场景。svelte 主要是一个应用框架,通过编译器将代码转换为高效的 JavaScript,虽然它也能编译为 Web 组件,但其核心优势在于构建完整的 Svelte 应用。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
@stencil/core013,09023.1 MB1791 个月前MIT
lit021,572106 kB6993 天前BSD-3-Clause
svelte086,5772.84 MB1,0062 天前MIT

Stencil、Lit 与 Svelte:Web 组件架构深度对比

@stencil/corelitsvelte 都致力于解决前端组件化的问题,但它们的实现路径和适用场景有明显区别。Stencil 和 Lit 专注于生成标准 Web 组件,而 Svelte 主要是一个应用框架,虽然具备编译为 Web 组件的能力。让我们从架构师的角度深入对比它们如何处理核心工程问题。

🏗️ 组件定义方式:类装饰器 vs 编译器指令

@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 装饰器定义响应式属性。
  • 更贴近原生 Web 组件标准,类结构更轻量。
// lit: 继承 LitElement
import { LitElement, property } from 'lit';

export class MyElement extends LitElement {
  @property() name = '';
}

svelte 使用独立的 .svelte 文件,通过编译器指令处理。

  • 不需要类,直接使用脚本标签和模板。
  • 若要生成 Web 组件,需在配置中开启 customElements 选项。
<!-- svelte: 文件组件 -->
<script>
  export let name;
</script>
<div>{name}</div>

🔄 状态管理:响应式装饰器 vs 编译时信号

@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 5 引入 Runes,但传统写法仍广泛使用。
<!-- svelte: 普通变量 -->
<script>
  let count = 0;
  function increment() { count += 1; }
</script>
<button on:click={increment}>{count}</button>

🎨 渲染语法:JSX vs 模板字面量 vs 类 HTML

@stencil/core 支持 JSX,类似 React。

  • render() 方法中返回 JSX。
  • 适合熟悉 React 的开发者。
// 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>

📦 构建产出:标准 Web 组件 vs 框架特定组件

@stencil/core 编译为标准 Web 组件(Custom Elements)。

  • 产出物可在任何框架中直接使用。
  • 包含额外的构建优化(如懒加载)。
// stencil: 输出配置
{ "build": { "targets": ["dist"] } }
// 生成标准的 customElements.define()

lit 本身就是构建 Web 组件的库。

  • 产出物是标准的 Custom Elements。
  • 运行时极小,依赖少。
// lit: 注册组件
customElements.define('my-element', MyElement);

svelte 默认产出 Svelte 应用组件。

  • 需配置 compilerOptions.customElements: true 才能生成 Web 组件。
  • 主要生态围绕 Svelte 应用构建。
// svelte: 配置开启 Web 组件
// svelte.config.js
export default {
  compilerOptions: { customElements: true }
};

🤝 相似之处:核心共性

尽管实现方式不同,这三个工具在某些核心理念上是相通的。

1. ⚡ 高性能渲染

  • 都避免了传统虚拟 DOM 的全部开销(Stencil 可选虚拟 DOM,Lit 和 Svelte 默认无虚拟 DOM)。
  • 注重更新时的最小化操作。
// 所有工具都致力于只更新变化的部分
// Lit/Svelte: 直接操作 DOM 节点
// Stencil: 智能 diff 算法

2. 🌐 标准兼容性

  • 都支持 Shadow DOM 封装样式。
  • 都遵循 Web 组件标准规范。
/* 所有工具都支持 :host 选择器 */
:host { display: block; }

3. 🛠️ TypeScript 支持

  • 都提供优秀的类型定义。
  • 开发体验中类型提示完善。
// 所有工具都支持 TypeScript 接口定义
interface Props { name: string; }

4. 🔌 生态互操作性

  • 生成的组件都能在 React、Vue、Angular 中调用。
  • 支持事件派发和属性绑定。
// 所有工具都支持标准 DOM 事件
element.addEventListener('click', handler);

5. 📦 模块化打包

  • 都支持现代打包工具(Vite、Rollup、Webpack)。
  • 支持代码分割和按需加载。
// 所有工具都支持动态导入
const module = await import('./component');

📊 总结:关键差异

特性@stencil/corelitsvelte
核心定位🏭 Web 组件编译器🧩 Web 组件库🚀 应用框架
组件写法📝 类 + 装饰器📝 类 + 装饰器📄 独立文件
渲染语法⚛️ JSX📝 模板字面量🌐 类 HTML
状态管理🔔 装饰器驱动🔔 装饰器驱动🔄 编译时赋值
主要场景🏢 企业设计系统🌍 跨框架组件📱 Svelte 应用
构建配置⚙️ 较复杂✅ 简单✅ 简单

💡 最终建议

@stencil/core 就像是一个重型工业机床 🏭——适合需要严格规范、复杂构建优化和跨框架分发的大型设计系统团队。如果你需要确保组件在所有旧浏览器和框架中表现一致,它是稳妥的选择。

lit 就像是一把精密的手术刀 🔪——轻量、标准、快速。适合现代 Web 项目,尤其是微前端或需要极致加载性能的场景。它是构建标准 Web 组件的当前首选。

svelte 就像是一个全能的工作室 🎨——主要用于构建完整的 Svelte 应用。虽然它能输出 Web 组件,但如果你不是为了 Svelte 生态而构建,可能会觉得配置有些迂回。

核心结论:如果目标是纯粹的跨框架 Web 组件库,优先在 lit@stencil/core 之间选择。如果目标是构建单页应用,svelte 是极佳的选择,但不要仅仅为了 Web 组件功能而选用它。

如何选择: @stencil/core vs lit vs svelte

  • @stencil/core:

    选择 @stencil/core 如果你需要构建一个供多个框架(如 React、Vue、Angular)共用的设计系统。它提供了强大的构建优化和原生 Web 组件支持,适合大型企业项目,但需要接受其特定的构建配置和类组件写法。

  • lit:

    选择 lit 如果你希望使用标准的 Web 组件技术栈,同时拥有轻量级的运行时和 Google 背后的生态支持。它非常适合需要快速加载、高互操作性且不依赖特定构建框架的项目,尤其是微前端架构。

  • svelte:

    选择 svelte 如果你的主要目标是构建一个完整的 Svelte 应用,并且偶尔需要将部分组件导出为 Web 组件。它的开发体验极佳,语法简洁,但如果主要目的是跨框架共享组件,其配置复杂度可能高于 Lit 或 Stencil。

@stencil/core的README

stencil-logo

Stencil

A compiler for generating Web Components using technologies like TypeScript and JSX, built by the Ionic team.

StencilJS is released under the MIT license. StencilJS is released under the MIT license. PRs welcome! Follow @stenciljs Official Ionic Discord

Quick Start · Documentation · Contribute · Blog
Community: Discord · Forums · Twitter

Getting Started

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.

Examples

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.

Contributing

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.