Lit SSR サーバーの使用方法
テンプレートのレンダリング
「テンプレートのレンダリング」へのパーマリンクサーバーレンダリングは、@lit-labs/ssr パッケージで提供されるサーバー固有の render() 関数を使用して、Lit テンプレートをレンダリングすることから始まります。
render 関数のシグネチャは次のとおりです
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 が含まれているわけではありません。Promise は、カスタム要素がデータのフェッチなどの非同期タスクを実行するときに発生する可能性があります。しかし、RenderResult には Promise を含めることができるため、文字列または HTTP レスポンスに処理することは潜在的に非同期操作です。
RenderResult には Promise を含めることができますが、それでも非同期イテラブルではなく、同期イテラブルです。これは、同期イテラブルが非同期イテラブルよりも高速であり、多くのサーバーレンダリングでは非同期レンダリングを必要とせず、非同期イテラブルのオーバーヘッドを支払うべきではないためです。
同期イテラブルで Promise を許可すると、一種のハイブリッド同期/非同期イテレーションプロトコルが作成されます。RenderResult を使用する場合は、各値が Promise かイテラブルかどうかを確認し、必要に応じて待機または再帰する必要があります。
@lit-labs/ssr には、これを行うための 3 つのユーティリティが含まれています
RenderResultReadablecollectResult()collectResultSync()
RenderResultReadable
「RenderResultReadable」へのパーマリンク RenderResultReadable は、RenderResult から値を提供する Node Readable ストリームの実装です。これは、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 streamapp.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() の 2 番目の引数は、オプションと現在のレンダリング状態をコンポーネントとサブテンプレートに渡すために使用される RenderInfo オブジェクトです。
呼び出し元が設定できる主なオプションは次のとおりです。
deferHydration: トップレベルのカスタム要素に、要素が自動的にハイドレートしないことを知らせるdefer-hydration属性を追加するかどうかを制御します。これはデフォルトでfalseに設定されており、トップレベルの要素が自動的にハイドレートするように設定されています。elementRenderers: カスタム要素のレンダリングに使用するElementRendererクラスの配列。デフォルトでは、Lit 要素をレンダリングするためのLitElementRendererが含まれています。カスタムのElementRendererインスタンスを含めるように設定したり(ドキュメントは後日公開)、カスタム要素のレンダリングを完全に無効にするために空の配列に設定したりできます。
VMモジュールまたはグローバルスコープでのSSRの実行
「VMモジュールまたはグローバルスコープでのSSRの実行」へのパーマリンクNode でカスタム要素をレンダリングするには、まずグローバルな customElements API で定義および登録する必要があります。これはブラウザ専用の機能です。そのため、Lit が Node で実行されると、サーバーで Lit をレンダリングするために必要な最小限の DOM API のセットを自動的に使用し、customElements グローバルを定義します。(エミュレートされた API のリストについては、DOM エミュレーションを参照してください。)
Lit SSR は、カスタム要素をサーバー側でレンダリングする 2 つの異なる方法を提供します。それは、グローバルスコープでレンダリングするか、VM モジュールを介してレンダリングすることです。VM モジュールは、V8 仮想マシンコンテキスト内でコードを実行できるようにする Node の vm.Module API を利用します。2 つの方法は、主にカスタム要素のレジストリなどのグローバル状態がどのように共有されるかが異なります。
グローバルスコープでレンダリングする場合、単一の共有 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 exampleapp.use(async (ctx) => { const ssrResult = render(myTemplate(data)); ctx.type = 'text/html'; ctx.body = new RenderResultReadable(ssrResult);});VMモジュール
「VMモジュール」へのパーマリンクLit は、アプリケーションコードを別の VM コンテキストにロードし、独自のグローバルオブジェクトでレンダリングする方法も提供します。
// render-template.jsimport {render} from '@lit-labs/ssr';import {myTemplate} from './my-template.js';
export const renderTemplate = (someData) => { return render(myTemplate(someData));};// server.jsimport {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 exampleapp.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.jsimport {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 exampleapp.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 に渡す必要があります。