发布

本页提供了将 Lit 组件发布到 npm 的指南,npm 是大多数 JavaScript 库和开发人员使用的包管理器。有关可用于发布到 npm 的可重用组件模板,请参阅 入门套件

要将您的组件发布到 npm,请参阅有关贡献 npm 包的说明

您的 package.json 配置应包含 typemainmodule 字段

package.json

您还应该创建一个 README,描述如何使用您的组件。

我们建议以标准 ES2021 语法发布 JavaScript 模块,因为所有常青浏览器都支持此语法,并且会导致 JavaScript 更快、更小。您的软件包用户始终可以使用编译器来支持旧版浏览器,但如果在发布之前预编译代码,他们就无法将遗留 JavaScript 转换为现代语法。

但是,重要的是,如果您正在使用新提出的或非标准的 JavaScript 功能(例如 TypeScript、装饰器和类字段),您应该将这些功能编译为标准 ES2021(浏览器本地支持)并在发布到 npm 之前。

以下 JSON 示例是一个部分 tsconfig.json,它使用推荐的选项来定位 ES2021,启用装饰器的编译,并为用户输出 .d.ts 类型

tsconfig.json

注意,将 useDefineForClassFields 设置为 false 仅在 target 设置为 es2022 或更高(包括 esnext)时才需要,但建议明确确保此设置是 false

从 TypeScript 编译时,您应该在 package.jsontypes 字段中包含组件类型的声明文件(根据上面的 declaration: true 生成),并确保 .d.ts.d.ts.map 文件也发布。

package.json

有关更多信息,请参阅 tsconfig.json 文档

要编译使用 ES2021 中尚未包含的提出的 JavaScript 功能的 Lit 组件,请使用 Babel。

安装 Babel 和您需要的 Babel 插件。例如

配置 Babel。例如

babel.config.json

您可以调整 "targets" 选项以定位您希望支持的浏览器。有关可用选项,请参阅 @babel/preset-env

您可以通过捆绑器插件(例如 @rollup/plugin-babel)或从命令行运行 Babel。有关更多信息,请参阅 Babel 文档

以下是在发布可重用 Web 组件时应遵循的其他最佳实践。

Polyfills 是应用程序的关注点,因此应用程序应该直接依赖于它们,而不是单个包。所需的具体 polyfills 通常取决于应用程序需要支持的浏览器,而该选择最好留给使用您的组件的应用程序开发人员。您的组件文档应该清楚地识别它使用的任何可能需要 polyfills 的 API。

包可能需要依赖于 polyfills 用于测试和演示,因此如果需要,它们应该只放在 devDependencies 中。

捆绑和其他优化是应用程序的关注点。在发布到 npm 之前捆绑可重用组件还会将 Lit(和其他包)的多个版本引入用户的应用程序,因为 npm 无法对包进行重复数据消除。这会导致膨胀,并可能导致错误。

在发布之前优化模块也可能阻止应用程序级别的优化。

从 CDN 提供模块时,捆绑和其他优化可能很有价值,但由于用户可能需要使用依赖于 Lit 的多个包,因此从 CDN 提供会导致用户加载比必要更多的代码。出于这些原因,我们建议性能敏感的应用程序始终从 npm 构建,在 npm 中可以对包进行重复数据消除,而不是从 CDN 加载捆绑的包。

如果您想支持从 CDN 使用,我们建议在用于 CDN 的模块和用于生产用途的模块之间进行明确的区分。例如,将它们放在单独的文件夹中,或者只将它们作为 GitHub 版本的一部分添加,而不是将它们添加到已发布的 npm 模块中。

Node 模块解析不需要文件扩展名,因为它会执行文件系统的搜索,如果未给出文件扩展名,则查找几个文件扩展名中的一个。当您导入 some-package/foo 时,Node 会导入 some-package/foo.js(如果存在)。同样,在构建时将包说明符解析为 URL 的构建工具也可以执行此文件系统搜索。

但是,导入映射 规范正在开始在浏览器中发布,它将允许浏览器从源加载具有裸包说明符的模块未经转换,方法是通过在导入映射清单(这很可能基于您的 npm 安装(例如)通过工具生成)中提供导入说明符到 URL 的映射。

导入映射将允许将导入映射到 URL,但它们只有两种类型的映射:精确和前缀。这意味着通过将包名称映射到单个 URL 前缀,可以轻松地为给定包下的所有模块设置别名。但是,如果您在导入中没有文件扩展名,则意味着您的包中的每个文件都需要导入映射中的条目。这会大大膨胀导入映射。

因此,为了让您的源代码现在能够与导入映射最佳兼容,我们建议在导入中使用文件扩展名进行创作。

为了让您的元素易于从 TypeScript 中使用,我们建议您

  • 为在 TypeScript 中编写的每个元素添加 HTMLElementTagNameMap 条目。

  • 在您的 npm 包中发布 .d.ts 类型定义。

有关 HTMLElementTagNameMap 的更多信息,请参阅 提供良好的 TypeScript 类型定义

声明 Web 组件类的模块应始终包含对 customElements.define()(或 @customElement 装饰器)的调用来定义元素。

目前,Web 组件始终在全局注册表中定义。每个自定义元素定义都需要使用唯一的标签名称以及唯一的 JavaScript 类。尝试两次注册相同的标签名称或相同的类将导致错误。简单地导出一个类并期望用户调用 define() 是脆弱的。如果两个不同的组件都依赖于同一个共享的第三个组件,并且都尝试定义它,那么其中一个将失败。如果元素始终在声明其类的同一个模块中定义,则这不是问题。

这种方法的一个缺点是,如果两个不同的元素使用相同的标签名称,则它们不能都导入到同一个项目中。

人们正在努力为平台添加 作用域自定义元素注册表。作用域注册表允许组件用户为给定的 shadow root 作用域选择自定义元素的标签名称。一旦浏览器开始发布此功能,将变得切实可行地为每个组件发布两个模块:一个导出没有副作用的自定义元素类,另一个在全局范围内注册它并使用标签名称。

在此之前,我们建议继续在全局注册表中注册元素。

为了支持子类化,请从定义它的模块中导出元素类。这允许子类化以用于扩展目的,以及将来在 作用域自定义元素注册表 中注册。

有关创建高质量可重用 Web 组件的更一般指南,请参阅 Web 组件黄金标准清单