mcpField
F
frontend-best-practices

frontend-best-practices

github.com/o-marsters-1997開発052 回インストール2 日前に更新
リポジトリ

frontend-best-practices について

frontend-best-practicesは、フロントエンド開発とコードレビュー向けに、フレームワーク共通のUI原則をまとめたスキルです。まずプロジェクトのフレームワークを判定し、対応するリファレンスを必要に応じて読み込むことで、別のフレームワークの手法を誤用しないようにします。

主な機能

  1. 01フレームワーク判定と対応リファレンスの選択
  2. 02コンポーネント設計と状態管理の指針
  3. 03非同期データ・フォーム・アクセシビリティの確認
  4. 04パフォーマンスとTypeScriptの実践
  5. 05動作重視のテストとプロジェクト構成

活用シーン

  1. 01フロントエンドUIの構築やリファクタリング
  2. 02フロントエンドの変更内容をレビュー
  3. 03リアクティブなロジックの問題を調査
  4. 04アクセシビリティ・性能・型安全性を確認

インストール

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

$npx skills add https://github.com/o-marsters-1997/my-claude-code --skill frontend-best-practices

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
evals.json
evals/fixtures/
package.react.json
package.solid.json
TodoList.tsx
UserCard.tsx
UserDashboard.tsx
useToggleSearch.tsx
references/
react.md
solidjs.md
references/solidjs/
async.md
solid-2.md
stores.md

詳細

フロントエンド

正しく、アクセシブルで、高速かつ型安全な UI を構築するためのベストプラクティスです。以下の原則はフレームワークに依存しません。React、SolidJS、その他の何を使う場合にも当てはまります。フレームワーク固有の「方法」は、必要に応じて読み込むリファレンスに記載されています。フロントエンドのバグの最大の原因は、あるフレームワークの考え方を別のフレームワークに当てはめてしまうことだからです。

フレームワークの選択 — 最初に行う

共通の原則は、何を目指すべきかを示します。リアクティブなコードの書き方はフレームワークによって大きく異なり、間違えると「UI が更新されない」「再レンダリングが多すぎる」といったバグの最も一般的な原因になるため、原則だけでは説明しません。リアクティブなロジックを書く前、またはレビューする前に、フレームワークを判定し、該当するリファレンスを1つだけ読み込んでください。

