公開
このページでは、圧倒的多数のJavaScriptライブラリと開発者が使用するパッケージマネージャーであるnpmにLitコンポーネントを公開するためのガイドラインを提供します。スターターキットを参照して、npmへの公開用に設定された再利用可能なコンポーネントテンプレートを確認してください。
npmへの公開
「npmへの公開」へのパーマリンクコンポーネントをnpmに公開するには、npmパッケージの投稿に関する手順を参照してください。
package.json設定には、type
、main
、およびmodule
フィールドが必要です
package.json
{
"type": "module",
"main": "my-element.js",
"module": "my-element.js"
}
また、コンポーネントの使用方法を説明するREADMEを作成する必要があります。
最新のJavaScriptの公開
「最新のJavaScriptの公開」へのパーマリンクJavaScriptモジュールは標準のES2021構文で公開することをお勧めします。これはすべてのエバーグリーンブラウザでサポートされており、最速で最小のJavaScriptになります。パッケージのユーザーは、古いブラウザをサポートするためにコンパイラを使用できますが、公開前にコードをプリコンパイルすると、レガシーJavaScriptを最新の構文に変換することはできません。
ただし、TypeScript、デコレータ、クラスフィールドなどの新しく提案された、または非標準のJavaScript機能を使用している場合は、npmに公開する前に、ブラウザでネイティブにサポートされている標準ES2021にコンパイルする必要があります。
TypeScriptでのコンパイル
「TypeScriptでのコンパイル」へのパーマリンク次のJSONサンプルは、ES2021をターゲットとするための推奨オプションを使用し、デコレータのコンパイルを有効にし、ユーザー向けに.d.ts
タイプを出力する部分的なtsconfig.json
です
tsconfig.json
"compilerOptions": {
"target": "es2021",
"module": "es2015",
"moduleResolution": "node",
"lib": ["es2021", "dom"],
"declaration": true,
"declarationMap": true,
"experimentalDecorators": true,
"useDefineForClassFields": false
}
なお、`useDefineForClassFields`を`false`に設定する必要があるのは、`target`が`es2022`以上に設定されている場合(`esnext`を含む)のみですが、この設定が`false`であることを明示的に確認することをお勧めします。
TypeScriptからコンパイルする場合、`package.json`の`types`フィールドにコンポーネントの型の宣言ファイル(上記の`declaration: true`に基づいて生成されます)を含め、`.d.ts`および`.d.ts.map`ファイルも公開されていることを確認する必要があります
package.json
{
...
"types": "my-element.d.ts"
}
詳細については、tsconfig.jsonのドキュメントを参照してください。
Babelでのコンパイル
「Babelでのコンパイル」へのパーマリンクES2021にまだ含まれていない、提案されたJavaScript機能を使用するLitコンポーネントをコンパイルするには、Babelを使用します。
Babelと必要なBabelプラグインをインストールします。例えば
npm install --save-dev \
@babel/core \
@babel/cli \
@babel/preset-env \
@babel/plugin-proposal-decorators
Babelを設定します。例えば
babel.config.json
{
"presets": [
["@babel/preset-env", {"targets": "defaults"}]
],
"plugins": [
["@babel/plugin-proposal-decorators", {"version": "2023-05"}]
]
}
サポートするブラウザをターゲットにするために、`"targets"`オプションを調整できます。使用可能なオプションについては、`@babel/preset-env`を参照してください。
@rollup/plugin-babelなどのバンドラープラグイン、またはコマンドラインからBabelを実行できます。詳細については、Babelのドキュメントを参照してください。
公開のベストプラクティス
「公開のベストプラクティス」へのパーマリンク再利用可能なWebコンポーネントを公開する際に従うべきその他のグッドプラクティスを以下に示します。
モジュールにポリフィルをインポートしないでください
「モジュールにポリフィルをインポートしないでください」へのパーマリンクポリフィルはアプリケーションの懸念事項であるため、個々のパッケージではなく、アプリケーションが直接依存する必要があります。必要なポリフィルは、アプリケーションがサポートする必要があるブラウザによって異なり、その選択はコンポーネントを使用するアプリケーション開発者に任せるのが最善です。コンポーネントのドキュメントでは、ポリフィルが必要になる可能性のあるAPIを明確に示す必要があります。
パッケージはテストとデモのためにポリフィルに依存する必要がある場合があるため、必要な場合は`devDependencies`にのみ配置する必要があります。
モジュールをバンドル、縮小、または最適化しないでください
モジュールをバンドル、縮小、または最適化しないでください」へのパーマリンクバンドリングやその他の最適化はアプリケーションの懸念事項です。npmはパッケージを重複排除できないため、npmに公開する前に再利用可能なコンポーネントをバンドルすると、ユーザーのアプリケーションに複数のバージョンのLit(およびその他のパッケージ)が導入される可能性があります。これは膨張を引き起こし、バグを引き起こす可能性があります。
モジュールを公開前に最適化すると、アプリケーションレベルの最適化が妨げられる可能性があります。
CDNからモジュールを提供する場合、バンドリングやその他の最適化は役立ちますが、ユーザーはLitに依存する複数のパッケージを使用する必要がある場合があるため、CDNから提供すると、ユーザーが必要以上に多くのコードを読み込むことになります。これらの理由から、パフォーマンスに敏感なアプリケーションでは、パッケージを重複排除できるnpmから常にビルドすることをお勧めします。CDNからバンドルされたパッケージを読み込むことはお勧めしません。
CDNからの使用をサポートする場合は、CDNモジュールと本番環境で使用するためのモジュールを明確に区別することをお勧めします。たとえば、別のフォルダーに配置するか、GitHubリリースの一部としてのみ追加し、公開されたnpmモジュールには追加しません。
インポート指定子にファイル拡張子を含めてください
インポート指定子にファイル拡張子を含めてください」へのパーマリンクNodeモジュール解決では、ファイル拡張子が指定されていない場合、ファイルシステムを検索して複数のファイル拡張子のいずれかを探すため、ファイル拡張子は必要ありません。`some-package/foo`をインポートすると、Nodeは`some-package/foo.js`が存在する場合にそれをインポートします。同様に、パッケージ指定子をURLに解決するビルドツールも、ビルド時にこのファイルシステム検索を実行できます。
ただし、ブラウザで出荷が始まっているインポートマップ仕様により、ブラウザはインポートマップマニフェスト(これはおそらくツールによって生成されます。例:npmインストールに基づく)でインポート指定子とURLのマッピングを提供することにより、ソースから変換されていないベアプリッケージ指定子を使用してモジュールを読み込むことができます。
インポートマップでは、インポートをURLにマッピングできますが、マッピングには正確なマッピングとプレフィックスマッピングの2種類しかありません。つまり、パッケージ名を単一のURLプレフィックスにマッピングすることで、指定されたパッケージの下のすべてのモジュールに簡単にエイリアスを付けることができます。ただし、ファイル拡張子なしでインポートを記述すると、パッケージ内の各ファイルにインポートマップのエントリが必要になります。これはインポートマップを大幅に膨張させる可能性があります。
そのため、インポートマップとの最適な互換性を得るために、インポートにファイル拡張子を使用して作成することをお勧めします。
TypeScriptの型定義を公開する
`TypeScriptの型定義を公開する`へのパーマリンクTypeScriptから要素を簡単に使用できるように、以下をお勧めします。
TypeScriptで作成されたすべての要素に`HTMLElementTagNameMap`エントリを追加します。
@customElement('my-element')
export class MyElement extends LitElement { /* ... */ }
declare global {
interface HTMLElementTagNameMap {
"my-element": MyElement;
}
}
npmパッケージに`.d.ts`型定義を公開します。
`HTMLElementTagNameMap`の詳細については、適切なTypeScript型定義の提供を参照してください。
要素を自己定義する
「要素を自己定義する」へのパーマリンクWebコンポーネントクラスを宣言するモジュールには、要素を定義するための`customElements.define()`(または`@customElement`デコレータ)の呼び出しが常に含まれている必要があります。
現在、Webコンポーネントは常にグローバルレジストリで定義されています。カスタム要素の定義ごとに、一意のタグ名と一意のJavaScriptクラスを使用する必要があります。同じタグ名、または同じクラスを2回登録しようとすると、エラーが発生して失敗します。単にクラスをエクスポートして、ユーザーがdefine()
を呼び出すことを期待するのは脆弱です。2つの異なるコンポーネントがどちらも共有の第3コンポーネントに依存しており、両方がそれを定義しようとすると、一方が失敗します。要素が常にそのクラスが宣言されているのと同じモジュールで定義されている場合は、これは問題ではありません。
このアプローチの欠点の1つは、2つの異なる要素が同じタグ名を使用する場合、両方を同じプロジェクトにインポートできないことです。
プラットフォームにスコープ付きカスタム要素レジストリを追加する作業が進んでいます。スコープ付きレジストリを使用すると、特定のシャドウルートスコープに対して、コンポーネントのユーザーがカスタム要素のタグ名を選択できます。ブラウザがこの機能の提供を開始すると、コンポーネントごとに2つのモジュールを公開することが実用的になります。1つは副作用なしでカスタム要素クラスをエクスポートするモジュール、もう1つはタグ名を使用してグローバルに登録するモジュールです。
それまでは、グローバルレジストリに要素を登録し続けることをお勧めします。
要素クラスをエクスポートする
「要素クラスのエクスポート」へのパーマリンクサブクラス化をサポートするために、要素クラスを定義するモジュールからエクスポートします。これにより、拡張目的のサブクラス化と、将来のスコープ付きカスタム要素レジストリへの登録が可能になります。
さらに読むために
「参考資料」へのパーマリンク高品質で再利用可能なWebコンポーネントを作成するためのより一般的なガイドについては、Webコンポーネントのゴールドスタンダードチェックリストを参照してください。