こんにちは!日々のフロントエンド開発、お疲れ様です。
「アプリケーションが大規模化するにつれて、`npm run dev` を叩いてからローカルサーバーが立ち上がるまでにコーヒーを1杯飲めるくらいの時間がかかるようになった……」
そんな絶望感を味わったことはありませんか?
モジュール数が数千、数万を超えてくると、Webpackのような強力なバンドラであっても、起動時の全ファイル走査とメモリ消費に苦しみます。
今回は、その悪夢を鮮やかに断ち切るWebpack 5の隠し玉、「Lazy Compilation(遅延コンパイル)」の世界へあなたをご案内します。これをマスターすれば、巨大なプロジェクトであっても、起動は一瞬、メモリはクリーンに保たれ、毎日のコーディングが劇的に快適になりますよ。
—
1. なぜ「Lazy Compilation」が必要なのか?(ツールの本質と背景)
これまでのWebpack(および多くのバンドラ)のデフォルトの挙動は、「全モジュール一括事前ビルド(Eager Compilation)」でした。
開発サーバーを起動した瞬間、Webpackはエントリーポイントから依存関係をすべて辿り、使われるかどうかもわからない何千ものコンポーネントやページを必死に解析し、メモリ上にバンドル生成を試みます。
これが「起動の遅さ」と「メモリリーク感」の正体です。
Lazy Compilationがもたらすパラダイムシフト
Lazy Compilationは、この常識を根本から覆します。
思想は非常にシンプルです。「今、ブラウザが表示しようとしている(アクセスされた)ページやコンポーネントだけを、その瞬間にコンパイル(オンデマンドビルド)する」。
- 起動時: 最初に必要な最小限のコードだけをビルドするため、起動時間はほぼ「一瞬」になります。
- 開発時: ユーザーが特定のルーティング(例: `/settings`)にアクセスした瞬間、Webpackがそれを検知し、裏側で動的にそのモジュール群をコンパイルしてブラウザに送り届けます。
つまり、開発体験(DX)において「使っていないコードのためにCPUとメモリを浪費させない」という、極めて合理的かつモダンなアプローチなのです。
—
2. 最小構成で体感する!Lazy Compilationの基礎セットアップ
百聞は一見に如かず。実際に手を動かして、その圧倒的なスピードと動作の仕組みを体験してみましょう。
ここでは、Webpack 5がすでにインストールされている環境を前提に、最小限の設定ファイル(`webpack.config.js`)を組み上げていきます。
プロジェクト構成案
my-lazy-app/
├── src/
│ ├── index.js # ホーム画面(常に必要)
│ └── heavy.js # 重たい遅延ロード用モジュール
├── package.json
└── webpack.config.js
ステップ1: `webpack.config.js` の記述と詳細解説
Webpack 5の `experiments` プロジェクトとして実験的(現在は安定版でも広く使えますが)に導入された `lazyCompilation` を有効にします。
const path = require(‘path’);
module.exports = {
// 開発モードを指定
mode: ‘development’,
// エントリーポイント(アプリの起点)
entry: ‘./src/index.js’,
output: {
filename: ‘bundle.js’,
path: path.resolve(__dirname, ‘dist’),
},
// ★ここが今回の核心:Lazy Compilationの設定
experiments: {
lazyCompilation: {
// 動的インポート(import())されたモジュールを遅延コンパイルの対象にする
imports: true,
// エントリーポイント自体も遅延させたい場合は backend設定を行う(高度な設定のため今回はimportsを中心に解説)
backend: {
// 開発サーバーと連携してオンデマンドビルドを制御するサーバー設定(デフォルトのままでOK)
client: {
logging: ‘info’,
},
},
},
},
devServer: {
static: ‘./dist’,
port: 8080,
// 開発サーバーのホットリロードを有効化
hot: true,
},
};
【プロのワンポイント解説】
`experiments.lazyCompilation.imports: true` と設定するだけで、コード内の `import()`(Dynamic Import)で読み込まれるモジュールが、「実際にそのコードが実行されるまでビルドされない」状態に切り替わります。
—
3. HelloWorld検証:動的インポートで挙動を確認する
それでは、実際に遅延コンパイルがどのように動作するのか、コードを書いて検証してみましょう。
`src/index.js` (エントリーポイント)
ボタンをクリックした瞬間に初めて重たいモジュールを呼び出す(Dynamic Import)コードを書きます。
// src/index.js
console.log(‘アプリケーションが起動しました!’);
// 画面にボタンを作成
const button = document.createElement(‘button’);
button.innerText = ‘重たい機能を読み込む’;
document.body.appendChild(button);
button.addEventListener(‘click’, async () => {
console.log(‘重たいモジュールのロードを要求します…’);
// ★ここで動的インポートを使用。この瞬間に初めてWebpackがビルドを走らせます!
const heavyModule = await import(‘./heavy.js’);
// 読み込んだモジュールの関数を実行
heavyModule.run();
});
`src/heavy.js` (遅延対象のモジュール)
// src/heavy.js
export function run() {
console.log(‘【成功】重たいモジュールが遅延コンパイルされ、実行されました!’);
const div = document.createElement(‘div’);
div.innerText = ‘遅延ロード成功!’;
document.body.appendChild(div);
}
—
4. いざ実行!コンソールログから「遅延」の正体を目撃する
それでは、開発サーバーを立ち上げて挙動を確認しましょう。
npx webpack serve
実行結果のリアルな挙動
1. サーバー起動時:
コンソールには `index.js` に関連する最小限のバンドル完了ログしか流れません。`heavy.js` は一切ビルドされていません。この時点でメモリ消費量は最小限に抑えられています。
2. ブラウザアクセス&ボタンクリック前:
ブラウザで `http://localhost:8080` を開いても、コンソールには「アプリケーションが起動しました!」としか表示されません。
3. ボタンをクリックした瞬間!
ブラウザのボタンを押したその瞬間、ネットワークタブやWebpackのサーバーログに注目してください。
- Webpackが裏側で `heavy.js` のリクエストを検知します。
- コンソールに一瞬 `[lazy compilation] Compiling ‘src/heavy.js’` のようなビルドログ走ります。
- コンパイルが完了した瞬間にコードがブラウザに送られ、`【成功】重たいモジュールが遅延コンパイルされ、実行されました!` がコンソールに出現します。
この「使われる寸前に、必要な分だけコンパイルする」という仕組みこそが、巨大なWebアプリのビルド時間を劇的に短縮する正体です。
—
5. 実務で導入する際の注意点とアーキテクトからの助言
「これは素晴らしい!明日から全プロジェクトで導入しよう!」と意気込むあなたへ、現場のチーフエンジニアとしていくつか実務的なアドバイスを贈ります。
- サーバーサイドレンダリング(SSR)との相性:
Next.jsなどのSSRフレームワークでは、独自のルーティングやビルドパイプラインを持っているため、素のWebpackのLazy Compilationをそのまま噛み合わせるのは少しコツがいります(※Next.jsなどは自前で同様のオンデマンド最適化を持っています)。SPA(Single Page Application)や、自社製の巨大なWebpack構成を持つ管理画面などで最大の効果を発揮します。
- 初回のロード体感:
開発時、ユーザー(開発者)が初めて重いページを開いた瞬間に「コンパイル待ち」が発生するため、数秒(プロジェクトの規模によっては1〜2秒)待たされることがあります。しかし、「最初に全体を待たされる苦痛」に比べれば、「必要な時だけ一瞬待つ」方が圧倒的に開発ストレスが少ないことを、すぐに実感できるはずです。
まとめ
今回は、Webpack 5の隠れた名機能「Lazy Compilation」について、その哲学から具体的な実装、動作検証までを解説しました。
- 全件ビルドの呪縛から解放され、起動時間が劇的に速くなる
- 開発時のメモリ消費量を大幅に削減できる
- `experiments.lazyCompilation: { imports: true }` を書くだけで簡単に導入できる
毎日のコーディングで「ビルド待ち」にイライラする時間はもう終わりです。ぜひ次のプロジェクトのWebpack設定に組み込んで、快適な開発ライフを手に入れてください!