コンセプト

lit-htmlはJavaScript標準のテンプレートリテラルや、HTML<template>要素の独自のプロパティを使って高速なパフォーマンスを実現しています。よって、最初にそれらを理解するのは大事なことです。

タグ付きテンプレートリテラル

JavaScript標準のテンプレートリテラルは、JavaScript評価式を埋め込むことができる文字列リテラルです。

`My name is ${name}.`

いわゆるリテラルとは、引用符の代わりにバッククォートを使い、複数の行にまたがることができます。${}の内部は 全ての JavaScript評価式が使えます。

タグ付けされた テンプレートリテラルは、特別なテンプレートタグ機能が付いています:

let name = 'Monica';
tag`My name is ${name}.`

テンプレートタグは、テンプレートのリテラル文字列と埋め込み式の値を受け取り、新しい値を返す関数です。これは文字列だけでなく、あらゆる種類の値を返すことができます。lit-htmlは、TemplateResult というテンプレートを表すオブジェクトを返します。

lit-htmlが高速に更新を行うために利用するテンプレートタグの重要な機能は、テンプレートのリテラル文字列を保持するオブジェクトが、特定のテンプレートのタグを何度呼び出しても 正確に 同じであることです。

これは、文字列をキャッシュへのキーとして使えるので、lit-htmlはテンプレートを初めて描画したときにテンプレートの準備を一度しか行わず、その作業をスキップして更新することができることを意味します。

HTMLテンプレート要素

<template>要素は、インスタンス化していない部分的なDOMです。テンプレートのコンテンツ内では、スクリプトは実行されず、画像も読み込まれず、カスタム要素も更新されません。コンテンツは効率的に複製できます。テンプレート要素は通常、文書のセクションを解析する際にインスタンス化しないようHTMLパーサを伝えるために使われますが、createElementinnerHTMLによって命令的に作成することもできます。

lit-htmlはHTML<template>要素をタグ付きテンプレートリテラルから作成し、それらをクローンして新しいDOMを作成します。

テンプレート生成

特定のlit-htmlテンプレートがアプリケーション内のどこかで最初に描画される時、lit-htmlは一度だけHTMLテンプレートを作成します。すべてのリテラル部分を特殊なプレースホルダ"{{}}"で結合し、次に<template>を作成し、innerHTMLに結果を格納します。

次のようなテンプレートで始める場合:

let header = (title) => html`<h1>${title}</h1>`;

lit-htmlは次のようなHTMLを生成します:

<h1>{{}}</h1>

そこから<template>を生成します。

その後、lit-htmlはテンプレートのDOMをまわってプレースホルダを抽出し、その場所を記録します。最終的なテンプレートにはプレースホルダは含まれていません。

<h1></h1>

lit-htmlは式がどこにあったかの補助テーブルをつくります:

[{type: 'node', index: 1}]

テンプレート描画

render()TemplateResultオブジェクトをとり、それをDOMコンテナに描画します。最初の描画では、テンプレートをクローンし、次に記憶されたプレースホルダ位置を覚えてテンプレートを巡り、Partオブジェクトを作成します。

Partは値を挿入できるDOMの「穴」です。lit-htmlはバインディングする型によってPartのサブクラスを持ちます。NodePartはテキストコンテンツのバインディングで、AttributePartは属性の値を設定できるようになっています。Partオブジェクトのコンテナ、およびグループ化されたテンプレートが呼び出されたオブジェクトはTemplateInstanceと呼ばれます。

関数的に考えよう

lit-htmlは、関数的アプローチでUIを記述するのに最適です。UIをデータの関数と考えると、通常は次のように表されます UI = f(data)。これを正確に表すlit-htmlテンプレートは次のように書くことができます。

let ui = (data) => html`...${data}...`;

この種の機能は、データの変更があればいつでも呼び出すことができ、非常に低コストで呼び出すことができます。lit-htmlがhtmlタグで行う唯一のことは、引数を元にテンプレートを生成することです。

結果が描画されると、前の描画以降に値が変更された式のみが更新されます。

これは、書くことが容易で推論が簡単なモデルにつながります。常に依存するデータの単純な関数としてのUIの記述、中間状態のキャッシングの回避、または手動によるDOM操作の実行をするようにしてください。lit-htmlは、ほとんどの場合、あなたのUIへの最も単純な記述で十分に速く動作します。

JavaScriptモジュール

なぜlit-htmlはUMD / CJS / AMDではなく、JavaScriptモジュールとして配布(ESM)されていますか?

JavaScriptモジュール機構がリリースされるまで、ブラウザはコードからコードをインポートする標準的な方法を持っていなかったので、ユーザーランドモジュールローダまたはバンドルが必要でした。標準の枠組みがなかったことで、競合するフォーマットが倍増しました。多くの場合、ライブラリはさまざまなツールのユーザーをサポートするためにさまざまな形式で公開されていますが、これは共通ライブラリが他の多くの中間ライブラリに依存している場合に問題を引き起こします。それらの中間ライブラリのいくつかがフォーマットAをロードし、他のフォーマットがフォーマットBをロードし、フォーマットCをロードするものがあると、複数のコピーがロードされ、膨らんで、パフォーマンスが低下します、みつけにくいバグを引き起します。

唯一の真の解決策は、他のすべてのライブラリがインポートするライブラリの正規バージョンを1つ持つことです。モジュールは現在ブラウザでサポートされており、ツールでも非常にうまく扱えるため、フォーマットをJavaScritpモジュール機構とすることは理にかなっています。

現在のブラウザは、フルパスまたは相対パス( /./、または ../で始まるパス)を使用して指定されたモジュールのみを受け付けます。編集を容易にするために、多くの開発者は名前でモジュールをインポートすることを好みます(nodeスタイルのモジュール形式としても知られています)。これは現在ブラウザではサポートされていないため、これらの指定をブラウザ対応のパスに変換できるツールを使用する必要があります。開発サーバーに関する情報についてはツールを参照し、この変換を実行できるツールで構築してください:

JavaScriptモジュールの詳細については、次を参照してください。