Viteの本番バンドルファイルを可視化する

# はじめに
みなさん、バンドルファイルのコード分割行っていますでしょうか。各UIフレームワークが提供もしくは推奨しているコンポーネントの遅延読み込みだったり、バンドラーの設定でチャンク戦略を取って分割を行っている方が多いと思います。
コードの分割を行うと分割したファイルの様子を知りたかったり、不自然に肥大化したファイルの原因を辿ったりするなど分割されたファイルの様子を知りたいケースがいくつか出てきます。
この記事ではViteの環境において分割されたバンドルファイルがどのように分布されているかを可視化するライブラリーを紹介します。
Reactを想定したサンプルコードを使用しますが、Viteを用いるVueなどの他のライブラリでも同様に動きます。
![collage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/f2641c49-809d-6c06-7de9-ea3ba1d9d0b0.png)


# rollup-plugin-visualizer
Viteはesbuildを利用しているというイメージが強いですがesbuildは開発環境でしか用いられておらず、本番ではRollupを用いたバンドルを行っています。Rollupにはファイルの分布を可視化するライブラリがあります。[rollup-plugin-visualizer](https://github.com/btd/rollup-plugin-visualizer)です。先述の通りViteのビルドはRollupを利用することからViteでもこれを利用できます。
## 導入
ライブラリをインストールします(npmを使いましたが、yarnでもpnpmでも可能です)。
```sh
npm install --save-dev rollup-plugin-visualizer
```
インストール後はvite.config.tsにimportしてpluginsを追加するだけで利用できます。
```ts:vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { visualizer } from 'rollup-plugin-visualizer';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), visualizer()]
})
```
設定後`npm run build`でビルドと同時にstats.htmlを生成してくれます。そのファイルをブラウザで開くと下のように表示されます。
![スクリーンショット 2022-12-01 11.21.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/85a35f5f-341e-99a4-466d-65771b94fe25.png)
実行したプロジェクトは`npm create vite@latest`で作成したばかりのプロジェクトなので一つのindex.jsにまとまった状態になっています。ブラウザの表示からindex.jsの中に色々なライブラリが入っていてreact-domが多くの割合を占めていることがわかります。領域の大きさがそのライブラリやファイルが占めているファイルの容量そのものを表しています。
## コード分離
viteの提供するチャンク戦略(splitVendorChunkPlugin)を利用してコード分離を行った場合の出力を見てみます。この戦略はコードとライブラリをindexとvenderに分割するような戦略です。
```ts:vite.config.ts
import { defineConfig, splitVendorChunkPlugin } from 'vite'
import react from '@vitejs/plugin-react'
import { visualizer } from 'rollup-plugin-visualizer';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), visualizer(), splitVendorChunkPlugin()],
})
```
![スクリーンショット 2022-12-01 15.27.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/2832d9ca-7e18-edc5-eb4f-3e4c4b5498a7.png)
小さくて見にくいですが、色によってindexとvenderで分割されています。赤がindex、青がvenderです。コード分割を行なっている成熟されたアプリケーションではもっと綺麗な表示を見ることができると思います(はじめにの画像のような)。


## 設定
rollup-plugin-visualizerにはさまざまな設定があります。それぞれ`visualizer`の引数にオブジェクトとして渡すことで設定が可能です。
### filename
出力するファイル名を設定します。後述のtemplateに沿った拡張子にする必要があります。
デフォルトは`stat.html`です(templateがdefaultの時の拡張子)。
```ts
visualizer({ filename: 'filename.html' })
```
### title
出力されるファイルのタイトルを設定します。デフォルトは`Rollup Visualizer`です。
```ts
visualizer({ title: 'タイトル' })
```
### open
ファイルが作成されたときにデフォルトブラウザで自動で開いてくれる設定をします。デフォルトは`false`です。
```ts
visualizer({ open: true })
```
### template
どのような種類のテンプレートで出力するか設定します。デフォルトは`treemap`です。`sunburst`, `treemap`, `network`, `raw-data`, `list`を設定することができます。`treemap`はデフォルトの表示で、`raw-data`は`stat.json`に生データを、`list`は`stats.yml`にデータを出力します。`sunburst`の出力は中央(root)から沿って依存しているパッケージ、ファイルを追って確認することができます。
![スクリーンショット 2022-12-01 16.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/e13c06fe-ca39-f0dd-3b28-787e5c93fc90.png)
`network`はライブラリやファイルの大きさに対応した円があって、それらが依存関係に合わせて繋がっているものが出力されます。
![スクリーンショット 2022-12-01 16.28.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/aef7f031-2f65-f9f9-3ff0-48f56833fd25.png)

```ts
visualizer({ open: true })
```
### gzipSize
レンダリングされたファイルの他にgzipファイルを元にした出力に切り替えできるようにします。デフォルトはfalseです。
ブラウザの左上に出力されたラジオボタンで切り替えできます。
![スクリーンショット 2022-12-01 15.49.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/1d37b625-7eb9-5bf1-2265-d1032a510104.png)

```ts
visualizer({ gzipSize: true })
```
### brotliSize
ブラウザの左上に出力されたラジオボタンで切り替えできます。
レンダリングされたファイルの他にbrotliファイルを元にした出力に切り替えできるようにします。デフォルトはfalseです。
![スクリーンショット 2022-12-01 15.48.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/da4833bf-0496-782c-3f03-5754c46ca88f.png)

```ts
visualizer({ brotliSize: true })
```
### emitFile
emitFileを利用した出力に設定します。デフォルトはfalseです。

```ts
visualizer({ emitFile: true })
```
### sourcemap
ソースマップを利用してサイズを計算する設定をします。デフォルトはfalseです。オプションの最後に設定する必要があります。ソースマップがなければ警告が出るので注意してください(出力がうまくいきません)。
```ts
visualizer({ sourcemap: true })
```
### projectRoot
ルートパスを絶対パスで設定します。デフォルトは`process.cwd()`です。
```ts
visualizer({ projectRoot: '' })
```

# さいごに
この記事ではViteでバンドルファイルの可視化する方法を紹介しました。ファイルの分離が適切に行われているか、巨大になっているファイルのボトルネックの特定と分離であったりに役立つので是非ご利用ください。