viteでパッケージをライブラリに公開する(TypeScript対応)
vite のLibrary Modeを使うことで簡単にパッケージが作ることができます。
本記事では加えて、TypeScript への対応方法も説明していきます。
vite の設定
まずは、vite.config.js から見ていきましょう。
const path = require("path");
const { defineConfig } = require("vite");
module.exports = defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, "lib/main.js"),
name: "MyLib",
fileName: (format) => `my-lib.${format}.js`,
},
},
});
build.lib がライブラリモードのオプションになります。説明すると、
entry
作成するバンドルのエントリーポイントを指定します。
このファイルで公開(export)されている関数や変数が公開されます。
name
<script />
タグを用いてグローバルにインストールした場合に使用される名前になり、window.MyLib
というアクセスが可能になります。(よって、CommonJS や ESM では関係ないです)
fileName
配布ディレクトリ(例:dist)に出力されるファイル名を指定できます。
省略した場合は、package.json の name オプションが使用されます。
出力形式(format)を引数に取る関数を指定すると、フォーマット毎に名前を変えることができます。
format はデフォルトでは es(ESM)と umd(UMD)ですが、rollup のオプションを指定することで、変更することもできます。
React や Vue のパッケージを作る場合
React Hooks 等のパッケージを公開する場合は、追加で設定が必要です。
下記は Vue の例です。
// vite.config.js
const path = require("path");
const { defineConfig } = require("vite");
module.exports = defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, "lib/main.js"),
name: "MyLib",
fileName: (format) => `my-lib.${format}.js`,
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},
});
external はバンドルしてほしくないパッケージを指定します。
そして、globals を指定することで external で指定したパッケージが UMD ビルド時に<script>
タグで読み込まれた際に使用されるべき変数名を設定できます。
ここで指定したパッケージは、peerDependencies として設定すると良いでしょう。
package.json の設定
vite に限った設定ではないのですが、説明します。
package.json の main フィールドに生成したファイルを指定し、パッケージに含める配布フォルダを files フィールドに指定します。
{
...
"files": [
"/dist"
],
"main": "./dist/my-lib.umd.js",
"module": "./dist/my-lib.es.js",
"exports": {
".": {
"import": "./dist/my-lib.es.js",
"require": "./dist/my-lib.umd.js"
},
}
...
}
もし、ブラウザ環境のみをターゲットにしている場合は、main の代わりに browser フィールドを指定します。
{
...
"browser": "dist/my-lib.umd.js"
...
}
ビルドとWatchスクリプトは以下のようにします。
{
"build": "vite build",
"watch": "vite build --watch",
"prepare": "npm run build"
}
prepare
を指定しておくことで、npm publish
前に必ずビルドできます。
公開手順は、以下の記事で正しく解説されているので参照してください。
TypeScript に対応
TypeScript に対応するには、型定義を提供する必要があります。(これも vite に限らない話になります)
パッケージのコードを JS で書いた場合は自分で作成する必要があり、TS で書いた場合は自動生成できます。(自動生成の方法も後で書きます)
まず、作成した型定義を指定する方法を説明します。
TypeScript のドキュメントによると、package.json の types フィールドに型定義を指定することで、利用する側は型定義ファイルを認識できるようになり、更に files フィールドに型定義を格納しているフォルダを指定し、同梱して公開します。
{
...,
"types": "./types/main.d.ts",
"files": [
"/dist",
"/types"
],
...,
}
ビルドスクリプトも以下のように変更します。(vue-tscによる型チェック+型定義生成を追加)
{
"build": "vue-tsc && vite build",
"watch": "concurrently \"vue-tsc --watch\" \"vite build --watch\"",
"prepare": "npm run build"
}
次に、TS のコードから型定義を生成する方法を説明します。
型定義を自動生成するには tsconfig.json を設定する必要があります。
下記に示すように、noEmit オプションを消し、declaration(型宣言)に関わるオプションを追加します。
{
"compilerOptions": {
...,
- "noEmit": true,
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "declarationMap": true,
+ "declarationDir": "./types",
...
},
...
}
ここで、declarationDir に指定したフォルダ(./types)に型定義が格納されます。
emitDeclarationOnly
にする理由は、TSのコンパイル後のJSファイルはviteで出力されるため、型定義のみが必要だからです。
終わりに
vite を使うとパッケージの公開も非常に簡単になることが分かりました。
読んでいただいた方は、是非思いついたアイデアを公開して頂けたらと思います。
簡単に始めたい方は、Github のテンプレートも用意してあるので、ご利用ください。
また、テストの追加方法も載せているので、併せて読んでいただければと思います。
Discussion