こんにちは。よっしーです(^^)
今日は、SvelteKitでのパッケージングについて解説しています。
背景
SvelteKitでのパッケージングについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。
TypeScript
TypeScriptを自身で使用していない場合でも、ライブラリの型定義をリリースすべきです。これにより、TypeScriptユーザーがあなたのライブラリを使用する際に適切なインテリセンスを得ることができます。@sveltejs/package
を使用すると、型生成のプロセスはほぼ自動化されます。デフォルトでは、ライブラリのパッケージング時に、JavaScript、TypeScript、Svelteファイルの型定義が自動生成されます。必要なのは、exportsマップの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の
typesVersions
機能を(悪用して)型を接続する方法。これはpackage.json
内のフィールドで、TypeScriptバージョンに応じて異なる型定義をチェックするために使用されます。
解説
この記事は、以下の重要なポイントを説明しています:
- 型定義の重要性
- TypeScriptを使用していなくても、ライブラリの型定義を提供することが重要
- ユーザーのための良好な開発体験(インテリセンス)を確保できる
- @sveltejs/packageの利点
- 型生成を自動化
- JavaScript、TypeScript、Svelteファイルの型定義を自動生成
- サブパス型定義の課題
- ルートエクスポート以外の型定義には追加の設定が必要
- TypeScriptのデフォルト動作では正しく解決されない問題がある
- 解決方法
- moduleResolutionの設定変更(推奨方法)
- typesVersionsを使用した代替方法
このドキュメントは、特にライブラリ開発者向けに、TypeScriptの型定義システムの複雑さと、その適切な実装方法を説明しています。
コード例
{
"exports": {
"./foo": {
"types": "./dist/foo.d.ts",
"svelte": "./dist/foo.js"
}
},
"typesVersions": {
">4.0": {
"foo": ["./dist/foo.d.ts"]
}
}
}
>4.0
は、使用されているTypeScriptのバージョンが4より大きい場合に内部マップをチェックするようTypeScriptに指示します(これは実際にはほぼ常に真となります)。内部マップは、your-library/foo
の型定義が./dist/foo.d.ts
内にあることをTypeScriptに伝えており、これは本質的にexports
条件の内容を複製しています。また、*
をワイルドカードとして使用することで、コードを繰り返すことなく多くの型定義を一度に利用可能にすることができます。注意点として、typesVersions
を使用する場合は、ルートインポート("index.d.ts": [..]
として定義される)を含むすべての型インポートをこれを通して宣言する必要があります。
コード解説
- package.jsonの構造
exports
フィールド:- モジュールのエントリーポイントを定義
"./foo"
:サブパスエクスポートの定義"types"
:TypeScript用の型定義ファイルの場所"svelte"
:Svelte用のJavaScriptファイルの場所
- typesVersionsの役割
- TypeScriptのバージョンに応じた型定義の場所を指定
">4.0"
:TypeScript 4.0以降のバージョンで適用- 内部マップでは、各インポートパスに対する型定義ファイルの場所を指定
- マッピングの仕組み
"foo": ["./dist/foo.d.ts"]
は以下を意味します:your-library/foo
としてインポートされた際に- 型定義を
./dist/foo.d.ts
から読み込む
- ワイルドカード機能
*
を使用することで、複数のファイルに対する型定義を一括で指定可能- 例:
"*": ["./dist/*"]
とすることで、すべてのサブパスに対する型定義を指定可能
- 重要な注意点
typesVersions
を使用する場合:- すべての型インポートをここで宣言する必要がある
- ルートインポートの型定義も含める必要がある
- 例:
"index.d.ts": ["./dist/index.d.ts"]
の形で指定
このような設定は、特に以下のような場合に重要です:
- サブパスエクスポートを持つライブラリを作成する場合
- 異なるTypeScriptバージョンに対応する必要がある場合
- 標準的な場所以外に型定義ファイルを配置する場合
この設定により、ライブラリの利用者は適切な型情報を得ることができ、より良い開発体験を提供することができます。
おわりに
今日は、 SvelteKitでのパッケージングについて解説しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント