mcpField
W
web-performance-optimization

web-performance-optimization

github.com/davila7開発33.0k518 回インストール今日更新
リポジトリ

web-performance-optimization について

開発者向けのウェブ性能最適化スキルです。計測、問題の特定、改善、検証を通じて、読み込み速度や実行時性能、Core Web Vitals の改善を支援します。

主な機能

  1. 01性能の基準値を計測
  2. 02性能ボトルネックの分析
  3. 03アセットと描画経路の最適化
  4. 04キャッシュと遅延読み込みの適用
  5. 05改善結果の検証

活用シーン

  1. 01読み込みが遅いサイトの調査
  2. 02Core Web Vitals の改善
  3. 03JavaScript バンドルの縮小
  4. 04性能監査の準備

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davila7/claude-code-templates --skill web-performance-optimization

インストール後、Claude Code で/web-performance-optimizationを入力して読み込まれたか確認します。

詳細

Web パフォーマンス最適化

概要

開発者がウェブサイトおよびウェブアプリケーションのパフォーマンスを最適化し、ユーザーエクスペリエンス、SEO ランキング、コンバージョン率を向上できるよう支援します。このスキルは、読み込み速度、ランタイムパフォーマンス、Core Web Vitals 指標を計測、分析、改善するための体系的なアプローチを提供します。

このスキルを使用するタイミング

  • ウェブサイトやアプリの読み込みが遅いとき
  • Core Web Vitals (LCP、FID、CLS) を最適化するとき
  • JavaScript バンドルサイズを削減するとき
  • Time to Interactive (TTI) を改善するとき
  • 画像とアセットを最適化するとき
  • キャッシュ戦略を実装するとき
  • パフォーマンスのボトルネックをデバッグするとき
  • パフォーマンス監査に備えるとき

仕組み

ステップ 1: 現在のパフォーマンスを計測する

ベースライン指標の把握をお手伝いします:

  • Lighthouse 監査を実行する
  • Core Web Vitals (LCP、FID、CLS) を計測する
  • バンドルサイズを確認する
  • ネットワークウォーターフォールを分析する
  • パフォーマンスのボトルネックを特定する
ステップ 2: 問題を特定する

パフォーマンスの問題を分析します:

  • 大きな JavaScript バンドル
  • 最適化されていない画像
  • レンダリングをブロックするリソース
  • サーバー応答時間の遅さ
  • キャッシュヘッダーの欠如
  • レイアウトシフト
  • メインスレッドをブロックする長いタスク
ステップ 3: 最適化の優先順位を決める

効果の大きい改善に注力します:

  • クリティカルレンダリングパスの最適化
  • コード分割と遅延読み込み
  • 画像の最適化
  • キャッシュ戦略
  • サードパーティスクリプトの最適化
ステップ 4: 最適化を実装する

パフォーマンス改善を適用します:

  • アセット (画像、フォント、CSS、JS) を最適化する
  • コード分割を実装する
  • キャッシュヘッダーを追加する
  • 重要度の低いリソースを遅延読み込みする
  • クリティカルレンダリングパスを最適化する
ステップ 5: 改善を検証する

変更の効果を計測します:

  • Lighthouse 監査を再実行する
  • 改善前後の指標を比較する
  • リアルユーザー指標 (RUM) を監視する
  • さまざまなデバイスやネットワークでテストする

例

例 1: Core Web Vitals の最適化
## Performance Audit Results

### Current Metrics (Before Optimization)
- **LCP (Largest Contentful Paint):** 4.2s ❌ (should be < 2.5s)
- **FID (First Input Delay):** 180ms ❌ (should be < 100ms)
- **CLS (Cumulative Layout Shift):** 0.25 ❌ (should be < 0.1)
- **Lighthouse Score:** 62/100

### Issues Identified

1. **LCP Issue:** Hero image (2.5MB) loads slowly
2. **FID Issue:** Large JavaScript bundle (850KB) blocks main thread
3. **CLS Issue:** Images without dimensions cause layout shifts

### Optimization Plan

#### Fix LCP (Largest Contentful Paint)

**Problem:** Hero image is 2.5MB and loads slowly

