mcpField
R
remix-v2-data-flow-review

remix-v2-data-flow-review

github.com/existential-birdsテスト・品質8542 回インストール11 週間前に更新
リポジトリ

remix-v2-data-flow-review について

TypeScript の Remix v2 プロジェクト向けコードレビュースキルです。ルートのデータ読み込み、更新、再検証、ストリーミングを対象とし、誤検知を避けるチェックリストも備えています。

主な機能

  1. 01loader と action のデータフロー確認
  2. 02入力検証と機密フィールド漏えいの確認
  3. 03再検証と処理中状態の監査
  4. 04defer とストリーミングの確認
  5. 05レビュー手順と正当なパターンの提示

活用シーン

  1. 01Remix v2 ルートのデータ処理レビュー
  2. 02action の検証と成功分岐の確認
  3. 03再検証や遅延データの問題調査

インストール

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

$npx skills add https://github.com/existential-birds/beagle --skill remix-v2-data-flow-review

インストール後、Claude Code で/remix-v2-data-flow-reviewを入力して読み込まれたか確認します。

同梱ファイル

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

references/
actions.md
defer-await.md
loaders.md
revalidation.md

詳細

Remix v2 データフローのコードレビュー

@remix-run/* からインポートする TypeScript のルートモジュールが対象です。標準的なパターンについては、remix-v2-data-flow を参照してください。

対象範囲

  • 対象:app/routes/ 配下にある loader、action、shouldRevalidate、または headers をエクスポートするルートモジュール、および useLoaderData、useActionData、useNavigation、useFetcher、useRevalidator、<Await> を使用するコンポーネント。
  • 対象外:フォームの使いやすさ(<Form> のマークアップ、アクセシビリティ、useFetcher の UI パターン)→ remix-v2-forms-review が担当します。ルートモジュールの規約、ファイル名、ネストされたルーティング、エラーバウンダリの配置 → remix-v2-routing-review が担当します。
  • 想定されるインポート:サーバーユーティリティには @remix-run/node(または @remix-run/cloudflare / @remix-run/deno)、フックとコンポーネントには @remix-run/react。

クイックリファレンス

問題の種類参照先
loader 内のミューテーション、バリデーション不足、サーバーフィールドの漏えい、プリミティブ値のスロー、パラメーターのチェック不足references/loaders.md
未検証の FormData、成功時に redirect ではなく json を使用、エラーケースの欠落、actionData の漏えいreferences/actions.md
v1 からの useTransition の残存、保留中状態の欠落、無条件の shouldRevalidate: false、useRevalidator の誤用references/revalidation.md
すでに高速なデータへの defer の使用、<Suspense> の欠落、<Await> の errorElement の欠落、ストリーミングすべきデータの awaitreferences/defer-await.md

レビューチェックリスト

  • 初回レンダリングに必要なデータは useEffect ではなく loader にある
  • loader は読み取りのみを行い、書き込みは action に置く
  • request.formData() の結果は使用前に検証する(zod/valibot/invariant)
  • loader/action の戻り値は射影された DTO であり、パスワードハッシュ、トークン、または internal_* フィールドを含まない
  • useLoaderData<typeof loader>() では型アノテーション形式を使用する(as Foo ではない)
  • 404 / 認証の早期終了では Response(または json / redirect)を throw し、通常の Error や文字列は決して使わない
  • action の成功時は redirect(...) を返す(PRG)。バリデーション失敗時は json({ errors }, { status: 400 }) を返す
  • action は成功とエラーの両方の分岐を処理し、無言で return null しない
  • params.foo は使用前に invariant / zod でチェックする
  • 保留中の UI では useNavigation() / fetcher.state を読み取り、useTransition は使用しない
  • formMethod の比較には大文字を使う("post" ではなく "POST")
  • shouldRevalidate はデフォルトで defaultShouldRevalidate を返す。再検証の除外は限定的かつ正当化されたものにする
  • defer() は少なくとも1つの Promise がストリーミングされる場合にのみ使用する(渡す前に await しない)
  • すべての <Await> を <Suspense> でラップし、errorElement を指定する
  • useRevalidator().revalidate() はフォーカス、ポーリング、SSE に限定して使用する。<Form> の送信後や fetcher.submit の直後には呼び出さない(Remix がすでに再検証します)。

有効なパターン(問題として報告しないでください)

以下は正しい Remix v2 の使用方法であり、問題として報告してはいけません。

  • クライアント専用データに対する useEffect — ローダーはサーバー側で実行されます。localStorage、window のサイズ、IntersectionObserver、ブラウザー専用 API は useEffect で扱います。
  • null を返す loader — ローダーは正当な理由で null を返すことがあります(例:任意のリソースが存在しない場合)。404 を throw する必要がある場合に限り、問題として報告してください。
  • 型注釈としての useLoaderData<typeof loader>() — <typeof loader> は SerializeFrom<T> に渡されるジェネリックパラメーターであり、as 形式の型アサーションではありません。「安全でないキャスト」として報告しないでください。
  • new Response(body, init) をそのまま返す — v2 のルートでは任意の Response を返せます。json() は使いやすくするためのラッパーであり、必須ではありません。JSON 以外の本文(バイナリ、テキスト、ストリーム)で json() を使わないのは適切です。
  • アクションからの return redirect(...) — アクションでは return redirect(...) と throw redirect(...) のどちらも有効です。呼び出し元の関数から抜ける必要がある場合に throw が必須となるのは、アクションではないヘルパーから呼び出す場合だけです。
  • request 引数なしで宣言された loader — ローダーでは必要なものだけを分割代入できます({ params }、{ context }、または引数なしの ())。未使用の引数がないことはバグではありません。
  • 無関係なアクションの後に親の loader が再検証される — これは Remix のデフォルトの動作であり、問題の兆候ではありません。shouldRevalidate が存在し、かつ誤っている場合に限り、問題として報告してください。
  • json({ errors }, { status: 400 }) を返すアクション — これは正規のバリデーションエラーパターンです(フィールドエラーを表示したままフォームのルートをレンダリングできます)。「成功時にリダイレクトしない」というアンチパターンとは異なります。
  • フォーカス/ポーリング/タブ間同期のための useRevalidator — これらはドキュメントで説明されている使用例です。<Form> の送信や fetcher.submit の直後に手動で revalidate() を呼び出し、Remix がすでに再検証する場合に限り、問題として報告してください。
  • SerializeFrom によって引き起こされる型の変更 — デシリアライズ後に Date が string として型付けされることや、Map が {} として型付けされることは、正しいワイヤー形式の動作であり、型付けのバグではありません。

コンテキストに応じたルール

以下の問題は、該当する特定のコンテキストでのみ報告してください。

問題以下の場合に限り報告
ローダーがない(代わりに useEffect を使用)データがサーバー側で利用可能で、ブラウザー専用 API の読み取りではない
loader が ORM オブジェクトをそのまま返すオブジェクトに、レビュー担当者がスクリーンショットに載せたくないフィールド(パスワード、トークン、内部フラグ)が含まれている
アクションが成功時に json を返すアクションが <Form> 経由で呼び出され、URL が変更される場合。useFetcher 経由の場合は除く
保留中の UI がない同じ画面を制御する nav.state / fetcher.state への参照がファイル内のほかの場所にない
shouldRevalidate が false を返す本体に条件がない、または formAction / currentParams / nextParams を一度も参照しない
手動での useRevalidator().revalidate()呼び出しが Remix 管理のミューテーション(<Form> の送信、fetcher.submit)の後に行われる場合。フォーカス/ポーリング/WebSocket の場合は除く
defer() の使用defer({...}) のペイロード内のすべてのプロミスが、呼び出し前にすでに await されている

指摘事項を作成する前の必須ゲート

以下を順番に実行してください。報告するバッチについてすべてのゲートを通過するまで、ユーザー向けの指摘事項を作成しないでください。

  1. 場所の証拠 — 合格: 各問題には、リポジトリ内のルートモジュールのパスと、読み取ったファイルにある行範囲または短い逐語引用(記憶や差分だけに基づく推測ではないもの)が記載されています。export async function loader|action へのパスが示されていないローダー/アクションの問題は報告できません。

  2. 免除項目の確認 — 合格: 各問題について、有効なパターン(指摘しない)の対象外である理由を1行で説明できます。特に、useEffect がクライアント限定データを読み込んでいないこと、単独の Response の返却が意図的に非JSONでないこと、loader が null を返すケースが正当な任意読み込みでないことを確認してください。

  3. 型注釈と型アサーションの確認 — 合格: ローダー/アクションのデータ利用に関して「安全でないキャスト」を指摘する前に、コードで使われているのが as(アサーション)であることを確認してください。useLoaderData<typeof loader>()(注釈)でも、useActionData<typeof action>()(注釈)でもないことを確認します。ジェネリック形式は、文書化された安全な方法であり、指摘してはいけません。

  4. v1からの残存コード確認 — 合格: 「保留状態の不足」を指摘する前に、ファイル内で useTransition、transition.submission、fetcher.type、formMethod === "post" または formMethod==='post'(小文字、空白や引用符の形式は問わない)、および LoaderArgs / ActionArgs を検索してください。該当するものがある場合、その指摘は機能不足ではなく、v1からの移行時に残った問題です。そのように分類してください。

  5. プロトコル — 合格: このレビューについて、review-verification-protocol の提出前検証チェックリストを完了しています。

参照資料を読み込むタイミング

  • loader の本体、戻り値の形式、パラメーター、例外、機密フィールドの漏えいをレビューする場合 → references/loaders.md
  • action の本体、FormData の検証、成功/エラー分岐、PRG リダイレクトをレビューする場合 → references/actions.md
  • useNavigation/useTransition の移行、shouldRevalidate、useRevalidator の使い方をレビューする場合 → references/revalidation.md
  • defer()、<Await>、<Suspense>、ストリーミングの判断をレビューする場合 → references/defer-await.md

レビュー時の確認事項

  1. 初回レンダリングに必要なデータは loader で取得されていますか。それとも、SSR と再検証を妨げる useEffect 内に残っていますか?
  2. すべてのローダーが射影済みの DTO を返していますか。それとも、ORM の生レコード(password、token、internal_* フィールドを含む)がブラウザーに漏えいしていますか?
  3. すべてのアクションで、データベースにアクセスする前にスキーマを使って request.formData() を検証していますか?
  4. 各アクションの成功分岐で redirect(...) していますか。これにより、更新/戻る操作が正しく動作しますか(PRG)?
  5. 利用側のコードでは useLoaderData<typeof loader>()(注釈)を使っていますか。useLoaderData() as Foo(アサーション)ではありませんか?
  6. v1からの残存コード(useTransition、transition.submission、fetcher.type、小文字の formMethod、LoaderArgs / ActionArgs)は残っていますか?
  7. shouldRevalidate はリテラルの false を返していますか。それとも defaultShouldRevalidate を参照し、限定的に再検証を抑制していますか?
  8. defer() は未解決の Promise が少なくとも1つ渡される場合にのみ使用されていますか。また、すべての <Await> は errorElement を指定した <Suspense> でラップされていますか?

その他のドキュメント

指摘事項を提出する前に

必須ゲート(特にゲート5)を完了し、review-verification-protocol の提出前チェックに引き続き合格する問題のみを報告してください。

コメント