frontend-excellence について
frontend-excellenceは、ReactやNext.jsの開発者向けのフロントエンド資料です。レンダリング、読み込み、バンドルサイズ、画像、レイアウトの安定性、性能測定を扱います。
主な機能
- 01React Server ComponentsとストリーミングSSR
- 02コード分割とバンドル最適化
- 03Core Web Vitalsの目標値と調整
- 04画像とフォントの読み込み指針
- 05CLSの防止策
- 06実ユーザーの性能測定
活用シーン
- 01サーバー/クライアントコンポーネント境界の設計
- 02JavaScriptバンドルサイズの削減
- 03画像読み込みとレイアウト安定性の改善
- 04LCP、INP、CLSの監視
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill frontend-excellenceインストール後、Claude Code で/frontend-excellenceを入力して読み込まれたか確認します。
詳細
フロントエンドの卓越性
React Server Components
Server Components はサーバー上で実行され、レンダリング済みの HTML をクライアントに送信します。データベース、ファイルシステム、内部 API に直接アクセスできるため、ブラウザーに公開する必要はありません。
// app/products/page.tsx (Server Component by default)
async function ProductsPage() {
const products = await db.query("SELECT * FROM products WHERE active = true");
return (
<main>
<h1>Products</h1>
<ProductList products={products} />
<AddToCartButton /> {/* Client Component */}
</main>
);
}
ルール:
- Server Components では
useState、useEffect、ブラウザー API を使用できません - インタラクティブなコンポーネントは、ファイルの先頭に
'use client'を指定します - Server Components から Client Components には、シリアライズ可能な props を渡します(関数やクラスは不可)
'use client'の境界は、ツリー内のできるだけ深い位置に置きます
ストリーミング SSR
import { Suspense } from 'react';
export default function Dashboard() {
return (
<div>
<Header /> {/* renders immediately */}
<Suspense fallback={<ChartSkeleton />}>
<AnalyticsChart /> {/* streams when ready */}
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<RecentOrders /> {/* streams independently */}
</Suspense>
</div>
);
}
各 Suspense 境界は個別にストリーミングされます。ページ全体がブロックされないよう、データを取得するコンポーネントの周囲に境界を配置します。
コード分割
import dynamic from 'next/dynamic';
const HeavyEditor = dynamic(() => import('@/components/Editor'), {
loading: () => <EditorSkeleton />,
ssr: false,
});
const AdminPanel = dynamic(() => import('@/components/AdminPanel'));
次の単位で分割します。
- ルートの境界(Next.js App Router では自動)
- 条件付きでレンダリングされるコンポーネント(モーダル、ドロワー、管理パネル)
- 重いライブラリ(チャートライブラリ、リッチテキストエディター、地図)
- ファーストビュー以降のコンテンツ
バンドルの最適化
// next.config.js
module.exports = {
experimental: {
optimizePackageImports: ['lucide-react', '@heroicons/react', 'lodash-es'],
},
};
チェックリスト:
npx next buildを実行し、ルートごとの出力サイズを確認します@next/bundle-analyzerを使って、大きな依存関係を特定しますmomentをdate-fnsまたはdayjsに置き換えます(約200KB削減)- 必要な関数だけをインポートします:
import { debounce } from 'lodash-es/debounce' - アニメーションには JS より CSS を優先します(実行時コストなし)
- アイコンライブラリをツリーシェイクします:
import { Search } from 'lucide-react'
Core Web Vitals の目標値
| 指標 | 良好 | 要改善 | 不良 |
|---|---|---|---|
| LCP(Largest Contentful Paint) | <2.5s | 2.5-4.0s | >4.0s |
| INP(Interaction to Next Paint) | <200ms | 200-500ms | >500ms |
| CLS(Cumulative Layout Shift) | <0.1 | 0.1-0.25 | >0.25 |
LCP の最適化
- ヒーロー画像をプリロードします:
<link rel="preload" as="image" href="..." /> - ファーストビューに表示される
<Image>コンポーネントにはpriorityprop を使用します - クリティカル CSS をインライン化し、重要でないスタイルシートの読み込みを遅らせます
- ファーストビューのコンテンツには、クライアントサイドレンダリングを避けます
- レイアウトシフトを防ぐため、画像に明示的な
width/heightを設定します
画像の最適化
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Descriptive alt text"
width={1200}
height={630}
priority // preload for LCP images
sizes="(max-width: 768px) 100vw, 50vw"
placeholder="blur"
blurDataURL={base64} // inline tiny placeholder
/>
next/imageまたは同等の機能を使用します(WebP/AVIF とレスポンシブな srcset を自動生成)- サイズが大きすぎる画像のダウンロードを避けるため、
sizes属性を設定します - 体感パフォーマンスを高めるため、base64 データ URL と
placeholder="blur"を使用します - ファーストビュー以降の画像を遅延読み込みします(デフォルトの動作)
フォント読み込みの戦略
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // show fallback font immediately
preload: true,
variable: '--font-inter',
});
export default function RootLayout({ children }) {
return (
<html className={inter.variable}>
<body>{children}</body>
</html>
);
}
next/fontを使用すると、自動サブセット化により CLS を発生させずにフォントを読み込めます- 読み込み中にテキストが非表示になるのを避けるため、
display: 'swap'を設定します - Google CDN から読み込む代わりにフォントをセルフホストします(DNS ルックアップを削減)
- フォントファミリーは最大2種類に制限します
CLS の防止
- 画像と動画には必ず
widthとheightを設定します - レスポンシブなメディアコンテナーには CSS の
aspect-ratioを使用します min-heightを使って、動的コンテンツ(広告、埋め込み)のためのスペースを確保します- 読み込み後に既存コンテンツの上へコンテンツを挿入しないようにします
- サイズが変化するコンポーネントには CSS の
contain: layoutを使用します
パフォーマンスのモニタリング
import { onCLS, onINP, onLCP } from 'web-vitals';
onCLS(console.log);
onINP(console.log);
onLCP(console.log);
ラボスコアだけでなく、実際のユーザー指標(RUM)を測定します。Vercel Analytics と Google Search Console では、フィールドデータを確認できます。
コメント
Markdown 対応