佐藤CTOからの指令:「ECサイトのLighthouseスコアが45点まで落ちている。Core Web Vitals を改善し、90点以上を達成してほしい。」
| # | ミッション | 難易度 | 目安時間 |
|---|---|---|---|
| 1 | Core Web Vitals の診断 | ★★☆ | 15分 |
| 2 | バンドル最適化 | ★★★ | 15分 |
| 3 | 画像・フォント最適化 | ★★☆ | 15分 |
| 4 | レンダリング戦略の設計 | ★★★ | 15分 |
Mission 1: Core Web Vitals の診断
以下のLighthouse結果を分析し、改善の優先順位を付けよ。
Performance Score: 45
LCP: 6.2s (Poor) - Hero画像(2.4MB JPEG)
INP: 450ms (Poor) - 商品フィルタの再レンダリング
CLS: 0.35 (Poor) - Web Font読み込み時のシフト、画像サイズ未指定
FCP: 3.1s - レンダリングブロックCSS(800KB)
TBT: 1200ms - メインスレッドで重いJS処理
バンドル構成:
main.js: 1.2MB (gzip 380KB) - lodash全体, moment.js含む
vendor.js: 2.1MB (gzip 650KB) - UI library全体
styles.css: 450KB - Tailwind未使用クラス大量
解答例
■ 優先順位(インパクト × 実装容易性)
1. [LCP] Hero画像の最適化 (インパクト: 大, 容易性: 高)
- JPEG → WebP/AVIF変換で70%圧縮(2.4MB → 200KB)
- srcset でレスポンシブ対応
- preload + fetchpriority="high"
- 期待改善: LCP 6.2s → 2.0s
2. [TBT/INP] バンドルサイズ削減 (インパクト: 大, 容易性: 中)
- lodash → lodash-es(Tree Shaking)
- moment.js → dayjs(280KB → 6KB)
- UI libraryをTree Shaking対応版に変更
- 期待改善: main.js 380KB → 120KB
3. [CLS] レイアウトシフト修正 (インパクト: 中, 容易性: 高)
- 全img/video にwidth/height属性追加
- font-display: swap + size-adjust設定
- 期待改善: CLS 0.35 → 0.05
4. [FCP] CSS最適化 (インパクト: 中, 容易性: 中)
- Tailwind CSS Purge有効化(450KB → 15KB)
- Critical CSS インライン化
- 期待改善: FCP 3.1s → 1.2s
5. [INP] フィルタ再レンダリング最適化 (インパクト: 中, 容易性: 中)
- React.memo + useMemoで再レンダリング抑制
- 商品リスト仮想化(react-window)
- フィルタ処理をWeb Workerに移動
- 期待改善: INP 450ms → 150ms
Mission 2: バンドル最適化
以下のバンドル構成を分析し、最適化計画を策定せよ。
// 現在のインポート構成
import _ from 'lodash';
import moment from 'moment';
import 'moment/locale/ja';
import { Chart } from 'chart.js';
import * as Icons from '@heroicons/react/24/outline';
import { DataGrid } from '@mui/x-data-grid';
解答例
// 最適化後
import { debounce, get, groupBy } from 'lodash-es'; // 個別インポート
import dayjs from 'dayjs'; // moment → dayjs
import 'dayjs/locale/ja';
dayjs.locale('ja');
// Chart.js: 必要なコンポーネントだけ登録
import { Chart, LineController, LineElement, PointElement,
LinearScale, CategoryScale, Tooltip } from 'chart.js';
Chart.register(LineController, LineElement, PointElement,
LinearScale, CategoryScale, Tooltip);
// Icons: 個別インポート
import { ShoppingCartIcon, HeartIcon } from '@heroicons/react/24/outline';
// DataGrid: 動的インポート(管理画面でのみ使用)
const DataGrid = lazy(() => import('@mui/x-data-grid').then(m => ({ default: m.DataGrid })));
// 結果:
// main.js: 380KB → 95KB (gzip) - 75%削減
// vendor.js: 650KB → 180KB (gzip) - 72%削減
Mission 3: 画像・フォント最適化
以下のECサイトの画像構成を最適化せよ。
現在の構成:
- Hero画像: 2400x1200px JPEG, 2.4MB
- 商品サムネイル: 800x800px PNG, 平均500KB × 20枚
- カテゴリアイコン: 64x64px PNG × 12個
- カスタムフォント: NotoSansJP-Regular.ttf (16MB)
解答例
<!-- Hero画像 -->
<picture>
<source srcset="/hero-1200.avif 1200w, /hero-800.avif 800w" type="image/avif" />
<source srcset="/hero-1200.webp 1200w, /hero-800.webp 800w" type="image/webp" />
<img src="/hero-800.jpg" alt="Hero"
sizes="100vw" width="2400" height="1200"
fetchpriority="high" decoding="async" />
</picture>
<!-- 2.4MB → 約150KB (AVIF) -->
<!-- 商品サムネイル: 画像CDN + lazy loading -->
<img src="https://cdn.example.com/products/123?w=400&f=webp&q=80"
srcset="...?w=400 400w, ...?w=800 800w"
sizes="(max-width: 640px) 50vw, 25vw"
loading="lazy" decoding="async" width="400" height="400" alt="Product" />
<!-- 500KB → 約30KB/枚 -->
<!-- アイコン: SVGスプライトに統合 -->
<!-- 12個のPNG (合計100KB) → 1つのSVGスプライト (8KB) -->
<!-- フォント: woff2 + サブセット化 -->
<!-- ttf 16MB → woff2サブセット 約300KB -->
<link rel="preload" href="/fonts/NotoSansJP-subset.woff2"
as="font" type="font/woff2" crossorigin />
<!-- 総削減: 12.4MB → 約0.9MB (93%削減) -->
Mission 4: レンダリング戦略の設計
以下のECサイトの各ページに最適なレンダリング戦略を選択し、根拠を説明せよ。
ページ一覧:
1. トップページ(プロモバナー、人気商品、カテゴリ一覧)
2. 商品一覧ページ(フィルタ、ソート、ページネーション)
3. 商品詳細ページ(商品情報、レビュー、関連商品)
4. カート・チェックアウト(ユーザー固有、決済)
5. マイページ(注文履歴、お気に入り)
6. 特集ページ(セール、季節コンテンツ)
解答例
| ページ | 戦略 | 根拠 |
|---|---|---|
| トップ | ISR (60秒) | プロモは頻繁に変わるが秒単位の鮮度は不要。高トラフィックなのでキャッシュ効果大 |
| 商品一覧 | SSR + クライアントフィルタ | フィルタ/ソートはクライアントで動的処理。初期一覧はSSRでSEO対応 |
| 商品詳細 | ISR (300秒) | SEO重要。在庫・価格は部分的にクライアントで最新取得 |
| カート | CSR | ユーザー固有データ。SEO不要。リアルタイム更新が必要 |
| マイページ | CSR | ユーザー認証必須。SEO不要。動的データ |
| 特集ページ | SSG | 事前に用意可能な静的コンテンツ。ビルド時に生成 |
Hydration戦略:
- トップ/商品詳細: Progressive Hydration
→ Hero/商品情報は即Hydrate、レビュー/関連商品は遅延
- 商品一覧: フィルタUIのみ即Hydrate、商品カードは静的
- カート: Full Hydration(全体がインタラクティブ)