**Solutions:**
\`\`\`html

<img src="/hero.jpg" alt="Hero">


<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img 
    src="/hero.jpg" 
    alt="Hero"
    width="1200" 
    height="600"
    loading="eager"
    fetchpriority="high"
  >
</picture>
\`\`\`

**Additional optimizations:**
- Compress image to < 200KB
- Use CDN for faster delivery
- Preload hero image: `<link rel="preload" as="image" href="/hero.avif">`

#### Fix FID (First Input Delay)

**Problem:** 850KB JavaScript bundle blocks main thread

**Solutions:**

1. **Code Splitting:**
\`\`\`javascript
// Before: Everything in one bundle
import { HeavyComponent } from './HeavyComponent';
import { Analytics } from './analytics';
import { ChatWidget } from './chat';

// After: Lazy load non-critical code
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const ChatWidget = lazy(() => import('./chat'));

// Load analytics after page interactive
if (typeof window !== 'undefined') {
  window.addEventListener('load', () => {
    import('./analytics').then(({ Analytics }) => {
      Analytics.init();
    });
  });
}
\`\`\`

2. **Remove Unused Dependencies:**
\`\`\`bash
# Analyze bundle
npx webpack-bundle-analyzer

# Remove unused packages
npm uninstall moment  # Use date-fns instead (smaller)
npm install date-fns
\`\`\`

3. **Defer Non-Critical Scripts:**
\`\`\`html

<script src="/analytics.js"></script>


<script src="/analytics.js" defer></script>
\`\`\`

#### Fix CLS (Cumulative Layout Shift)

**Problem:** Images without dimensions cause layout shifts

**Solutions:**
\`\`\`html

<img src="/product.jpg" alt="Product">


<img 
  src="/product.jpg" 
  alt="Product"
  width="400" 
  height="300"
  style="aspect-ratio: 4/3;"
>
\`\`\`

**For dynamic content:**
\`\`\`css
/* Reserve space for content that loads later */
.skeleton-loader {
  min-height: 200px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
\`\`\`

### Results After Optimization

- **LCP:** 1.8s ✅ (improved by 57%)
- **FID:** 45ms ✅ (improved by 75%)
- **CLS:** 0.05 ✅ (improved by 80%)
- **Lighthouse Score:** 94/100 ✅
例 2: JavaScript バンドルサイズの削減
## Bundle Size Optimization

### Current State
- **Total Bundle:** 850KB (gzipped: 280KB)
- **Main Bundle:** 650KB
- **Vendor Bundle:** 200KB
- **Load Time (3G):** 8.2s

### Analysis

\`\`\`bash
# Analyze bundle composition
npx webpack-bundle-analyzer dist/stats.json
\`\`\`

**Findings:**
1. Moment.js: 67KB (can replace with date-fns: 12KB)
2. Lodash: 72KB (using entire library, only need 5 functions)
3. Unused code: ~150KB of dead code
4. No code splitting: Everything in one bundle

### Optimization Steps

#### 1. Replace Heavy Dependencies

\`\`\`bash
# Remove moment.js (67KB) → Use date-fns (12KB)
npm uninstall moment
npm install date-fns

# Before
import moment from 'moment';
const formatted = moment(date).format('YYYY-MM-DD');

# After
import { format } from 'date-fns';
const formatted = format(date, 'yyyy-MM-dd');
\`\`\`

**Savings:** 55KB

#### 2. Use Lodash Selectively

\`\`\`javascript
// Before: Import entire library (72KB)
import _ from 'lodash';
const unique = _.uniq(array);

// After: Import only what you need (5KB)
import uniq from 'lodash/uniq';
const unique = uniq(array);

// Or use native methods
const unique = [...new Set(array)];
\`\`\`

**Savings:** 67KB

#### 3. Implement Code Splitting

\`\`\`javascript
// Next.js example
import dynamic from 'next/dynamic';

// Lazy load heavy components
const Chart = dynamic(() => import('./Chart'), {
  loading: () => <div>Loading chart...</div>,
  ssr: false
});

const AdminPanel = dynamic(() => import('./AdminPanel'), {
  loading: () => <div>Loading...</div>
});

// Route-based code splitting (automatic in Next.js)
// pages/admin.js - Only loaded when visiting /admin
// pages/dashboard.js - Only loaded when visiting /dashboard
\`\`\`

#### 4. Remove Dead Code

\`\`\`javascript
// Enable tree shaking in webpack.config.js
module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true,
    sideEffects: false
  }
};

// In package.json
{
  "sideEffects": false
}
\`\`\`

#### 5. Optimize Third-Party Scripts

\`\`\`html

<script src="https://analytics.com/script.js"></script>


<script>
  window.addEventListener('load', () => {
    const script = document.createElement('script');
    script.src = 'https://analytics.com/script.js';
    script.async = true;
    document.body.appendChild(script);
  });
</script>
\`\`\`

### Results

- **Total Bundle:** 380KB ✅ (reduced by 55%)
- **Main Bundle:** 180KB ✅
- **Vendor Bundle:** 80KB ✅
- **Load Time (3G):** 3.1s ✅ (improved by 62%)
例 3: 画像最適化の戦略
## Image Optimization

### Current Issues
- 15 images totaling 12MB
- No modern formats (WebP, AVIF)
- No responsive images
- No lazy loading

### Optimization Strategy

#### 1. Convert to Modern Formats

\`\`\`bash
# Install image optimization tools
npm install sharp

# Conversion script (optimize-images.js)
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');

async function optimizeImage(inputPath, outputDir) {
  const filename = path.basename(inputPath, path.extname(inputPath));
  
  // Generate WebP
  await sharp(inputPath)
    .webp({ quality: 80 })
    .toFile(path.join(outputDir, \`\${filename}.webp\`));
  
  // Generate AVIF (best compression)
  await sharp(inputPath)
    .avif({ quality: 70 })
    .toFile(path.join(outputDir, \`\${filename}.avif\`));
  
  // Generate optimized JPEG fallback
  await sharp(inputPath)
    .jpeg({ quality: 80, progressive: true })
    .toFile(path.join(outputDir, \`\${filename}.jpg\`));
}

// Process all images
const images = fs.readdirSync('./images');
images.forEach(img => {
  optimizeImage(\`./images/\${img}\`, './images/optimized');
});
\`\`\`

#### 2. Implement Responsive Images

\`\`\`html

<picture>
  
  <source 
    srcset="
      /images/hero-400.avif 400w,
      /images/hero-800.avif 800w,
      /images/hero-1200.avif 1200w
    "
    type="image/avif"
    sizes="(max-width: 768px) 100vw, 50vw"
  >
  
  
  <source 
    srcset="
      /images/hero-400.webp 400w,
      /images/hero-800.webp 800w,
      /images/hero-1200.webp 1200w
    "
    type="image/webp"
    sizes="(max-width: 768px) 100vw, 50vw"
  >
  
  
  <img 
    src="/images/hero-800.jpg"
    srcset="
      /images/hero-400.jpg 400w,
      /images/hero-800.jpg 800w,
      /images/hero-1200.jpg 1200w
    "
    sizes="(max-width: 768px) 100vw, 50vw"
    alt="Hero image"
    width="1200"
    height="600"
    loading="lazy"
  >
</picture>
\`\`\`

#### 3. Lazy Loading

\`\`\`html

<img 
  src="/image.jpg" 
  alt="Description"
  loading="lazy"
  width="800"
  height="600"
>


<img 
  src="/hero.jpg" 
  alt="Hero"
  loading="eager"
  fetchpriority="high"
>
\`\`\`

#### 4. Next.js Image Component

\`\`\`javascript
import Image from 'next/image';

// Automatic optimization
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // For above-the-fold images
  quality={80}
/>

// Lazy loaded
<Image
  src="/product.jpg"
  alt="Product"
  width={400}
  height={300}
  loading="lazy"
/>
\`\`\`

### Results

| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| Total Image Size | 12MB | 1.8MB | 85% reduction |
| LCP | 4.5s | 1.6s | 64% faster |
| Page Load (3G) | 18s | 4.2s | 77% faster |

ベストプラクティス

✅ 推奨事項
  • まず計測する - 最適化の前に必ずベースライン指標を確立する
  • Lighthouse を使う - 進捗を追跡するために定期的に監査を実行する
  • 画像を最適化する - 最新のフォーマット (WebP、AVIF) とレスポンシブ画像を使用する
  • コードを分割する - 大きなバンドルを小さなチャンクに分割する
  • 遅延読み込みする - 重要度の低いリソースの読み込みを遅らせる
  • 積極的にキャッシュする - 静的アセットに適切なキャッシュヘッダーを設定する
  • メインスレッドの作業を最小化する - JavaScript の実行を 50ms 以下のチャンクに保つ
  • 重要なリソースをプリロードする - 重要なアセットには <link rel="preload"> を使用する
  • CDN を使用する - 静的アセットを CDN から配信して高速化する
  • 実際のユーザーを監視する - 実ユーザーから Core Web Vitals を収集する
❌ 避けるべきこと
  • やみくもに最適化しない - まず計測し、その後で最適化する
  • モバイルを無視しない - 実際のモバイル端末や低速ネットワークでテストする
  • レンダリングをブロックしない - レンダリングをブロックする CSS と JavaScript を避ける
  • すべてを最初に読み込まない - 重要度の低いリソースは遅延読み込みする
  • 寸法を指定し忘れない - 画像には必ず幅と高さを指定する
  • 同期スクリプトを使用しない - async または defer 属性を使用する
  • サードパーティスクリプトを無視しない - パフォーマンス問題の原因になることが多い
  • 圧縮を省略しない - アセットは必ず圧縮および minify する

よくある落とし穴

問題: デスクトップ向けには最適化されているが、モバイルで遅い

症状: デスクトップでは Lighthouse スコアが良いが、モバイルでは悪い 解決策:

  • 実際のモバイル端末でテストする
  • Chrome DevTools のモバイルスロットリングを使用する
  • 3G/4G ネットワーク向けに最適化する
  • JavaScript の実行時間を短縮する
# Test with throttling
lighthouse https://yoursite.com --throttling.cpuSlowdownMultiplier=4
問題: JavaScript バンドルが大きい

症状: Time to Interactive (TTI) が長い、FID が高い 解決策:

  • webpack-bundle-analyzer でバンドルを分析する
  • 未使用の依存関係を削除する
  • コード分割を実装する
  • 重要度の低いコードを遅延読み込みする
# Analyze bundle
npx webpack-bundle-analyzer dist/stats.json
問題: レイアウトシフトを引き起こす画像

症状: CLS スコアが高い、コンテンツが跳ねる 解決策:

  • 常に幅と高さを指定する
  • aspect-ratio CSS プロパティを使用する
  • スケルトンローダーで領域を確保する
img {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
}
問題: サーバー応答時間が遅い

症状: TTFB (Time to First Byte) が高い 解決策:

  • サーバーサイドキャッシュを実装する
  • 静的アセットに CDN を使用する
  • データベースクエリを最適化する
  • 静的サイト生成 (SSG) を検討する
// Next.js: Static generation
export async function getStaticProps() {
  const data = await fetchData();
  return {
    props: { data },
    revalidate: 60 // Regenerate every 60 seconds
  };
}

パフォーマンスチェックリスト

画像
  • 最新フォーマット (WebP、AVIF) に変換する
  • レスポンシブ画像を実装する
  • 遅延読み込みを追加する
  • サイズ (幅/高さ) を指定する
  • 画像を圧縮する (各 200KB 未満)
  • 配信に CDN を使用する
JavaScript
  • バンドルサイズを 200KB 未満にする (gzip 圧縮後)
  • コード分割を実装する
  • 重要でないコードを遅延読み込みする
  • 未使用の依存関係を削除する
  • 圧縮・ミニファイする
  • スクリプトに async/defer を使用する
CSS
  • クリティカル CSS をインライン化する
  • 重要でない CSS を遅延させる
  • 未使用の CSS を削除する
  • CSS ファイルをミニファイする
  • CSS containment を使用する
キャッシュ
  • 静的アセットにキャッシュヘッダーを設定する
  • Service Worker を実装する
  • CDN キャッシュを使用する
  • API レスポンスをキャッシュする
  • 静的アセットにバージョンを付与する
Core Web Vitals
  • LCP < 2.5 秒
  • FID < 100 ミリ秒
  • CLS < 0.1
  • TTFB < 600 ミリ秒
  • TTI < 3.8 秒

パフォーマンスツール

計測ツール
  • Lighthouse - 包括的なパフォーマンス監査
  • WebPageTest - 詳細なウォーターフォール分析
  • Chrome DevTools - パフォーマンスプロファイリング
  • PageSpeed Insights - 実ユーザーのメトリクス
  • Web Vitals Extension - Core Web Vitals の監視
分析ツール
  • webpack-bundle-analyzer - バンドル構成の可視化
  • source-map-explorer - バンドルサイズの分析
  • Bundlephobia - インストール前にパッケージサイズを確認
  • ImageOptim - 画像圧縮ツール
監視ツール
  • Google Analytics - Core Web Vitals の追跡
  • Sentry - パフォーマンス監視
  • New Relic - アプリケーションパフォーマンス監視
  • Datadog - 実ユーザー監視

関連スキル

  • @react-best-practices - React のパフォーマンスパターン
  • @frontend-dev-guidelines - フロントエンド開発の標準
  • @systematic-debugging - パフォーマンス問題のデバッグ
  • @senior-architect - パフォーマンスのためのアーキテクチャ

追加リソース


Pro Tip: まずは Core Web Vitals (LCP、FID、CLS) に注力しましょう。ユーザー体験と SEO のランキングに最も大きな影響を与えます。

コメント