次の順序で判定し、最初に該当したものを採用します。

  1. ユーザーによる明示的な説明。 ユーザーがフレームワーク(「これは Solid のプロジェクトです」など)を指定した場合は、それに従います。
  2. package.json の依存関係 — 最も強い判断材料です。モノレポの場合は、ルートの package.json ではなく、編集対象のファイルに最も近い package.json を読みます。
    • react / react-dom(または next) → references/react.md を読み込みます
    • solid-js / @solidjs/*(例:@solidjs/router、@solidjs/start) → references/solidjs.md を読み込みます
    • tsconfig.json の "jsxImportSource" で確認できます。"solid-js" または "@solidjs/web" は Solid を意味します。
  3. 作業対象ファイルの拡張子とインポート。 import … from "react" または useState などのフック呼び出しがある .tsx / .jsx → React。import { createSignal } from "solid-js"、または <For> / <Show> を使った JSX → SolidJS。(注:どちらも .tsx を使うため、拡張子だけでは判断できません。インポートを確認してください。)
# Quick check:
grep -E '"(react|react-dom|next|solid-js|@solidjs/[^"]+|solid-start)"' package.json
grep -E '"jsxImportSource"' tsconfig*.json

該当するリファレンスだけを読み込みます。両方を読み込まないでください。まだリファレンスがないフレームワーク(Vue、Svelte)は共通の原則だけを使い、質問はしません。React と Solid の判断材料が本当に矛盾する場合、または判断材料が何もない場合(空のリポジトリに新規ファイルを作成する場合など)は、ユーザーに一度だけ確認してから作業を進めます。

hx-* 属性で制御されるサーバーサイドレンダリングのテンプレートは、コンポーネントフレームワークではありません。Go の html/template アプリでは、連携する TypeScript モジュールも含め、代わりに htmx-go-templates スキルを使います。

これが重要な理由(根本的な違い): React はレンダリングのたびにコンポーネント関数全体を再実行し、不要な処理や再レンダリングを防ぐために依存配列とメモ化に頼ります。SolidJS は各コンポーネント関数を一度だけ実行し、細粒度のシグナルを使って変更された DOM ノードだけを更新します。最適化すべき再レンダリングはありません。この違いひとつで、メモ化、エフェクト、派生状態、リストのレンダリング、プロパティに関する指針は大きく変わります。リファレンスでは各共通トピックを、それぞれのフレームワーク独自のモデルに沿って説明しています。以下の原則から推測せず、リファレンスを確認してください。

後からフレームワークを追加するには、見出しの分類を合わせた新しい references/<framework>.md を追加し、上記の判定ルールに1つ追加します。共通部分に変更を加える必要はありません。


共通の原則

これらはフレームワークに依存しません。それぞれの原則に対応する同名・同順の見出しがすべてのリファレンスにあり、そこにフレームワーク固有の仕組みが記載されています。

1. コンポーネントのアーキテクチャと合成

継承や、真偽値のプロパティによる設定よりも、合成を優先します。isModal、isCompact、variant のようなフラグが増えていくコンポーネントは、たいてい2つか3つのコンポーネントがトレンチコートを着ているようなものです。分割しましょう。柔軟な合成が必要な場合は、増え続けるプロパティの組み合わせを避けるため、複合コンポーネント(関連する子コンポーネントを調整する親コンポーネント)、レンダープロパティ / スロット、as スタイルの多態的なコンポーネントを活用します。

各コンポーネントには単一の責務を持たせ、実装方法ではなく、受け入れるものを示す、明確で完全に型付けされたプロパティ API を用意します。プロパティのバケツリレーは避けましょう。使わない値を複数の階層を通じて渡すのは問題の兆候です。状態を持ち上げるか、コンテキストを介して共有するか、利用側がデータの出所に近くなるよう構成を変えます。目安として、読み手がプロパティだけでコンポーネントの契約を理解できるようにしてください。

2. 状態とデータフロー

サーバー状態(API から取得したデータ。別の場所に正規のデータソースがあり、古くなるため、キャッシュと再検証が必要です)と、クライアント/ローカル状態(開閉状態、選択中のタブ、入力途中のフォームなど、クライアントが管理する UI 上の状態)を区別してください。取得したサーバーデータを場当たり的なローカル状態に保存し、手動で同期するのは避けてください。そうすると、UI が古くなったり、一貫性を失ったりします。サーバー状態には、サーバー状態/クエリレイヤーを使用してください。

状態は、それを使うコンポーネントの近くに置き、必要とする最も近い共通の祖先までに限って引き上げてください。それ以上上げる必要はありません。コンテキストは、テーマ、認証、ロケールなど、本当に共有が必要で更新頻度の低い状態に使い、何でも入れるグローバルな置き場にはしないでください。状態遷移が複雑になったり、互いに依存したりする場合は、リデューサー/ステートマシンでモデル化し、無効な状態を表現できないようにしてください。既存の状態から計算できる派生状態を、同期を保つ必要があるコピーとして保存するよりも優先してください。

3. 非同期処理とデータ取得

すべての非同期処理を、読み込み中、エラー、空、成功の4つの明示的な状態としてモデル化してください。空の状態(取得は成功したものの、何も返されなかった状態)は忘れられがちですが、読み込み中とは異なる UI です。値が未定義かもしれないのに、data.map(...) をレンダリングしないでください。

同じデータが画面内で何度も取得されないよう、リクエストをキャッシュし、重複を排除してください。競合状態にも対処してください。入力の変更がレスポンスの返却より速い場合(入力中の検索など)、古いレスポンスが新しいレスポンスを上書きすることがあります。順序が前後した結果をキャンセルするか、無視してください。あちこちに if (loading) 分岐を散在させるのではなく、フレームワークのサスペンス/非同期境界プリミティブを使い、読み込みとエラーの処理を宣言的に行ってください。

4. フォームとバリデーション

コンポーネントの状態をフィールド値の唯一の信頼できる情報源にできるよう、制御された入力を優先してください。型とバリデーターを別々に宣言して乖離させるのではなく、単一のスキーマ(Zod)を定義し、そこから TypeScript の型を推論してください。信頼できない入力は境界で検証してください。クライアント側のバリデーションは UX のためのものであり、正確性やセキュリティのために決して信頼してはいけません。サーバー側でも検証してください。

エラーをアクセシブルにしてください。各メッセージをフィールドに関連付け(aria-describedby)、送信に失敗したら最初のエラーにフォーカスを移し、検証結果を通知してください。そうすることで、スクリーンリーダーの利用者が、何も通知されないまま拒否されたフォームに取り残されるのを防げます。

5. アクセシビリティ

まずセマンティック HTML を使ってください。適切な <button>、<nav>、<label>、<dialog> を使えば、キーボード操作、フォーカス、スクリーンリーダー向けのセマンティクスが標準で得られます。セマンティック HTML では補えない本当の不足を埋める場合に限って ARIA を追加してください。不適切な ARIA は、何も使わないよりも悪影響があります。すべてのインタラクティブ要素はキーボードで操作でき、フォーカスが視覚的にわかり、適切に管理されていなければなりません(モーダル内ではフォーカスを閉じ込め、閉じたら元に戻します)。WCAG 2.1 AA のコントラスト比(通常のテキストで 4.5:1)を満たしてください。自動チェック(axe、Lighthouse)は最低限の確認として実施してください。検出できる問題は3分の1程度なので、UI を自分でもタブ操作で確認してください。

6. パフォーマンスとレンダリング

最適化の前にプロファイリングしてください。 体感速度の低下のほとんどは、広範囲にわたる非効率性ではなく、いくつかの実際のボトルネックによるものです。プロファイラーで測定し、実際に負荷の高い箇所を修正してください。メモ化は、測定結果から必要性が確認できた箇所で、意図的に行ってください。安易に適用してはいけません(メモ化の仕組みや、そもそも必要かどうかはフレームワークによって大きく異なります。参考資料を参照してください)。画面下部やルートレベルのチャンクは、コード分割して遅延読み込みしてください。長いリストは仮想化し、画面外のノードを何千個も描画せず、ビューポート内の行だけを描画してください。バンドルを分析して、意図せず重いインポートが含まれていないか確認し、画像も最適化してください(適切な形式、サイズ、遅延読み込み)。Core Web Vitals(LCP、INP、CLS)も継続的に確認してください。これらはユーザーが目にするパフォーマンス指標です。

7. TypeScript の規律

strict mode に加えて、noUncheckedIndexedAccess(配列へのアクセスは T | undefined になります)と exactOptionalPropertyTypes を有効にします。相互排他的な形状は判別可能なユニオンとしてモデル化し、 網羅的に処理します(never のデフォルトケースを設けると、バリアントを追加したときにビルドが失敗します)。 型ガードを使って、型が不明な入力を絞り込みます。as より satisfies を優先します。値を型に照らして検証しつつ、 型を広げたりエラーを握りつぶしたりしません。一方、as はチェックされないアサーションです。 再利用可能なコンポーネントやフックには制約付きジェネリクスを使い、型を繰り返し定義するのではなく、 ユーティリティ型、マップ型、条件型を使って型を導出します。スキーマ(Zod)から型を推論し、 実行時の検証とコンパイル時の型が単一の情報源を共有するようにします。コンポーネントの props、フックの戻り値、 イベントハンドラーには正確な型を指定します。シグネチャはドキュメントの第一線です。

8. テストの原則

内部実装の詳細ではなく、振る舞いとレンダリング結果をテストします。どの関数が呼び出されたか、 内部状態がどうなっているかではなく、ユーザーに何が表示され、何ができるかをアサートします。 そうすれば、リファクタリング後もテストが機能し続けます。シャロー レンダリングは避け、実際のものをレンダリングします。 自作モジュールをスタブするのではなく、境界でネットワークをモック(HTTP をインターセプト)し、 テストで実際のコードパスを通るようにします。

このスキルでは、テストランナーについて改めて説明しません。TDD のワークフロー(レッド・グリーン・リファクタリング、 テストを先に書くこと)については、tdd スキルを参照してください。エンドツーエンドテストとブラウザテストについては、 playwright スキルを参照してください。これらは名前を指定して利用し、ここで説明を独自に繰り返さないでください。

9. プロジェクト構成とツール

型別の巨大なフォルダー(components/、hooks/、utils/ など)に機能をツリー全体へ分散させるのではなく、 機能別に整理します(機能ごとにフォルダーを作り、その機能がコンポーネント、フック、テストを所有します)。 テストやヘルパーは、対象のコードと同じ場所に配置します。名前付きエクスポート(検索しやすく、 リファクタリングに強く、インポート時の名前変更のずれがない)と、一貫したファイル名・識別子名を優先します。

基本のツール構成:開発・ビルドには Vite、パッケージのインストールには pnpm、 リントとフォーマットには ESLint(フラット設定)と Prettier を使います。 すべてのコミットの前に型チェックとリントを実行し(コミット前フックまたは CI ゲートを使います)、 型の不備がメインブランチに取り込まれないようにします。


このスキルの適用方法

構築やリファクタリングを行うときは、まず上記の関連する共通原則を読み、具体的な手順について対応する フレームワークリファレンスを読み込みます。レビューでは、9 つのトピックをチェックリストとして差分を確認します。 ただし、実際に問題がある箇所だけを、その理由とともに指摘し、ルールをただ列挙しないでください。

コメント