最適化と注意点
ネットワーク最適化のチェックリスト。HTTP/2/3、圧縮、CDN、画像、Resource Hints、Early Hints、CSP まで。
パフォーマンスの主軸
- 遅延(latency)を減らす — 物理的に近い CDN、HTTP/3、0-RTT
- 転送量を減らす — 圧縮、画像最適化、不要 JS を削る
- 並列化する — HTTP/2 多重化、preload、prefetch
- キャッシュする — ブラウザ・CDN・SW
HTTP/2 / HTTP/3 を使う
- HTTP/2: 多重化で1接続で並列リクエスト。ドメインシャーディング不要
- HTTP/3 (QUIC): UDP ベースで TCP の HoL ブロッキング解消、0-RTT
- 主要 CDN(Cloudflare / Fastly / AWS CloudFront)は対応済み
- サーバー側で有効化されているか確認:
curl -I --http2 url/--http3
圧縮
- Brotli (br) が最強。HTML / JS / CSS で gzip より 15〜25% 小さい
- gzip はフォールバック
- zstd が CDN で対応進む(さらに速い)
- 画像・動画は圧縮しない(既に圧縮済み)
多くの CDN / Cloudflare Pages / Vercel は自動で Brotli。
画像最適化
- AVIF: 最強の圧縮率(一部古い iOS で未対応)
- WebP: 広い対応
- JPEG/PNG: フォールバック
<picture>+<source type="image/avif">で順次フォールバックloading="lazy"で遅延読み込みdecoding="async"でデコードを非同期fetchpriority="high"で重要な画像を先取得
<picture>
<source type="image/avif" srcset="hero.avif" />
<source type="image/webp" srcset="hero.webp" />
<img src="hero.jpg" alt="..." loading="lazy" decoding="async" />
</picture>
レスポンシブ画像
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="..."
/>
Resource Hints
ブラウザに「これ後で要るよ」と教える hint タグ。
<link rel="dns-prefetch">— DNS だけ事前解決<link rel="preconnect">— DNS + TCP + TLS まで<link rel="prefetch">— 次のページのリソース(低優先)<link rel="preload">— 現在のページの重要リソース(高優先)<link rel="modulepreload">— ES Module 用
<link rel="preconnect" href="https://api.example.com" />
<link rel="preload" href="/fonts/Inter.woff2" as="font" type="font/woff2" crossorigin />
<link rel="prefetch" href="/next-page.html" />
Early Hints (103)
サーバーが本レスポンスより先に 103 Early Hints を返して、preconnect / preload を伝える。
TTFB 待ち中に並列ロード開始できる。Cloudflare / Fastly が対応。
HTTP/2 Server Push(廃止)
以前推奨された Server Push は非推奨・廃止傾向。Early Hints が後継。
Critical CSS
ファーストビューに必要な CSS だけHTML にインライン、残りは非同期。
<style>/* critical CSS */</style>
<link rel="preload" href="/all.css" as="style" onload="this.rel='stylesheet'" />
Web Font 最適化
- WOFF2 一択(圧縮率最高)
font-display: swapでテキストが先に出る- サブセット化(必要文字のみ)で激減
preconnect+preloadで取得を早める
CDN の活用
- 静的アセットは必ず CDN 配信
- 動的 HTML も CDN でキャッシュ可能(SWR / 短期 max-age)
- 画像変換 CDN(Cloudflare Images / Imgix / Cloudinary)でフォーマット自動選択
- 地理的に分散されたエッジで低遅延
Compression Streams API
ブラウザでもgzip / deflate / deflate-rawの圧縮・展開ができる:
// 圧縮
const compressed = await new Response(
new Blob([data]).stream().pipeThrough(new CompressionStream("gzip"))
).blob()
// 展開
const decompressed = await new Response(
blob.stream().pipeThrough(new DecompressionStream("gzip"))
).text()
セキュリティヘッダー
- Strict-Transport-Security — HTTPS 強制
- Content-Security-Policy — XSS 対策
- X-Content-Type-Options: nosniff — MIME 推測禁止
- X-Frame-Options: DENY or frame-ancestors — クリックジャック対策
- Referrer-Policy — Referer 制御
- Permissions-Policy — 機能の許可制御
- Cross-Origin-Opener-Policy / -Embedder-Policy / -Resource-Policy — Spectre 対策
Hono / Fastify / Express の secure-headers ミドルウェア
全部一気にセットしてくれる。securityheaders.com でスコア確認。
Rate Limiting
- 同一 IP / トークン から一定時間に N リクエストまで
- 429 Too Many Requests +
Retry-After - Cloudflare Rate Limiting / nginx の
limit_req/ 自前実装 - API キー別にバジェット管理
計測
- Core Web Vitals: LCP / INP / CLS
- Lighthouse: ローカル測定
- WebPageTest: 詳細ウォーターフォール
- Chrome DevTools の Performance: フィルム ストリップ・Long Task
- Real User Monitoring (RUM): Sentry / Datadog / SpeedCurve
- Server-Timing: バックエンド側時間を共有
web-vitals ライブラリ
npm install web-vitals
import { onLCP, onINP, onCLS } from "web-vitals"
onLCP(console.log)
onINP(console.log)
onCLS(console.log)
失敗のリトライとサーキットブレーカー
- ネットワーク失敗 / 5xx は指数バックオフでリトライ
- 4xx はリトライしない(クライアント側の問題)
- 連続失敗が続いたらサーキットブレーカーで一時停止
- ユーザー UX を損なわない範囲で(無限スピナーNG)
大容量転送のコツ
- Range リクエストでレジューム可能に
- 分割アップロード(multipart)
- tus.io(resumable upload プロトコル)
- S3 multipart upload
- ストリーミング送信(fetch + ReadableStream)
よくある落とし穴
- 非圧縮で配信 — gzip / br を有効化
- 画像が無圧縮 — AVIF / WebP / 最適化
- HTTPS なのに混在コンテンツ — 全部 HTTPS に
- キャッシュが効いてない — Cache-Control 確認
- バンドルが大きい — code splitting / tree shaking
- 3rd-party スクリプトで詰まる — async / defer / 自前ホスト化
- 巨大な JSON を一気返し — ページング / ストリーミング
- Web Font が大きい — サブセット / WOFF2
判断ガイド
| 症状 | 対策 |
|---|---|
| 初回が遅い | Critical CSS / preload / Early Hints / CDN |
| 毎回サーバが重い | キャッシュ / SWR / CDN |
| 画像が遅い | AVIF / lazy-loading / レスポンシブ画像 |
| API が遅い | 並列化 / キャッシュ / streaming |
| ファイル送信が不安定 | resumable upload / tus.io |
| モバイルで遅い | 転送量を絞る / HTTP/3 |
参考