← 解説「初期表示を軽くする — バンドルサイズが最初の敵」に戻る
サンプルコードで身につける: 初期表示を軽くする — バンドルサイズが最初の敵
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1全ルート即時読み込みを遅延読み込みに直す
初期バンドル削減の定番ビフォーアフターです。全ページを最初に読み込む書き方から、利用頻度の低いページだけをloadComponentに切り替えます。機能は既習なので、ここでは「どのルートを遅延させるか」の選び方に注目してください。
import { Routes } from '@angular/router';
import { Home } from './home';
// ── 遅い書き方: 全ページのコードが初期バンドルに入る ──
// import { AdminPage } from './admin/admin-page';
// import { ReportPage } from './report/report-page';
// export const routes: Routes = [
// { path: '', component: Home },
// { path: 'admin', component: AdminPage },
// { path: 'report', component: ReportPage },
// ];
// ── 速い書き方: たまにしか開かないページは遅延読み込み ──
export const routes: Routes = [
// トップは全員が最初に見るので即時のまま
{ path: '', component: Home },
// 管理画面・帳票は使う人が限られるので切り離す
{
path: 'admin',
loadComponent: () => import('./admin/admin-page').then((m) => m.AdminPage),
},
{
path: 'report',
loadComponent: () => import('./report/report-page').then((m) => m.ReportPage),
},
];
2初期画面内の重い部品を @defer に切り出す
ルート単位では切れない「初期画面の中の重い部品」を@deferで遅らせる例です。ファーストビューの外にあるグラフをon viewportにすると、そのコードは初期バンドルから外れます。ルート遅延と@deferの使い分けの典型例です。
import { Component } from '@angular/core';
import { SalesChartComponent } from './sales-chart.component';
@Component({
selector: 'app-dashboard',
imports: [SalesChartComponent],
// ページ上部の数字はすぐ表示し、スクロールしないと見えない
// グラフ(描画ライブラリ込みで重い)は viewport 到達まで遅らせる
template:
'<h1>今月の売上</h1>' +
'<p>{{ total }}円</p>' +
'@defer (on viewport) {' +
' <app-sales-chart />' +
'} @placeholder {' +
' <div class="chart-skeleton">グラフを準備中...</div>' +
'}',
})
export class DashboardComponent {
total = 1234567;
}
// 効いたかは ng build の Lazy chunk files にグラフ用の
// チャンクが分かれて出ることと、Initial total の減少で確認する
3angular.json の budgets で肥大化を検知する
初期バンドルのサイズ上限を宣言するbudgets設定です。警告ラインとエラーラインの2段構えにしておくと、じわじわ太る変化に警告で気づき、明確な超過はCIで止められます。数値はまず現状より少し厳しい値から始めるのがコツです。
// angular.json(抜粋)。projects.my-app.architect.build.configurations.production
{
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
]
}
}
}
// type: "initial" が初期バンドル全体、
// "anyComponentStyle" は各コンポーネントのCSSサイズの上限
4budgets 超過時のビルド出力と対応
budgetsに引っかかったときにng buildが出すメッセージと、その後の動き方です。エラーで止まったら上限を緩めるのではなく、まず何が増えたのかを調べるのが正しい順番です。上限の変更はチームで合意してから行います。
ng build
# ── 警告ラインを超えたとき(ビルドは成功する) ──
# ▲ [WARNING] bundle initial exceeded maximum budget.
# Budget 500.00 kB was not met by 34.10 kB
# with a total of 534.10 kB.
# ── エラーラインを超えたとき(ビルドが失敗し、CIも落ちる) ──
# ✘ [ERROR] bundle initial exceeded maximum budget.
# Budget 1.00 MB was not met by 120.55 kB
# with a total of 1.12 MB.
# 超過したときの対応順:
# 1. 直近で追加したライブラリ・機能を思い出す
# 2. source-map-explorer で何が増えたかを特定する
# 3. 遅延読み込み・部分 import・代替ライブラリを検討する
# 4. どうしても必要な増加なら、合意の上で budgets を更新する
5遅延させすぎの悪い例 — 分割にもコストがある
何でも遅延にした結果、かえって体験が悪くなる例です。毎回使うページを分割すると、遷移のたびに読み込み待ちが発生します。「初回に必ず通る画面は即時、たまの画面だけ遅延」という判断基準を示す反面教師です。
import { Routes } from '@angular/router';
import { Home } from './home';
import { OrderList } from './order-list';
// ── 悪い例: 毎回使うページまで遅延にしてしまう ──
// export const routes: Routes = [
// { path: '', loadComponent: () => import('./home').then((m) => m.Home) },
// { path: 'orders',
// loadComponent: () => import('./order-list').then((m) => m.OrderList) },
// ];
// => 業務で1日中往復する注文一覧が、開くたびに一瞬待たされる
// ── 良い例: 主要動線は即時、周辺ページだけ遅延 ──
export const routes: Routes = [
{ path: '', component: Home },
{ path: 'orders', component: OrderList }, // 主要動線は即時読み込み
{
path: 'settings', // 設定は開く頻度が低いので遅延
loadComponent: () => import('./settings').then((m) => m.Settings),
},
];
// 判断に迷ったら計測に戻る: Lighthouse の初期表示と
// 実際の遷移の体感、両方を見て決める