Communitygithub.com

Blaise1030/astro-marketing

実際のユーザーシグナルに基づくエビデンス主導型のパフォーマンス最適化で、読み込み速度、ランタイム応答性、リソース配信を改善します。サイトの高速化、パフォーマンス最適化、読み込み時間短縮などの依頼に使用します。

astro-marketing とは?

このスキルは、実際のユーザーデータ(フィールドデータ)とブラウザのパフォーマンストレース(ラボデータ)を組み合わせて、ウェブパフォーマンスをエビデンスベースで最適化するための包括的なガイドです。Core Web Vitals(LCP、INP、CLS)の優先順位付けから、画像・フォント・JavaScriptの最適化、キャッシュ戦略、サードパーティスクリプトの管理、View Transitions APIを使ったスムーズな画面遷移まで、実践的なテクニックと具体的なコード例が提供されています。特に、パフォーマンス予算の設定、重要なレンダリングパスの改善、ランタイムパフォーマンスのチューニングに重点を置き、Chrome DevTools MCPなどのツールを使った測定と診断のワークフローが組み込まれています。Astro、Next.js、Nuxtなどのモダンなフレームワークに加え、あらゆるウェブサイトで利用可能です。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Blaise1030/astro-marketing/tree/HEAD/.agents/skills/performance

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

プレビュー

スキル README より

astro-marketing preview
astro-marketing preview
astro-marketing preview
astro-marketing preview

ドキュメント

パフォーマンス最適化

実際のユーザーシグナルに基づくエビデンス主導のパフォーマンス最適化。読み込み速度、ランタイム応答性、リソース配信に焦点を当てます。

動作の仕組み

  1. ページが実行可能な場合は、測定ワークフローを読み、フィールド+ラボのベースラインを確立してから編集を開始します。
  2. 悪化している実際のユーザーのCore Web Vitalsを優先します。DevToolsパフォーマンストレースとその焦点を絞ったインサイトを使用して原因を特定します。
  3. 測定されたボトルネックに関連するコードまたはアセットのみを検査し変更します。
  4. 同等のラボ測定を再実行し、前後の値、条件、不確実性を報告します。フィールド検証は、十分な新しいユーザーデータが到着するまで保留されます。

実行可能なページが存在しない場合は、静的インスペクションを実行しますが、発見事項は仮説と呼び、測定された回帰とは呼びません。各影響度の高い仮説を検証できるコマンドまたはブラウザワークフローを含めてください。

パフォーマンストレースを記録し、焦点を絞ったインサイトを公開するブラウザツールを推奨します。Chrome DevTools MCPでは、performance_start_trace と performance_analyze_insight を使用してください。パフォーマンス以外のLighthouseカテゴリをカバーする lighthouse_audit を経由してパフォーマンスをルーティングしないでください。

初期パフォーマンス予算

予算は、製品のターゲットデバイス、ネットワーク、ページタイプ、ユーザージャーニーを反映する必要があります。以下の値は、典型的なコンテンツページまたはコマースページの初期ガードレールであり、普遍的な合格/不合格基準ではありません。既存のプロジェクト予算が定義されている場合は、それを維持してください。

リソース予算根拠
総ページサイズ< 1.5 MB制約のあるターゲットネットワークでの転送時間とデータコストを制限します。代表的なページで調整してください。
JavaScript (圧縮後)< 300 KB解析と実行コストを保護します。
CSS (圧縮後)< 100 KBレンダリングブロッキング作業を制限します。
画像 (ファーストビュー)< 500 KB可能性のあるLCPリソースを保護します。
フォント< 100 KBクリティカルなフォント転送を制限します。
サードパーティ< 200 KBプロダクトの制御外のコードを制限します。

クリティカルレンダリングパス

サーバーレスポンス

  • TTFB < 800ms。 Time to First Byteは高速であるべきです。CDN、キャッシュ、効率的なバックエンドを使用してください。
  • 圧縮を有効にする。 テキストアセットにはGzipまたはBrotli。Brotli推奨(15-20%小さい)。
  • HTTP/2 または HTTP/3。 多重化により接続オーバーヘッドを削減します。
  • エッジキャッシング。 可能な場合はHTMLをCDNエッジでキャッシュします。
  • 測定されたドキュメントレイテンシにはEarly Hints(HTTP 103)を検討する。 トレースがHTML生成の遅延と安定したクリティカルサブリソースを示している場合は、同じリクエストからの通常の最終レスポンスの前に、Link ヘッダーを含む中間 103 レスポンスを送信します。HTTP/2以降を使用してください。CDNは、以前の 200 レスポンスの Link ヘッダーから 103 を合成するか、オリジン/エッジハンドラーが直接それを送出できます。サポートされていないクライアントは最終レスポンスに進みますが、現在のブラウザとインフラストラクチャのサポートを確認してください。ヒントは、証明されたクリティカルなプリロードまたはプリコネクトに限定してください:不正確なヒントは帯域幅を無駄にします。Cloudflareは、人工的な画像主体のテストで20〜30%のLCP改善を報告しています。これはベンダーのケーススタディとして扱い、期待される改善として扱わず、自身の結果を測定してください。MDNの103実装例とCloudflareの研究を参照してください。

