こんにちは!フロントエンドの開発現場で、日々「なんだか最近、ビルドが重くなってきたな……」「初回ロードの速度(LCP)をもっと改善したいのに、巨大なベンダーチャンクが足を引っ張っている……」なんて頭を抱えていませんか?
今回は、Viteの裏側を支えている最強のエンジン「Rollup」の力を極限まで引き出し、バンドル構成を完全に手懐ける方法を一緒に見ていきましょう。
これをマスターすれば、ただコードを書くだけのフロントエンドエンジニアから、「アプリケーションのパフォーマンスを意のままに操るアーキテクト」へと一歩踏み出すことができますよ。毎日のビルド待ち時間や、重い画面に悩まされるストレスから解放される快感を、ぜひ一緒に味わいましょう!
—
そもそもなぜ、Viteの裏側(Rollup)を触る必要があるのか?
Viteは「開発サーバーの立ち上がりが爆速」ことで有名ですよね。これは、ブラウザのネイティブES Modules(ESM)の力を借りて、必要なファイルだけをオンデマンドでコンパイルしているからです。
しかし、「プロダクション向けビルド(本番リリース用)」を作る時の話は別です。Viteは本番ビルドの際、内部でRollup(ロラップ)という強力なモジュールバンドラを呼び出し、数多あるファイルを綺麗にまとめて(バンドルして)出力します。
デフォルトのままでもViteは賢く動いてくれますが、実務で大規模なアプリを作ると、次のような壁にぶつかります。
- 「ReactやLodashのような重いライブラリまで自前バンドルに巻き込まれて、JSファイルが1MBを超えてしまった……」
- 「ちょっとしたバグ修正でコードの1行を変えただけなのに、全ライブラリを含んだ巨大なファイル全体がキャッシュ無効化されてしまう……」
これらを鮮やかに解決するのが、今回解説する「外部化(External)」と「高度なコード分割(manualChunks)」です。
—
1. 開発環境の準備と「HelloWorld」的な現状確認
まずは、今回の実験場となるViteプロジェクトをサクッと立ち上げましょう。まだ手元に環境がない方は、以下のコマンドをターミナルに叩いてみてください。
Viteを使った最新のReact + TypeScript環境を生成します(npmでも可)
npm create vite@latest vite-rollup-lab — –template react-ts
ディレクトリへ移動
cd vite-rollup-lab
依存関係をインストール
npm install
プロジェクトが生成できたら、一度ビルドを走らせてみましょう。
npm run build
実行すると、ターミナルに以下のようなビルド結果(出力ログ)が表示されるはずです。
vite v5.X.X building for production…
transforming…
rendering chunks…
dist/index.html 0.46 kB │ gzip: 0.20 kB
dist/assets/index-B7x3zK2q.js 142.50 kB │ gzip: 45.10 kB
dist/assets/index-C1y9W8p1.css 1.42 kB │ gzip: 0.70 kB
【先輩からのワンポイント解説】
ここが重要なポイントです。デフォルトの状態では、あなたが書いたコードも、node_modulesから読み込んだライブラリも、すべてごちゃ混ぜになって `index-[hash].js` という巨大な単一ファイル(モノリスなチャンク)にコンパイルされています。これが「すべての元凶」です。
—
2. 外部化(External)で巨大ライブラリを切り離す
まずは、重たいライブラリをバンドルから「つまみ出す(外部化する)」テクニックです。
例えば、プロジェクトで `lodash` や `moment`、あるいは巨大なUIライブラリを大量に使っているとします。これらをCDN経由(unpkgやcdnjsなど)でブラウザに直接読み込ませ、自前のバンドルには含めないように設定してみましょう。
`vite.config.ts` を次のように書き換えてみてください。
import { defineConfig } from ‘vite’
import react from ‘@vitejs/plugin-react’
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
// 1. バンドルに含めず、外部(グローバル変数など)として扱うモジュールを指定
external: [‘react’, ‘react-dom’],
// 2. 外部化したモジュールが、ブラウザ上でどのグローバル変数として参照されるかを定義
output: {
globals: {
react: ‘React’,
‘react-dom’: ‘ReactDOM’,
},
},
},
},
})
なぜこの設定が必要なのか?(内部の動き)
`external` に指定されたモジュール名(ここでは `react` と `react-dom`)に遭遇したとき、Rollupは「おっ、こいつは自分でバンドルしなくていいんだな」と判断し、ビルド対象から除外します。
その代わり、生成されたJavaScriptコード内には `import React from ‘react’` の代わりに、グローバル空間にある `window.React` を参照するコードが残ります。そのため、あらかじめHTML側(`index.html`)でCDNからReactを読み込んでおく必要があります。
これにより、自社製コードのバンドルサイズを劇的にダイエットさせることができ、CDN側のブラウザキャッシュを強力に効かせられるようになります。
—
3. output.manualChunks で出力チャンクを自在に支配する
「CDNを使うほどではないけれど、ベンダーコード(node_modules配下のライブラリ)と、自分が書いたビジネスロジックのコードは絶対にファイルを分けたい!」
実務で100%求められるこの要望を叶えるのが、`output.manualChunks` です。
Vite(Rollup)に、「どのファイルをどのファイルにまとめるか」をプログラム的に指示してみましょう。
`vite.config.ts` を次のように高度化させます。
import { defineConfig } from ‘vite’
import react from ‘@vitejs/plugin-react’
export default defineConfig({
plugins: [react()],
build: {
// チャンクサイズが大きくなった際の警告閾値を調整(デフォルトは500kB)
chunkSizeWarningLimit: 600,
rollupOptions: {
output: {
// manualChunksには、モジュールのパスを受け取り、出力先のチャンク名を返す関数を渡します
manualChunks(id) {
// node_modules(外部ライブラリ群)に含まれるファイルの場合
if (id.includes(‘node_modules’)) {
// 例:React関連はまとめて「react-vendor」という独立したファイルにする
if (id.includes(‘react’) || id.includes(‘react-dom’) || id.includes(‘react-router-dom’)) {
return ‘react-vendor’;
}
// 例:その他の細々としたライブラリ(lodashなど)は「libs」としてまとめる
return ‘libs’;
}
// 自作のコンポーネントやページ単位で細かく分けたい場合の拡張もここで可能です
},
},
},
},
})
この設定が生み出す圧倒的な実務メリット
この設定を行って再度 `npm run build` を実行してみてください。出力結果が以下のように美しく分割されているはずです。
dist/assets/react-vendor-A3x9K.js 130.20 kB (React関連はここで固められる)
dist/assets/libs-C8z1L.js 45.50 kB (その他のライブラリ)
dist/assets/index-F4b2M.js 8.20 kB (あなたが書いたピュアなビジネスロジック)
この分割の何が素晴らしいかというと、「ユーザーが日常的にアプリをアップデートしても、変更されるのは `index-[hash].js` だけ」という状況を作れる点です。
重い `react-vendor` や `libs` はユーザーのブラウザに一度キャッシュされれば、次からは全くダウンロードし直す必要がなくなります。結果として、アプリの起動スピードとネットワーク効率が劇的に向上します。
—
まとめ:Rollup Optionsを制する者は、フロントエンドのパフォーマンスを制す
今回は、Viteの裏側であるRollupの設定をいじり、以下の2つの強力な武器を手に入れました。
1. `external` と `globals`:重いライブラリをバンドルから追い出し、CDNや外部キャッシュにオフロードする。
2. `output.manualChunks`:アプリのコードとライブラリ群を意図通りに分割し、キャッシュ効率とロード速度を極限まで最適化する。
フロントエンドのビルドツールは、ただの「コードをまとめる黒い箱」ではありません。中身の仕組みを理解し、自分の手でコントロールできるようになると、開発が何倍も楽しく、エキサイティングになります。
「これをマスターすれば、毎日のコーディングが劇的に楽になりますよ!」
ぜひあなたのプロジェクトでも、今日の知見を試して、ビルド結果の美しさと速度の変化に感動してみてください。それでは、次のアーキテクチャ解説でお会いしましょう!