Lit SSR 的组件创作
Lit 在服务器环境中渲染 Web 组件的方法对组件代码有一些限制,以实现高效的服务器渲染。在创作组件时,请牢记以下考虑因素,以确保它们与 Lit SSR 兼容。
注意: 本页面列出的限制可能会随着我们对 Lit SSR 的改进而更改。如果您希望看到特定用例得到支持,请提交问题或启动讨论 线程。
浏览器专用代码
指向“浏览器专用代码”的永久链接大多数浏览器 DOM API 在 Node 环境中不可用。Lit SSR 使用 DOM 模拟,这是渲染 Lit 模板和组件所必需的最低限度。有关可用 API 的完整列表,请参见DOM 模拟 页面。
在创作组件时,请从仅在客户端(而不是在服务器上)调用的生命周期方法中执行命令式 DOM 操作。例如,如果您需要测量更新后的 DOM,请使用 updated()
。此回调仅在浏览器中运行,因此可以安全地访问 DOM。
请参见下面的生命周期部分,了解哪些特定方法在服务器上调用,哪些方法仅在浏览器上调用。
定义 Lit 组件的一些模块可能还具有使用浏览器 API 的副作用——例如检测某些浏览器功能——这样一来,该模块在非浏览器环境中导入时就会中断。在这种情况下,您可以将副作用代码移入浏览器专用生命周期回调,或进行条件化,使其仅在浏览器中运行。
对于简单的情况,向某些 DOM 访问添加条件语句或可选链可能足以防止无法访问的 DOM API。例如
const hasConstructableStylesheets = typeof globalThis.CSSStyleSheet?.prototype.replaceSync === 'function';
lit
包还提供了一个 isServer
环境检查器,可用于编写针对不同环境的条件代码块
import {isServer} from 'lit';
if (isServer) {
// only runs in server environments like Node
} else {
// runs in the browser
}
条件导出
指向“条件导出”的永久链接对于更复杂的用例,请考虑使用条件导出,这些导出专门匹配 "node"
环境,以便您可以根据模块是在 Node 中导入还是在浏览器中导入来提供不同的代码。用户将根据模块是从 Node 导入还是从浏览器导入来获得相应的版本包。流行的捆绑工具(如rollup 和webpack)也支持导出条件,以便用户可以为您的捆绑包引入相应的代码。
一个示例配置可能如下所示
// package.json
{
"name": "my-awesome-lit-components",
"exports": {
"./button.js": {
"node": "./button-node.js",
"default": "./button.js"
}
}
}
Node 入口点文件可以手动创建,或者您可以使用捆绑器来生成这些文件。
捆绑器
指向“捆绑器”的永久链接如果可能,请避免将 Lit 内联捆绑到发布的组件中。
由于 Lit 包使用条件导出向 Node 和浏览器环境提供不同的模块,因此我们强烈建议不要将 lit
捆绑到您发布到 NPM 的包中。如果您这样做,您的捆绑包只会包含专为您的捆绑环境设计的 lit
模块,并且不会根据环境自动切换。
如果您使用 ESBuild 或 Rollup 之类的捆绑器来转换代码,则可以将包标记为外部,以便它们不会被捆绑到您的组件中。ESBuild 具有packages
选项,用于将所有依赖项外部化,或者您可以在external 选项中仅标记 lit
和相关包。类似地,Rollup 也具有等效的"external" 配置选项。
如果您必须将 Lit 库代码捆绑到您的组件中(例如,通过 CDN 分发),我们建议创建两个入口点:一个用于浏览器,一个用于 Node。捆绑器将具有选项,可以选择浏览器或 Node 之类的目标平台,或者允许您明确指定用于解析模块的导出条件。
例如,ESBuild 具有platform
选项,在 Rollup 中,您可以向 @rollup/plugin-node-resolve
的exportConditions
选项提供 "node"
。
然后,必须在您的组件库的 package.json
文件中指定这些用于浏览器和 Node 目标的入口点。请参见条件导出,了解详细信息。
生命周期
指向“生命周期”的永久链接仅在服务器端渲染期间运行某些生命周期回调。这些回调生成组件的初始样式和标记。在组件被水合后,其他生命周期方法将在客户端水合期间和运行时期间调用。
下表列出了标准自定义元素和 Lit 生命周期方法,以及它们是否在 SSR 期间调用。所有生命周期都在元素注册和水合后在浏览器中可用。
在服务器上调用的方法不应包含对未模拟的浏览器/DOM API 的引用。未在服务器端调用的方法可能包含这些引用,不会造成中断。
方法是否在服务器上调用取决于 Lit SSR 作为 Lit Labs 的一部分而发生变化。
标准自定义元素和 LitElement
指向“标准自定义元素和 LitElement”的永久链接方法 | 在服务器上调用 | 说明 |
---|---|---|
constructor() | 是 ⚠️ | |
connectedCallback() | 否 | |
disconnectedCallback() | 否 | |
attributeChangedCallback() | 否 | |
adoptedCallback() | 否 | |
hasChanged() | 是 ⚠️ | 属性设置时调用 |
shouldUpdate() | 否 | |
willUpdate() | 是 ⚠️ | 在 render() 之前调用 |
update() | 否 | |
render() | 是 ⚠️ | |
firstUpdate() | 否 | |
updated() | 否 |
ReactiveController
指向“ReactiveController”的永久链接方法 | 在服务器上调用 | 说明 |
---|---|---|
constructor() | 是 ⚠️ | |
hostConnected() | 否 | |
hostDisconnected() | 否 | |
hostUpdate() | 否 | |
hostUpdated() | 否 |
方法 | 在服务器上调用 | 说明 |
---|---|---|
constructor() | 是 ⚠️ | |
update() | 否 | |
render() | 是 ⚠️ | |
disconnected() | 否 | 仅异步指令 |
reconnected() | 否 | 仅异步指令 |
异步性
指向“异步性”的永久链接目前没有机制可以等待异步结果,然后再继续渲染(例如来自异步指令或控制器的结果),尽管我们正在考虑将来允许此操作的选项。目前解决此问题的办法是在服务器上渲染顶级模板之前执行任何异步工作,并将数据作为某些属性或属性提供给模板。
例如
- 诸如
asyncAppend()
或asyncReplace()
之类的异步指令不会在服务器端产生任何可渲染的结果。 until()
指令只会产生最高优先级非 Promise 占位符值。
@lit-labs/testing
包包含使用Web Test Runner 插件创建测试夹具的实用函数,这些夹具使用 @lit-labs/ssr
在服务器端渲染。它可以帮助测试您的组件是否可服务器端渲染。请参见自述文件 中的更多信息。