この記事の概要
Viteにはライブラリモードがあります。
ライブラリを配布するためのバンドル設定はvite.config.js
に記載をします。
その際、フォーマットにあわせてビルドアセットのディレクトリを分けるのに手こずったので記事にしました。
環境
Viteのバージョンは4.2.1です。
やりたかったこと
以下のような構成で配布をしようとしていました。
ES ModulesとCommonJSの両方で配布する、いわゆるdual packageのUIライブラリです。
src
├── components
│ ├── Foo
│ ├── Bar
│ └── Baz
└── index.js
dist
├── cjs
│ ├── index.js
│ └── components
│ ├── Foo
│ │ └── Foo.js
│ ├── Bar
│ │ └── Bar.js
│ └── Baz
│ └── Baz.js
└── es
├── index.mjs
└── components
├── Foo
│ └── Foo.mjs
├── Bar
│ └── Bar.mjs
└── Baz
└── Baz.mjs
完成形
若干省略していますが、最終的なconfigは以下のようになりました。
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
formats: ['es', 'cjs'],
fileName: '[format]/[name]',
},
rollupOptions: {
output: {
preserveModules: true,
exports: 'named',
},
},
},
})
ステップバイステップ
ライブラリモードを使うにあたって、1番簡単な(?)指定は次のようなイメージです。
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
formats: ['es', 'cjs'],
},
},
})
この状態だと、dist/
への出力は次のようになります。
dist
├── package-name.js
└── package-name.mjs
1つのファイルにまとまっているので、コンポーネントごとにファイルを分けたいです。
そのためrollupOptions
を指定します。
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
formats: ['es', 'cjs'],
},
+ rollupOptions: {
+ output: {
+ preserveModules: true,
+ exports: 'named',
+ },
+ },
},
})
dist/
への出力は次のようになります。
dist
├── package-name.js
├── package-name.mjs
├── package-name2.js
├── package-name2.mjs
├── package-name3.js
├── package-name3.mjs
├── package-name4.js
└── package-name4.mjs
ファイル名がただの連番になってしまっているので、ちゃんとコンポーネント名をつけたくなります。
build.lib.fileName
の欄を指定するとファイル名を変えられます。
ただし、単なる文字列を指定しても、結局その文字列+連番で出力されるだけです。
ここで次のような書式で指定すると、目当ての結果が得られます。
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
formats: ['es', 'cjs'],
+ fileName: '[format]/[name]',
},
rollupOptions: {
output: {
preserveModules: true,
exports: 'named',
},
},
},
})
dist
├── cjs
│ ├── index.js
│ └── components
│ ├── Foo
│ │ └── Foo.js
│ ├── Bar
│ │ └── Bar.js
│ └── Baz
│ └── Baz.js
└── es
├── index.mjs
└── components
├── Foo
│ └── Foo.mjs
├── Bar
│ └── Bar.mjs
└── Baz
└── Baz.mjs
指定できる書式は以下の通りです。
-
[format]
- 以下の4つから選べます
'es'
'cjs'
'umd'
'iife'
- 以下の4つから選べます
-
[hash]
- ハッシュ値が付与されます
-
[name]
- ディレクトリ名、ファイル名などがすべて付与されます
これは、Viteの機能というより、Viteが内部で使っているRollupの機能です。
そのためViteのドキュメントには(恐らく)記載がなく、Rollupのドキュメントを見ないと分からないと思います。
ちなみにrollupOption内に記載をしても似たような動きをしますが、うまく実現できませんでした。
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
formats: ['es', 'cjs'],
- fileName: '[format]/[name]',
},
rollupOptions: {
output: {
preserveModules: true,
exports: 'named',
+ entryFileNames: '[format]/[name]',
},
},
},
})
次のように、軒並み拡張子が消えてしまいました。
dist
├── cjs
│ ├── index # 拡張子無し
│ └── components
│ ├── Foo
│ │ └── Foo # 拡張子無し
│ ├── Bar
│ │ └── Bar # 拡張子無し
│ └── Baz
│ └── Baz # 拡張子無し
└── es
├── index # 拡張子無し
└── components
├── Foo
│ └── Foo # 拡張子無し
├── Bar
│ └── Bar # 拡張子無し
└── Baz
└── Baz # 拡張子無し
entryFileNames
の中でformatにあわせて拡張子を変えるのが自分では実現できなかったのもあり、rollupOptions
ではなくlib
の中でfileName
を指定するに至りました。
最後に
過去に書いた記事とかなり近しい内容ですが、今回は今回で悩むポイントが変わりました。
Viteとしての動き、Rollupをラップしているだけの動き、どちらもあるので難しかったです。
探しても意外と出てこない情報だったので記事にしました。
ニッチな自覚はありますが、誰かの役に立場幸いです。
最後まで読んでくださってありがとうございます!
Twitterでも情報を発信しているので、良かったらフォローお願いします!
Devトークでお話してくださる方も募集中です!