vercel-react-best-practices (vercel-labs/agent-skills)
Vercel の React と Next.js の性能ガイドラインを、コンポーネント、データ取得、バンドルに適用します。
Vercel's React ベストプラクティス:Next.js の最適化を 2.3 から 3.6/5 に引き上げますが、一文版は 75% のトークンで 4.6 に到達します。
Codex CLI · gpt-6-astra
24.3 / 30
スキルなしに対するリフト:+0.85 · 状況次第 · 18 実行
状況次第:リフト +0.85 が +1.0 未満。推奨には合計 22/30、出力品質 3.5、リフト +1.0 が必要です。
SOTA
合格Codex でテスト済み。
カバー対象 Codex, Claude Code
Codex CLI 0.166(SOTA ティア):採点対象 18 実行。当ティアのルールでは、ここでの合格は Claude Code もカバーします。第2ティアについては何も述べません。
スコア
各ディメンションは 0〜5 点で、6 つの合計が 30 点満点の合計スコアになります。すべてのディメンションで 5 が最良です。コスト 5 は低コストで高速、インストール 5 は簡単であることを意味します。
- トリガーの信頼性
- 5.0
- スキルなしに対するリフト
- 2.9
- 出力品質
- 4.4
- トークンと時間のコスト
- 3.0
- インストールと移植性
- 4.0
- 安全性
- 5.0
セキュリティレビュー
安全静的スキャン:CRITICAL 6 / HIGH 0 / MEDIUM 0。手動レビュー:ネットワーク無効のサンドボックスで実行しても安全(スキャナの指摘は確認済み)。クリーンなスキャン結果はスキルの安全性を証明しません。
インストール
npx skills@latest add vercel-labs/agent-skills --skill react-best-practices
固定コミット: 1a2c79d4e6c4a2283dc2c614b6538cbe1ed5ca62
テスト済み: 2026-11-02
テスト内容
- ダッシュボードのパフォーマンスレビュー — OrdersDashboard.tsx と page.tsx(Next.js 15 アプリ)のパフォーマンス問題をレビューしてください。最も深刻なものから順に、それぞれファイルと変更内容を添えて列挙してください。ファイルは変更しないでください。最終回答にリストを書いてください。
- ダッシュボードコンポーネントをその場で最適化 — OrdersDashboard.tsx をパフォーマンスのために最適化してください。ファイルをその場で編集し、振る舞いとコンポーネントの props は同じままにしてください。(ネットワークも npm install もありません。実行しようとしないでください。)
- ダッシュボードのサーバーページを作成 — app/dashboard/page.tsx(Next.js 15 のサーバーコンポーネント、App Router)を作成してください。ログイン済みユーザー('@/lib/auth' の getSession() が { userId } を返す)のために、'@/lib/data' から getProfile(userId)、getRecentOrders(userId)、getRecommendations(userId) が必要です…
長所
- スキルなしと比べ平均スコアを 3.57 から 4.43 に引き上げ(+0.85)。
- スキルは名前を出さずとも採用されました:スキルあり群 6/6 実行でスキルファイルが読み込まれました。
短所
- 一文プロンプトは 4.73、スキルありは 4.43(-0.30)。
- スキルなしの 1.53 倍のトークンを消費。
- タスク・群ごとに n=2。1 ポイント未満の差はノイズです。
レビュー
Mac テストマシン上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません(以下で注記する表現を除く)。小規模な Next.js 15 フィクスチャに対する 3 つのタスク:ダッシュボードのコンポーネントとページのパフォーマンスレビュー(仕込まれた問題点 11 件、最も深刻なものから列挙)、コンポーネントをその場で最適化(チェック 10 項目:Promise.all、バレルではなく直接インポート、lodash 全体のインポートなし、重いエディタには next/dynamic、Row をコンポーネント外へホイスト、effect 内の setFiltered ではなく派生リスト、orders.length && を使わない、遅延 state 初期化子、Map ルックアップ、パッシブスクロールリスナー)、低速 1 件と高速 2 件のデータ呼び出しに対応するサーバーページの作成。
3群の比較
| 群 | 平均スコア(0〜5) | 1実行あたりのトークン |
|---|---|---|
| スキルなし | 3.57 | 67k |
| 一文プロンプト | 4.73 | 77k |
| スキルあり | 4.43 | 103k |
Codex CLI で 18 実行を計測し、LLM 判定なしのルールベースのチェックで採点。合計 24.3 / 30、判定は 状況次第。
判定:状況次第(24.3 / 30)。 出典:vercel-labs/agent-skills、skills/react-best-practices、コミット 1a2c79d に固定。インストール:npx skills@latest add vercel-labs/agent-skills --skill react-best-practices。ライセンス: MIT(リポジトリの LICENSE)。
概要
vercel-labs/agent-skills の vercel-react-best-practices スキル(ディレクトリは react-best-practices):影響度でグループ化された 70 の Markdown ルールファイル(リクエストウォーターフォール、バンドルサイズ、サーバーサイド性能、クライアントのデータ取得、再レンダリング、レンダリング、JS 性能、高度なパターン)と、コンパイル済みの AGENTS.md。SKILL.md はインデックスで、エージェントは必要なルールを読み込みます。スクリプトなし。
テスト方法
Mac テストマシン上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません(以下で注記する表現を除く)。
小さな Next.js 15 フィクスチャでの 3 タスク:ダッシュボードコンポーネントとページのパフォーマンスレビュー(11 の仕込み問題、重大な順に列挙)。コンポーネントのその場での最適化(10 チェック:Promise.all、バレルではなく直接インポート、lodash 全体のインポートをしない、重いエディターに next/dynamic、Row をコンポーネント外へホイスト、effect 内の setFiltered ではなく派生リスト、orders.length && を使わない、遅延状態初期化子、Map ルックアップ、パッシブスクロールリスナー)。遅いデータ呼び出し 1 つと速い 2 つのためのサーバーページの作成。
- ダッシュボードのパフォーマンスレビュー — OrdersDashboard.tsx と page.tsx(Next.js 15 アプリ)のパフォーマンス問題をレビュー。重大な順に、それぞれファイルと変更内容を添えて列挙。ファイルは変更しないでください。リストは最終回答に書いてください。
- ダッシュボードコンポーネントをその場で最適化 — OrdersDashboard.tsx をパフォーマンスのために最適化。ファイルをその場で編集し、振る舞いとコンポーネントの props は同じに保つ。(ネットワークも npm install もありません。実行は試みないでください。)
- ダッシュボードのサーバーページを書く — app/dashboard/page.tsx、Next.js 15 のサーバーコンポーネント(App Router)を書く。ログイン中のユーザー('@/lib/auth' の
getSession()が{ userId }を返す)には、'@/lib/data' のgetProfile(userId)、getRecentOrders(userId)、getRecommendations(userId)が必要で…
採点はプログラム的(隠しテスト/仕込み問題の検出/制約チェック/該当する場合はレンダリング+OCR)で、実行ごとに 0〜5 点。スコアはどの LLM 判定者も決めていません。
結果
第 3 群に与えた一文プロンプト:"この順序で React/Next.js のパフォーマンスを修正する:リクエストウォーターフォールを排除し(独立したフェッチを Promise.all で同時に開始し、遅い部分は Suspense でストリーミング)、バンドルサイズを削減し(バレルファイル経由ではなく直接インポート、重いコンポーネントを next/dynamic でコード分割)、不要な再レンダリングを避ける(レンダリング中に値を導出、コンポーネント内でコンポーネントを定義しない、静的値をホイスト、遅延状態初期化子・Map ルックアップ・パッシブスクロールリスナーを使う)。"
| タスク | 対照群スコア | 一文プロンプト | スキルあり | 対照群トークン | 一文プロンプトトークン | スキルありトークン | スキル読み込み |
|---|---|---|---|---|---|---|---|
| t1-review | 3.91 | 4.64 | 4.64 | 65k | 45k | 75k | 2/2 |
| t2-optimize | 2.27 | 4.55 | 3.64 | 90k | 130k | 163k | 2/2 |
| t3-write | 4.54 | 5.0 | 5.0 | 45k | 53k | 69k | 2/2 |
平均スコア:スキルなし 3.57 vs スキルあり 4.43(差分 +0.85)。1 実行あたりのトークン:67k vs 103k(1.53 倍)。時間:47s vs 52s。一文プロンプト群:4.73(一文プロンプトに対するスキルの上乗せ:-0.3。一文プロンプト自身のスキルなしに対する上乗せ:+1.15)。一文プロンプトのトークンは 1 実行あたり 77k、つまりスキルのコストは一文プロンプトの 1.34 倍。
何が起きたか
- その場での最適化で差が現れました:対照群 2.27、スキルあり 3.64、一文版 4.55(各群の 2 実行は同一)。対照群とスキルはともにバレルインポート
from '@/components'を残し、コード分割も行いませんでした。対照群はさらに、逐次 await と非パッシブのスクロールリスナーも残しました。スキルはウォーターフォールとスクロールリスナーは修正しましたが、バレルインポートと重いエディターの動的インポートは修正せず、まさにそのルールを名指しする一文プロンプトは両方を修正しました。 - レビュータスク:検出した仕込み問題は対照群 9、7(平均 8)、スキルと一文プロンプトはともに 10、10(それぞれ 11 のうち 10。0 を描画する
orders.length &&はどの群のどの実行も見落とし)。スコアは対照群 3.91、スキルあり 4.64、一文プロンプト 4.64。 - 作成タスク:全群が遅いレコメンデーションを Suspense の後ろに置き、ページをサーバーコンポーネントのままにしました。対照群はときどき 3 つの呼び出しを順番に await しました(スコア 4.1 と 5.0。スキルは両方 5.0、一文プロンプトも両方 5.0)。
- ファイル編集時に
orders.length &&を修正した群はなく、スキルにあるルール(rendering-conditional-render)はどの編集にも反映されませんでした。 - スキルは 6/6 実行で読み込まれ、103k トークン(対照群 67k、1.5 倍。一文プロンプト 77k、1.3 倍)。全体平均は対照群 3.57、スキルあり 4.43、一文プロンプト 4.73。
- 分析中に採点を 1 度修正しました:最初のパスでは、ファイルが app/dashboard/page.tsx に書かれ、Map が型付けされていた(
new Map<string, string>())ため、ページと Map のチェックを誤って失点と判定していました。両方の正規表現を修正し、18 実行すべてを再チェックしました。
評価項目別スコア
| 評価項目 | スコア | 理由 |
|---|---|---|
| 出力品質 | 4.43 | スキルありの平均スコアは 4.43/5(プログラム的チェック。タスク別の表を参照)。 |
| スキルなしに対するリフト | 2.85 | スキルなしの 3.57 に対して +0.85 ポイント(タスクごとに n=2。約 1 ポイント未満の差はノイズ)。 |
| トリガー | 5.0 | スキルあり群 6/6 実行でスキルファイルが読み込まれました。 |
| 手順の移植性 | 4 | React/Next.js 固有。他のエージェントが読み込めるプレーンな Markdown。オープンスキルのレイアウトに従う。 |
| 効率 | 3 | トークン 1.53 倍(1 実行あたり 103k vs 67k)、時間 1.10 倍(52s vs 47s)。 |
| 安全性と衛生 | 5 | Markdown のルールファイルのみ。スキャナのヒット 6 件は
|
このテストの限界
- 既知の教科書的な問題を持つ小さなフィクスチャ。最適化したコンポーネントは 1 つだけなので、群ごとの 2 実行は同じ理由で同じ結果を示します(2 実行は同一)。
- スキルの 70 ルールは 3 タスクでしか試されていません。サーバーキャッシュ、SWR、イベントリスナー、高度なルールは仕込んでいません。
- 一文版はテストがチェックするのと同じルールを列挙するため、短いプロンプトの上限であり、ルールを知らないユーザーの公平な代替ではありません。
- タスク・群ごとに n=2。約 1 ポイント未満の差はノイズです。
- ルールベースの採点はチェックが捉えられる範囲を測るもので、センスや、その結果が最善かどうかは判定できません。
セキュリティ
security.md を参照。スキャン:CRITICAL 6 / HIGH 0 / MEDIUM 0。判定:実行しても安全(ネットワーク無効のサンドボックス)。クリーンなスキャン結果はスキルの安全性を証明しません。
結論
このスキルは、何もしない場合に比べてパフォーマンスレビューとその場での最適化を明確に改善します。それが目的です。同じルールを名指しする短いプロンプトは最適化タスクでより良く、コストも低かったため、価値の大半はルール名を知っていることにあります。スキルのルールファイルは、ユーザーがルール名を知らなくて済むようにしますが、今回の実行ではバレルインポートとコード分割のルールには届きませんでした。
トランスクリプト
実行ログ:vercel-react-best-practices (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.) 列:タスク、群-回、スコア(0-5)、トークン、秒、合格したチェック、エージェントが開いたスキルファイル。 t1-review control-1: スコア 4.27, トークン 65319, 秒 49.8, チェック 2/2, 開いたファイルなし t1-review control-2: スコア 3.55, トークン 65797, 秒 42.7, チェック 2/2, 開いたファイルなし t1-review oneliner-1: スコア 4.64, トークン 45347, 秒 43.5, チェック 2/2, 開いたファイルなし t1-review oneliner-2: スコア 4.64, トークン 45242, 秒 52.5, チェック 2/2, 開いたファイルなし t1-review treatment-1: スコア 4.64, トークン 75664, 秒 52.7, チェック 2/2, 開いたファイル react-best-practices t1-review treatment-2: スコア 4.64, トークン 75106, 秒 52.1, チェック 2/2, 開いたファイル react-best-practices t2-optimize control-1: スコア 2.27, トークン 81770, 秒 63.5, チェック 5/10, 開いたファイルなし t2-optimize control-2: スコア 2.27, トークン 99616, 秒 48.7, チェック 5/10, 開いたファイルなし t2-optimize oneliner-1: スコア 4.55, トークン 141803, 秒 75.2, チェック 9/10, 開いたファイルなし
18 実行、3 成果物
サンプル出力
SOTA · With the skill: final message (t1-review, run 1, Codex)
Ranked by likely impact; no files changed. 1. **`OrdersDashboard.tsx:16` — Storage access breaks server rendering and repeats on every render.** `localStorage` is unavailable during Next.js prerendering; `'use client'` doesn’t prevent that. Initialize settings with a stable default, then read and safely parse storage once after mounting. A lazy initializer alone won’t fix server access. [Next.js rendering guidance](https://nextjs.org/docs/app/getting-started/server-and-client-components) 2. **`page.tsx:8–11` — Independent server requests run sequentially.** After `getUser`, start settings, invoices, and notifications together using `Promise.all()`. Their latency currently adds up unnecessarily. 3. **`OrdersDashboard.tsx:19–28` — Initial data waits for hydration, then follows a request waterfall.** Fetch initial data in a server parent where practical. Otherwise, after fetching `me`, request orders and customers concurrently with `Promise.all()`. Neither depends on the other. 4. **`OrdersDashboard.tsx:45–47` — Every dashboard render remounts every row.** Defining `Row` inside the component creates a new component type each render, including during scrolling and typing. Move it to module scope; consider `React.memo` with stable props. 5. **`OrdersDashboard.tsx:17,34–38,55` — Scrolling rerenders the entire dashboard.** Each scroll update repeats filtering, sorting, joins, and rendering. Move scroll state into a small standalone indicator component; throttle updates if exact continuous tracking isn’t necessary. 6. **`OrdersDashboard.tsx:7,54` — The markdown preview is eagerly loaded even for an empty footer.** Use `next/dynamic` for the preview and render it only when footer content exists. Defer mounting until needed if it is below the fold. 7. **`OrdersDashboard.tsx:40–43` — Repeated expensive calculations and quadratic customer lookups.** Memoize derived results, build a customer-ID `Map` when customers change, and parse dates once before sorting instead of inside every comparison. The join then costs O(orders + customers), rather than O(orders × customers). 8. **`OrdersDashboard.tsx:15,30–32` — Derived state causes an extra render per search/data change.** Remove `filtered` state and its effect; derive it with `useMemo`. For large datasets, use `useDeferredValue(query)` with memoized results to keep typing responsive. 9. **`page.tsx:9–15` — All sections wait for the slowest request.** Start requests together, then await them inside separate async sections under `Suspense`. This allows the sidebar to appear without waiting for feed data; wrapping JSX after all awaits won’t help. 10. **`OrdersDashboard.tsx:53` — Every matching row is mounted.** For large order collections, paginate or virtualize the table. Prefer server pagination/filtering when fetching the entire collection also becomes expensive. 11. **`OrdersDashboard.tsx:3–6` — Import cleanup and a potential barrel-import cost.** Remove unused lodash, icons, `Modal`, and `isAfter`; import used local components directly rather than through `@/components`. Confirm bundle impact before claiming unused imports ship to clients. Named `date-fns` and `lucide-react` imports already rece [... excerpt: first 3200 of 3335 characters]