リソース読み込み

必要なオリジンへのプリコネクト:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

クリティカルリソースのプリロード:

トレースで発見が遅れることが確認されたリソースのみをプリロードしてください。各プリロードは帯域幅を競合し、不要な高優先度リクエストはLCPを遅らせる可能性があります。

<!-- LCP画像 -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">

<!-- クリティカルフォント -->
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>

可能性の高い次ナビゲーションをプリレンダリングするには、Speculation Rules APIを使用します:

<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/*" },
    "eagerness": "moderate"
  }]
}
</script>

moderate は、eagerモードよりも強い意図シグナルを待ちます。予測ヒット率、転送バイト数、サーバーコストを測定してください。誤ったプリレンダーは、使用されないナビゲーションとほぼ同じです。トレードオフと分析に必要な prerenderingchange ゲーティングについては、core-web-vitals → LCP を参照してください。

非クリティカルCSSの遅延読み込み:

<!-- クリティカルCSSをインライン化 -->
<style>/* ファーストビューのスタイル */</style>

<!-- 非クリティカルCSS -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>

JavaScript最適化

非必須スクリプトの遅延読み込み:

<!-- パーサーブロッキング (回避) -->
<script src="/critical.js"></script>

<!-- 遅延 (推奨) -->
<script defer src="/app.js"></script>

<!-- 非同期 (独立したスクリプト用) -->
<script async src="/analytics.js"></script>

<!-- モジュール (デフォルトで遅延) -->
<script type="module" src="/app.mjs"></script>

コード分割パターン:

// ルートベースの分割
const Dashboard = lazy(() => import('./Dashboard'));

// コンポーネントベースの分割
const HeavyChart = lazy(() => import('./HeavyChart'));

// 機能ベースの分割
if (user.isPremium) {
  const PremiumFeatures = await import('./PremiumFeatures');
}

ツリーシェイキングのベストプラクティス:

// ❌ ライブラリ全体をインポート
import _ from 'lodash';
_.debounce(fn, 300);

// ✅ 必要なものだけをインポート
import debounce from 'lodash/debounce';
debounce(fn, 300);

画像最適化

フォーマット選択

フォーマットユースケースブラウザサポート
AVIF写真、最高の圧縮率92%以上
WebP写真、優れたフォールバック97%以上
PNG透明度のあるグラフィックユニバーサル
SVGアイコン、ロゴ、イラストユニバーサル

レスポンシブ画像

<picture>
  <!-- モダンブラウザ向けAVIF -->
  <source 
    type="image/avif"
    srcset="hero-400.avif 400w,
            hero-800.avif 800w,
            hero-1200.avif 1200w"
    sizes="(max-width: 600px) 100vw, 50vw">
  
  <!-- WebPフォールバック -->
  <source 
    type="image/webp"
    srcset="hero-400.webp 400w,
            hero-800.webp 800w,
            hero-1200.webp 1200w"
    sizes="(max-width: 600px) 100vw, 50vw">
  
  <!-- JPEGフォールバック -->
  <img 
    src="hero-800.jpg"
    srcset="hero-400.jpg 400w,
            hero-800.jpg 800w,
            hero-1200.jpg 1200w"
    sizes="(max-width: 600px) 100vw, 50vw"
    width="1200" 
    height="600"
    alt="ヒーロー画像"
    loading="lazy"
    decoding="async">
</picture>

LCP画像の優先順位付け

<!-- ファーストビューのLCP画像: eager読み込み、高優先度 -->
<img 
  src="hero.webp" 
  fetchpriority="high"
  loading="eager"
  decoding="sync"
  alt="ヒーロー">

<!-- ファーストビュー以下の画像: 遅延読み込み -->
<img 
  src="product.webp" 
  loading="lazy"
  decoding="async"
  alt="商品">

フォント最適化

読み込み戦略

/* システムフォントスタックをフォールバックとして */
body {
  font-family: 'Custom Font', -apple-system, BlinkMacSystemFont, 
               'Segoe UI', Roboto, sans-serif;
}

/* 不可視テキストの防止 */
@font-face {
  font-family: 'Custom Font';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* または非クリティカルにはoptional */
  font-weight: 400;
  font-style: normal;
  unicode-range: U+0000-00FF; /* ラテン文字にサブセット化 */
}

クリティカルフォントのプリロード

<link rel="preload" href="/fonts/heading.woff2" as="font" type="font/woff2" crossorigin>

バリアブルフォント

/* 複数のウェイトの代わりに1ファイル */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

キャッシュ戦略

Cache-Controlヘッダー

# HTML (短いまたはキャッシュなし)
Cache-Control: no-cache, must-revalidate

# ハッシュ付き静的アセット (不変)
Cache-Control: public, max-age=31536000, immutable

# ハッシュなし静的アセット
Cache-Control: public, max-age=86400, stale-while-revalidate=604800

# APIレスポンス
Cache-Control: private, max-age=0, must-revalidate

サービスワーカーキャッシュ

