LoginSignup
12
6

More than 1 year has passed since last update.

Viteのライブラリモードでビルドする際、フォーマットごとにディレクトリを分ける

Last updated at Posted at 2023-04-12

この記事の概要

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は以下のようになりました。

vite.config.js
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番簡単な(?)指定は次のようなイメージです。

vite.config.js
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を指定します。

vite.config.js
  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の欄を指定するとファイル名を変えられます。
ただし、単なる文字列を指定しても、結局その文字列+連番で出力されるだけです。

ここで次のような書式で指定すると、目当ての結果が得られます。

vite.config.js
  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'
  • [hash]
    • ハッシュ値が付与されます
  • [name]
    • ディレクトリ名、ファイル名などがすべて付与されます

これは、Viteの機能というより、Viteが内部で使っているRollupの機能です。
そのためViteのドキュメントには(恐らく)記載がなく、Rollupのドキュメントを見ないと分からないと思います。

ちなみにrollupOption内に記載をしても似たような動きをしますが、うまく実現できませんでした。

vite.config.js
  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トークでお話してくださる方も募集中です!

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6