パッケージング
SvelteKitを使用して、アプリケーションだけでなく、`@sveltejs/package`パッケージを使用してコンポーネントライブラリも構築できます(`npx sv create`には、これを設定するためのオプションがあります)。
アプリケーションを作成する場合、`src/routes`の内容は公開されるものです。 `src/lib`には、アプリケーションの内部ライブラリが含まれています。
コンポーネントライブラリは、SvelteKitアプリケーションとまったく同じ構造ですが、`src/lib`が公開される部分であり、ルート`package.json`がパッケージの公開に使用される点が異なります。 `src/routes`は、ライブラリに付属するドキュメントまたはデモサイトである場合もあれば、開発中に使用するサンドボックスである場合もあります。
`@sveltejs/package`から`svelte-package`コマンドを実行すると、`src/lib`の内容が取得され、以下を含む`dist`ディレクトリ(設定可能)が生成されます。
- `src/lib`内のすべてのファイル。 Svelteコンポーネントは前処理され、TypeScriptファイルはJavaScriptにトランスパイルされます。
- Svelte、JavaScript、およびTypeScriptファイル用に生成される型定義(`d.ts`ファイル)。 これには、`typescript >= 4.0.0`をインストールする必要があります。 型定義は実装の横に配置され、手書きの`d.ts`ファイルはそのままコピーされます。 生成を無効にすることもできますが、強くお勧めしません。ライブラリを使用するユーザーはTypeScriptを使用する可能性があり、そのためにはこれらの型定義ファイルが必要です。
`@sveltejs/package`バージョン1は`package.json`を生成しました。 これはもはや当てはまらず、プロジェクトの`package.json`を使用して、代わりにそれが正しいことを検証します。 まだバージョン1を使用している場合は、移行手順についてこのPRを参照してください。
package.jsonの構造
公開用のライブラリを構築しているので、`package.json`の内容がより重要になります。 これを通じて、パッケージのエントリポイント、npmに公開されるファイル、ライブラリの依存関係を設定します。 最も重要なフィールドを1つずつ見ていきましょう。
name
これはパッケージの名前です。 他の人がその名前を使用してインストールできるようになり、`https://npmjs.com/package/<name>`に表示されます。
{
"name": "your-library"
}
詳細については、こちらをご覧ください。
license
すべてのパッケージには、ライセンスフィールドが必要です。これにより、人々はどのように使用できるかを知ることができます。 保証なしで配布と再利用に関して非常に寛容な、非常に一般的なライセンスは`MIT`です。
{
"license": "MIT"
}
詳細については、こちらをご覧ください。 パッケージには`LICENSE`ファイルも含める必要があることに注意してください。
files
これは、npmがパッケージ化してnpmにアップロードするファイルを指示します。 出力フォルダー(デフォルトでは`dist`)が含まれている必要があります。 `package.json`と`README`と`LICENSE`は常に含まれているため、指定する必要はありません。
{
"files": ["dist"]
}
不要なファイル(単体テスト、`src/routes`などからのみインポートされるモジュールなど)を除外するには、`。npmignore`ファイルに追加します。 これにより、インストールが高速になる、より小さなパッケージが作成されます。
詳細については、こちらをご覧ください。
exports
`"exports"`フィールドには、パッケージのエントリポイントが含まれています。 `npx sv create`を介して新しいライブラリプロジェクトを設定する場合、パッケージルートの単一エクスポートに設定されます。
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
}
}
これは、バンドラーとツールに、パッケージにはエントリポイントが1つだけ(ルート)であり、すべてを次のようにインポートする必要があることを伝えます。
import { import Something
Something } from 'your-library';
`types`キーと`svelte`キーは、エクスポート条件です。 これらは、`your-library`インポートを検索するときにどのファイルをインポートするかをツールに指示します。
- TypeScriptは`types`条件を確認し、型定義ファイルを検索します。 型定義を公開しない場合は、この条件を省略します。
- Svelte対応のツールは`svelte`条件を確認し、これがSvelteコンポーネントライブラリであることを認識します。 Svelteコンポーネントをエクスポートせず、Svelte以外のプロジェクトでも機能するライブラリ(たとえば、Svelteストアライブラリ)を公開する場合は、この条件を`default`に置き換えることができます。
以前のバージョンの`@sveltejs/package`も`package.json`エクスポートを追加しました。 すべてのツールが`package.json`が明示的にエクスポートされていないことを処理できるようになったため、これはもはやテンプレートの一部ではありません。
`exports`を好みに合わせて調整し、より多くのエントリポイントを提供できます。 たとえば、コンポーネントを再エクスポートした`src/lib/index.js`ファイルの代わりに、`src/lib/Foo.svelte`コンポーネントを直接公開する場合は、次のエクスポートマップを作成できます...
{
"exports": {
"./Foo.svelte": {
"types": "./dist/Foo.svelte.d.ts",
"svelte": "./dist/Foo.svelte"
}
}
}
...そして、ライブラリの消費者は、次のようにコンポーネントをインポートできます。
import module "your-library/Foo.svelte"
Foo from 'your-library/Foo.svelte';
これを行うと、型定義を提供する場合に追加の注意が必要になることに注意してください。 注意点の詳細については、こちらをご覧ください。
一般に、エクスポートマップの各キーは、ユーザーがパッケージから何かをインポートするために使用する必要があるパスであり、値はインポートされるファイルへのパス、またはこれらのファイルパスを含むエクスポート条件のマップです。
`exports`の詳細については、こちらをご覧ください。
svelte
これは、ツールがSvelteコンポーネントライブラリを認識できるようにするレガシーフィールドです。 `svelte` エクスポート条件を使用する場合、これはもはや必要ありませんが、エクスポート条件をまだ知らない古いツールとの下位互換性のために、これを保持することをお勧めします。 ルートエントリポイントを指している必要があります。
{
"svelte": "./dist/index.js"
}
sideEffects
`package.json`の`sideEffects`フィールドは、バンドラーがモジュールに副作用のあるコードが含まれている可能性があるかどうかを判断するために使用されます。 モジュールは、インポートされたときにモジュール外の他のスクリプトから観察できる変更を加える場合、副作用があると見なされます。 たとえば、副作用には、グローバル変数または組み込みJavaScriptオブジェクトのプロトタイプの変更が含まれます。 副作用はアプリケーションの他の部分の動作に影響を与える可能性があるため、これらのファイル/モジュールは、エクスポートがアプリケーションで使用されているかどうかに関係なく、最終バンドルに含まれます。 コードで副作用を回避することをお勧めします。
`package.json`に`sideEffects`フィールドを設定すると、バンドラーはツリーシェイキングとして知られるプロセスである最終バンドルから未使用のエクスポートを排除する際に、より積極的になることができます。 これにより、バンドルが小さく効率的になります。 さまざまなバンドラーが`sideEffects`をさまざまな方法で処理します。 Viteには必要ありませんが、ライブラリがすべてのCSSファイルに副作用があると明記することをお勧めします。これにより、ライブラリはwebpackと互換性があります。 これは、新しく作成されたプロジェクトに付属する構成です。
{
"sideEffects": ["**/*.css"]
}
ライブラリのスクリプトに副作用がある場合は、`sideEffects`フィールドを更新してください。 新しく作成されたプロジェクトでは、デフォルトですべてのスクリプトに副作用がないとマークされています。 副作用のあるファイルに誤って副作用がないとマークされていると、機能が壊れる可能性があります。
パッケージに副作用のあるファイルがある場合は、配列で指定できます。
{
"sideEffects": [
"**/*.css",
"./dist/sideEffectfulFile.js"
]
}
これにより、指定されたファイルのみが副作用を持つと見なされます。
TypeScript
TypeScriptを自分で使用していない場合でも、ライブラリの型定義を提供する必要があります。これにより、ライブラリを使用する際に適切なインテリセンスが得られます。 `@sveltejs/package`は、型の生成プロセスをほとんど意識させません。 デフォルトでは、ライブラリをパッケージ化すると、JavaScript、TypeScript、およびSvelteファイルの型定義が自動的に生成されます。 確実にする必要があるのは、エクスポートマップの`types`条件が正しいファイルを指していることだけです。 `npx sv create`を介してライブラリプロジェクトを初期化すると、ルートエクスポートに対してこれが自動的に設定されます。
ただし、ルートエクスポート以外に何かがある場合(たとえば、`your-library/foo`インポートを提供する場合)、型定義の提供には追加の注意が必要です。 残念ながら、TypeScriptはデフォルトでは、`{ "./foo": { "types": "./dist/foo.d.ts", ... }}`のようなエクスポートの`types`条件を解決*しません*。 代わりに、ライブラリのルートを基準にして`foo.d.ts`を検索します(つまり、`your-library/dist/foo.d.ts`ではなく`your-library/foo.d.ts`)。 これを修正するには、2つのオプションがあります。
最初のオプションは、ライブラリを使用するユーザーに、`tsconfig.json`(または`jsconfig.json`)の`moduleResolution`オプションを`bundler`(TypeScript 5以降で使用可能、将来推奨される最良のオプション)、`node16`、または`nodenext`に設定するように要求することです。 これにより、TypeScriptは実際にエクスポートマップを調べて型を正しく解決します。
2番目のオプションは、TypeScriptの`typesVersions`機能を(悪用して)型を接続することです。 これは、TypeScriptバージョンに応じて異なる型定義をチェックするためにTypeScriptが使用する`package.json`内のフィールドであり、そのためのパスマッピング機能も含まれています。 このパスマッピング機能を活用して、必要なものを取得します。 上記の`foo`エクスポートの場合、対応する`typesVersions`は次のようになります。
{
"exports": {
"./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js"
}
},
"typesVersions": {
">4.0": {
"foo": ["./dist/foo.d.ts"]
}
}
}
>4.0
は、使用されている TypeScript のバージョンが 4 より大きい場合(実際には常に true になるはずです)、TypeScript に内部マップをチェックするように指示します。内部マップは、your-library/foo
の型定義が ./dist/foo.d.ts
内にあることを TypeScript に伝えます。これは本質的に exports
条件を複製するものです。また、ワイルドカードとして *
を使用することで、多くの型定義を一度に利用可能にし、繰り返しを避けることができます。 typesVersions
をオプトインする場合は、ルートインポート("index.d.ts": [..]
として定義されます)を含むすべての型インポートを宣言する必要があることに注意してください。
この機能の詳細については、こちらをご覧ください。
ベストプラクティス
他の SvelteKit プロジェクトでのみ使用することを意図していない限り、パッケージ内で $app/environment
のような SvelteKit 固有のモジュールを使用することは避けるべきです。たとえば、import { browser } from '$app/environment'
を使用する代わりに、import { BROWSER } from 'esm-env'
を使用できます(esm-env のドキュメントを参照)。また、現在の URL やナビゲーションアクションなどを $app/stores
、$app/navigation
などに直接依存するのではなく、プロップとして渡すこともできます。このようにより汎用的な方法でアプリを作成することで、テスト、UI デモなどのためのツールをセットアップしやすくなります。
svelte.config.js
(vite.config.js
や tsconfig.json
ではなく)を介してエイリアスを追加し、svelte-package
によって処理されるようにしてください。
パッケージに加える変更がバグ修正、新機能、または破壊的な変更のいずれであるかを慎重に検討し、それに応じてパッケージのバージョンを更新する必要があります。既存のライブラリから exports
からパス、またはその中の export
条件を削除する場合は、破壊的な変更と見なされることに注意してください。
{
"exports": {
".": {
"types": "./dist/index.d.ts",
// changing `svelte` to `default` is a breaking change:
"svelte": "./dist/index.js"
"default": "./dist/index.js"
},
// removing this is a breaking change:
"./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js",
"default": "./dist/foo.js"
},
// adding this is ok:
"./bar": {
"types": "./dist/bar.d.ts",
"svelte": "./dist/bar.js",
"default": "./dist/bar.js"
}
}
}
オプション
svelte-package
は以下のオプションを受け入れます
-w
/--watch
—src/lib
内のファイルの変更を監視し、パッケージを再構築します-i
/--input
— パッケージのすべてのファイルを含む入力ディレクトリ。デフォルトはsrc/lib
です-o
/--output
— 処理されたファイルが書き込まれる出力ディレクトリ。package.json
のexports
は、このディレクトリ内のファイルを指し示し、files
配列にはこのフォルダが含まれている必要があります。デフォルトはdist
です-t
/--types
— 型定義(d.ts
ファイル)を作成するかどうか。エコシステムライブラリの品質向上のため、これを行うことを強くお勧めします。デフォルトはtrue
です--tsconfig
- tsconfig または jsconfig へのパス。指定されていない場合は、ワークスペースパスで次に上位の tsconfig/jsconfig を検索します。
公開
生成されたパッケージを公開するには
npm publish
注意事項
すべての相対ファイルインポートは、Node の ESM アルゴリズムに準拠して、完全に指定する必要があります。つまり、src/lib/something/index.js
のようなファイルの場合、拡張子を含むファイル名を指定する必要があります
import { import something
something } from './something/index.js';
TypeScript を使用している場合は、.ts
ファイルを同じ方法でインポートする必要がありますが、.ts
ファイルの末尾ではなく、.js
ファイルの末尾を使用します。(これは、制御できない TypeScript の設計上の決定です。)tsconfig.json
または jsconfig.json
で "moduleResolution": "NodeNext"
を設定すると、これに役立ちます。
Svelte ファイル(プリプロセス済み)と TypeScript ファイル(JavaScript にトランスパイル済み)を除くすべてのファイルは、そのままコピーされます。