// 静的アセットはキャッシュファースト
self.addEventListener('fetch', (event) => {
  if (event.request.destination === 'image' ||
      event.request.destination === 'style' ||
      event.request.destination === 'script') {
    event.respondWith(
      caches.match(event.request).then((cached) => {
        return cached || fetch(event.request).then((response) => {
          const clone = response.clone();
          caches.open('static-v1').then((cache) => cache.put(event.request, clone));
          return response;
        });
      })
    );
  }
});

ランタイムパフォーマンス

レイアウトスラッシングの回避

// ❌ 複数のリフローを強制
elements.forEach(el => {
  const height = el.offsetHeight; // 読み取り
  el.style.height = height + 10 + 'px'; // 書き込み
});

// ✅ 読み取りをバッチ処理し、次に書き込みをバッチ処理
const heights = elements.map(el => el.offsetHeight); // すべて読み取り
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + 'px'; // すべて書き込み
});

高コスト操作のデバウンス

function debounce(fn, delay) {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn(...args), delay);
  };
}

// スクロール/リサイズハンドラをデバウンス
window.addEventListener('scroll', debounce(handleScroll, 100));

requestAnimationFrameの使用

// ❌ カクツキの原因になる可能性あり
setInterval(animate, 16);

// ✅ ディスプレイリフレッシュと同期
function animate() {
  // アニメーションロジック
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

長いリストの仮想化

// 100アイテムを超えるリストの場合、表示されているアイテムのみレンダリング
// react-window、vue-virtual-scrollerなどのライブラリ、またはネイティブCSSを使用:
.virtual-list {
  content-visibility: auto;
  contain-intrinsic-size: 0 50px; /* 推定アイテム高さ */
}

View Transitionsによるスムーズなナビゲーション

View Transitions API を使用すると、ブラウザは単一のGPUコンポジットスナップショットを使用して2つのDOM状態間をクロスフェード(またはカスタムアニメーション)できます。ダブルレンダリングやレイアウトスラッシングは発生せず、スナップショットはCLSにカウントされません。

同一ドキュメント (SPAスタイル) — Baseline 2026:

// ビューを切り替えるDOMミューテーションをラップする
function navigate(newView) {
  if (!document.startViewTransition) return swapDOM(newView);
  document.startViewTransition(() => swapDOM(newView));
}

クロスドキュメント (MPAスタイル) — Chromium安定版、他ではプログレッシブエンハンスメント:

/* 送信元と送信先の両方のページで */
@view-transition { navigation: auto; }

これで統合は完了です。同一オリジンのナビゲーションが自動的にフェードするようになります。特定の要素を共有要素トランジション(例:サムネイルがヒーローに拡大する)にオプトインするには、それらに一致するview-transition-nameを指定します:

.product-thumb[data-id="42"], .product-hero { view-transition-name: product-42; }

これをSpeculation Rules(上記)と組み合わせると、インスタントでアニメーション化されたナビゲーションを実現できます。

サードパーティスクリプト

読み込み戦略

// ❌ メインスレッドをブロック
<script src="https://analytics.example.com/script.js"></script>

// ✅ 非同期読み込み
<script async src="https://analytics.example.com/script.js"></script>

// ✅ インタラクションまで遅延
<script>
document.addEventListener('DOMContentLoaded', () => {
  const observer = new IntersectionObserver((entries) => {
    if (entries[0].isIntersecting) {
      const script = document.createElement('script');
      script.src = 'https://widget.example.com/embed.js';
      document.body.appendChild(script);
      observer.disconnect();
    }
  });
  observer.observe(document.querySelector('#widget-container'));
});
</script>

ファサードパターン

<!-- インタラクションまで静的なプレースホルダーを表示 -->
<div class="youtube-facade" 
     data-video-id="abc123" 
     onclick="loadYouTube(this)">
  <img src="/thumbnails/abc123.jpg" alt="ビデオタイトル">
  <button aria-label="ビデオを再生">▶</button>
</div>

測定

URLが実行可能な場合は常に、測定ワークフローを使用してください。これは、Chrome DevTools MCPルーティング、CrUXとフォールバックソース、再現可能なラボ条件、およびコンパクトなエビデンスフォーマットを定義しています。

メトリクス種類解釈
p75でのLCP、INP、CLSフィールドユーザーアウトカムのCore Web Vitals。合格/不合格の優先順位付けに使用します。
トレース内のLCP、CLSラボ1回のナビゲーションにおける再現可能な診断値。
TBTラボメインスレッドブロッキングの診断とINPの大まかなプロキシ。フィールドINPではありません。
FCP、Speed Indexラボ読み込みの診断。Core Web Vitalsではありません。

生のPerformanceObserverスニペットは現在のブラウザセッションには役立ちますが、それ自体は実際のユーザーデータではありません。ユーザーが本番テレメトリを必要とする場合は、ファーストパーティRUMリファレンスを読み、手作りのメトリクス実装よりもweb-vitalsを優先してください。

参考情報

Core Web Vitals固有の最適化については、Core Web Vitalsを参照してください。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

関連スキル