Lit SSR 服务器使用
渲染模板
永久链接到“渲染模板”服务器渲染从使用 @lit-labs/ssr
软件包中提供的服务器特定 render()
函数渲染 Lit 模板 开始。
渲染函数的签名是
render(value: unknown, renderInfo?: Partial<RenderInfo>): RenderResult
通常,value
是由 Lit 模板表达式生成的 TemplateResult
,例如
html`<h1>Hello</h1>`
模板可以包含自定义元素。如果自定义元素在服务器上定义,它们将依次渲染,以及它们的模板。
import {render} from '@lit-labs/ssr';
import {html} from 'lit';
// Import `my-element` on the server to server render it.
import './my-element.js';
const result = render(html`
<h1>Hello SSR!</h1>
<my-element></my-element>
`);
要渲染单个元素,您需要渲染一个只包含该元素的模板
import {html} from 'lit';
import './my-element.js';
const result = render(html`<my-element></my-element>`);
处理 RenderResults
永久链接到“处理 RenderResults”render()
返回一个 RenderResult
:一个可迭代的值,可以将其流式传输或连接成字符串。
RenderResult
可以包含字符串、嵌套的渲染结果或字符串或渲染结果的 Promise。并非所有渲染结果都包含 Promise—这些情况可能发生在自定义元素执行异步任务时,例如获取数据—但由于 RenderResult
可以包含 Promise,因此将其处理成字符串或 HTTP 响应是一个潜在的异步操作。
即使 RenderResult
可以包含 Promise,它仍然是一个同步可迭代对象,而不是异步可迭代对象。这是因为同步可迭代对象比异步可迭代对象更快,而且许多服务器渲染不需要异步渲染,因此不应该为异步可迭代对象付出开销。
允许在同步可迭代对象中使用 Promise 创建了一种混合的同步/异步迭代协议。在使用 RenderResult
时,您必须检查每个值,以查看它是否是 Promise 或可迭代对象,并在需要时等待或递归。
@lit-labs/ssr
包含三个实用程序来为您执行此操作
RenderResultReadable
collectResult()
collectResultSync()
RenderResultReadable
永久链接到“RenderResultReadable” RenderResultReadable
是 Node Readable
流实现,它提供 RenderResult
中的值。这可以被管道传输到 Writable
流,或者传递给像 Koa 这样的 Web 服务器框架。
这是在与流式 HTTP 服务器或其他支持流的 API 集成时处理 SSR 结果的首选方法。
import {render} from '@lit-labs/ssr';
import {RenderResultReadable} from '@lit-labs/ssr/lib/render-result-readable.js';
import {html} from 'lit';
// Using Koa to stream
app.use(async (ctx) => {
const result = render(html`<my-element></my-element>`);
ctx.type = 'text/html';
ctx.body = new RenderResultReadable(result);
});
collectResult()
永久链接到“collectResult()” collectResult(result: RenderResult): Promise<string>
collectResult()
是一个异步函数,它接受一个 RenderResult
并将其连接成字符串。它等待 Promise 并递归到嵌套的可迭代对象中。
示例
import {render} from '@lit-labs/ssr';
import {collectResult} from '@lit-labs/ssr/lib/render-result.js';
import {html} from 'lit';
const result = render(html`<my-element></my-element>`);
const contents = await collectResult(result);
collectResultSync()
永久链接到“collectResultSync()” collectResultSync(result: RenderResult): Promise<string>
collectResultSync()
是一个同步函数,它接受一个 RenderResult
并将其连接成字符串。它递归到嵌套的可迭代对象中,但在遇到 Promise 时会抛出错误。
由于此函数不支持异步渲染,因此建议仅在无法等待异步函数时使用它。
import {render} from '@lit-labs/ssr';
import {collectResultSync} from '@lit-labs/ssr/lib/render-result.js';
import {html} from 'lit';
const result = render(html`<my-element></my-element>`);
// Throws if `result` contains a Promise!
const contents = collectResultSync(result);
渲染选项
永久链接到“渲染选项”render()
的第二个参数是一个 RenderInfo
对象,用于将选项和当前渲染状态传递给组件和子模板。
调用者可以设置的主要选项是
deferHydration
:控制顶级自定义元素是否添加了defer-hydration
属性,以指示元素不应自动水合。默认值为false
,因此顶级元素会自动水合。elementRenderers
:一个用于渲染自定义元素的ElementRenderer
类数组。默认情况下,它包含LitElementRenderer
来渲染 Lit 元素。它可以设置为包含自定义ElementRenderer
实例(文档即将发布),或者设置为一个空数组以完全禁用自定义元素渲染。
在 VM 模块或全局范围内运行 SSR
永久链接到“在 VM 模块或全局范围内运行 SSR”为了在 Node 中渲染自定义元素,它们必须首先在全局 customElements
API 中定义和注册,而 customElements
API 是一个浏览器专用功能。因此,当 Lit 在 Node 中运行时,它会自动使用一组最小的 DOM API 来在服务器上渲染 Lit,并定义 customElements
全局变量。(有关模拟的 API 列表,请参见 DOM 模拟。)
Lit SSR 提供两种不同的方式在服务器端渲染自定义元素:在 全局范围 或通过 VM 模块 渲染。VM 模块利用 Node 的 vm.Module
API,该 API 允许在 V8 虚拟机上下文中运行代码。这两种方法的主要区别在于全局状态(例如自定义元素注册表)的共享方式。
在全局范围内渲染时,将定义一个共享的 customElements
注册表,并将其与所有渲染请求共享,以及组件代码可能设置的任何其他全局状态。
使用 VM 模块渲染允许每个渲染请求拥有自己的上下文,该上下文具有与主 Node 进程分开的全局对象。customElements
注册表将仅在该上下文中安装,其他全局状态也将被隔离到该上下文。VM 模块是 Node 的一项实验性功能。
全局 | VM 模块 |
---|---|
优点
| 优点
|
全局范围
永久链接到“全局范围”当使用全局范围时,您只需使用模板调用 render()
即可获得 RenderResult
,并将该结果传递给您的服务器
import {render} from '@lit-labs/ssr';
import {RenderResultReadable} from '@lit-labs/ssr/lib/render-result-readable.js';
import {myTemplate} from './my-template.js';
// ...
// within a Koa middleware, for example
app.use(async (ctx) => {
const ssrResult = render(myTemplate(data));
ctx.type = 'text/html';
ctx.body = new RenderResultReadable(ssrResult);
});
VM 模块
永久链接到“VM 模块”Lit 还提供了一种方法,可以将应用程序代码加载到单独的 VM 上下文以及其自己的全局对象中,并从该上下文中进行渲染。
// render-template.js
import {render} from '@lit-labs/ssr';
import {myTemplate} from './my-template.js';
export const renderTemplate = (someData) => {
return render(myTemplate(someData));
};
// server.js
import {ModuleLoader} from '@lit-labs/ssr/lib/module-loader.js';
import {RenderResultReadable} from '@lit-labs/ssr/lib/render-result-readable.js';
// ...
// within a Koa middleware, for example
app.use(async (ctx) => {
const moduleLoader = new ModuleLoader();
const importResult = await moduleLoader.importModule(
'./render-template.js', // Module to load in VM context
import.meta.url // Referrer URL for module
);
const {renderTemplate} = importResult.module.namespace
as typeof import('./render-template.js')
const ssrResult = await renderTemplate({some: "data"});
ctx.type = 'text/html';
ctx.body = new RenderResultReadable(ssrResult);
});
// server.js
import {ModuleLoader} from '@lit-labs/ssr/lib/module-loader.js';
import {RenderResultReadable} from '@lit-labs/ssr/lib/render-result-readable.js';
// ...
// within a Koa middleware, for example
app.use(async (ctx) => {
const moduleLoader = new ModuleLoader();
const importResult = await moduleLoader.importModule(
'./render-template.js', // Module to load in VM context
import.meta.url // Referrer URL for module
);
const {renderTemplate} = importResult.module.namespace;
const ssrResult = await renderTemplate({some: "data"});
ctx.type = 'text/html';
ctx.body = new RenderResultReadable(ssrResult);
});
注意:使用此功能需要 Node 14+,并且由于它使用实验性的 VM 模块来创建与模块兼容的 VM 上下文,因此需要将 --experimental-vm-modules
标志传递给 Node。