こんにちは。よっしーです(^^)
今日は、SvelteKitでのパッケージングについて解説しています。
背景
SvelteKitでのパッケージングについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。
package.jsonの構造
公開用ライブラリを構築する場合、package.json
の内容がより重要になります。これを通じて、パッケージのエントリーポイント、npmに公開するファイル、ライブラリの依存関係を設定します。重要なフィールドを一つずつ見ていきましょう。
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 { 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 Foo from 'your-library/Foo.svelte';
型定義を提供する場合、これを行うには追加の注意が必要です。注意点の詳細についてはこちらを参照してください。
一般的に、exportsマップの各キーはユーザーがパッケージから何かをインポートする際に使用するパスであり、値はインポートされるファイルへのパス、またはそれらのファイルパスを含むエクスポート条件のマップです。
解説
このセクションは、package.jsonのexports
フィールドについて詳しく説明しています。主なポイントを整理します:
- 基本的な構造:
- シンプルなルートエクスポート
- 型定義とSvelteコンポーネントの指定
- エクスポート条件の設定
- エクスポート条件:
types
: TypeScript用の型定義svelte
: Svelteコンポーネント用default
: 一般的なJavaScript用
- カスタマイズ例:
- 個別コンポーネントのエクスポート
- パスマッピングの設定
- 型定義の考慮
- ベストプラクティス:
- 明確なエントリーポイントの定義
- 適切な型定義の提供
- ツール互換性の考慮
実装例:
{
"exports": {
// ルートエクスポート
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
},
// 個別コンポーネント
"./components": {
"types": "./dist/components/index.d.ts",
"svelte": "./dist/components/index.js"
},
// 特定のユーティリティ
"./utils": {
"types": "./dist/utils/index.d.ts",
"default": "./dist/utils/index.js"
}
}
}
このような設定により:
- クリーンなパッケージ構造の維持
- 効率的な型サポート
- 柔軟なインポートオプションの提供
が可能になります。
svelte
これは、Svelteコンポーネントライブラリをツールが認識できるようにするための従来のフィールドです。svelte
エクスポート条件を使用する場合には必要ありませんが、エクスポート条件をまだ認識しない古いツールとの後方互換性のために、このフィールドを維持しておくことが推奨されます。これはルートエントリーポイントを指定する必要があります。
{
"svelte": "./dist/index.js"
}
解説
このセクションは、package.jsonのsvelte
フィールドについて説明しています。主なポイントを詳しく解説します:
- 目的:
- Svelteライブラリの識別
- 古いツールとの互換性維持
- エントリーポイントの指定
- 現代的な代替手段:
exports
フィールドのsvelte
条件- より柔軟な設定が可能
- より明確な意図の表現
- 使用例:
{
"name": "my-svelte-library",
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
},
"svelte": "./dist/index.js" // 後方互換性のため
}
- 注意点:
- 新しいプロジェクトでも含めることを推奨
- ルートエントリーポイントと一致させる
exports
フィールドと整合性を保つ
このフィールドは以下の場合に特に重要です:
- 古いビルドツールをサポートする必要がある場合
- 広範な互換性が必要な場合
- 既存のプロジェクトとの統合が必要な場合
ベストプラクティス:
- 常に
exports
フィールドと一緒に使用 - 同じパスを指定して一貫性を保つ
- ドキュメントに互換性情報を記載
sideEffects
package.json
のsideEffects
フィールドは、モジュールがサイドエフェクトを含む可能性があるかどうかをバンドラーが判断するために使用されます。モジュールがインポートされた際に、モジュール外の他のスクリプトから観察可能な変更を行う場合、そのモジュールはサイドエフェクトを持つとみなされます。例えば、グローバル変数やJavaScriptの組み込みオブジェクトのプロトタイプを変更することなどがサイドエフェクトに含まれます。サイドエフェクトはアプリケーションの他の部分の動作に影響を与える可能性があるため、これらのファイル/モジュールは、そのエクスポートがアプリケーションで使用されているかどうかに関係なく、最終的なバンドルに含まれます。コードにサイドエフェクトを避けることがベストプラクティスです。
package.json
のsideEffects
フィールドを設定することで、バンドラーが最終バンドルから未使用のエクスポートを除去する処理(ツリーシェイキング)をより積極的に行うことができます。これにより、より小さく効率的なバンドルが実現できます。各バンドラーはsideEffects
を様々な方法で処理します。Viteでは必要ありませんが、ライブラリがwebpackと互換性を持つように、すべてのCSSファイルにサイドエフェクトがあることを宣言することを推奨します。これは新しく作成されたプロジェクトに付属する設定です:
{
"sideEffects": ["**/*.css"]
}
ライブラリのスクリプトにサイドエフェクトがある場合は、sideEffects
フィールドを更新してください。新しく作成されたプロジェクトでは、デフォルトですべてのスクリプトがサイドエフェクトフリーとしてマークされています。サイドエフェクトを持つファイルが誤ってサイドエフェクトなしとしてマークされると、機能が壊れる可能性があります。
パッケージにサイドエフェクトを持つファイルがある場合、それらを配列で指定できます:
{
"sideEffects": [
"**/*.css",
"./dist/sideEffectfulFile.js"
]
}
これにより、指定されたファイルのみがサイドエフェクトを持つものとして扱われます。
解説
このセクションは、package.jsonのsideEffects
フィールドについて詳しく説明しています。主なポイントを整理します:
- サイドエフェクトとは:
- グローバル変数の変更
- プロトタイプの変更
- モジュール外部に影響を与える変更
- ツリーシェイキングへの影響:
- 未使用コードの除去
- バンドルサイズの最適化
- パフォーマンスの向上
- 設定パターン:
- CSSファイルの扱い
- 特定のJSファイルの指定
- グロブパターンの使用
- ベストプラクティス:
{
"sideEffects": [
// すべてのCSSファイル
"**/*.css",
// 特定のJSファイル
"./dist/specific-file.js",
// 特定のディレクトリ内のファイル
"./dist/effects/**/*.js"
]
}
この設定は以下の場合に特に重要です:
- webpack互換性の確保
- バンドルサイズの最適化
- 効率的なツリーシェイキング
- 正確な依存関係の管理
おわりに
今日は、 SvelteKitでのパッケージングについて解説しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント