diff --git a/commands/react-build.md b/commands/react-build.md new file mode 100644 index 00000000..d630ae46 --- /dev/null +++ b/commands/react-build.md @@ -0,0 +1,187 @@ +--- +description: Fix React build failures (Vite, webpack, Next.js, CRA, Parcel, esbuild, Bun) incrementally — JSX/TSX compile errors, hydration mismatches, server/client component boundary failures, missing types. Invokes the react-build-resolver agent for minimal, surgical fixes. +--- + +# React Build and Fix + +This command invokes the **react-build-resolver** agent to incrementally fix React build errors with minimal changes. + +## What This Command Does + +1. **Detect Build System**: Identify Vite, webpack, Next.js, CRA, Parcel, esbuild, or Bun +2. **Run Build**: Execute the project's build script +3. **Parse Errors**: Group by layer (TypeScript / bundler config / runtime / hydration) +4. **Fix Incrementally**: One error at a time, re-running build after each change +5. **Report Summary**: Show what was fixed and what remains + +## When to Use + +Use `/react-build` when: + +- `npm run build` (or pnpm/yarn/bun equivalent) fails +- JSX/TSX compile errors after a TypeScript or React upgrade +- Next.js hydration mismatch errors at runtime +- Server/Client Component boundary errors in App Router +- After installing or upgrading `react`, `react-dom`, `@types/react`, or a bundler +- Missing types or "module not found" errors involving React + +## Scope + +This command owns **React build/bundler/runtime hydration** failures. For pure TypeScript type errors with no React involvement, use `/build-fix` (generic) instead. + +## Diagnostic Commands Run + +```bash +# Project build script (preferred) +npm run build --if-present +pnpm build 2>/dev/null +yarn build 2>/dev/null +bun run build 2>/dev/null + +# Standalone typecheck +npm run typecheck --if-present +tsc --noEmit -p tsconfig.json + +# Bundler-specific fallback +next build # Next.js +vite build # Vite +react-scripts build # CRA +webpack --mode=production # webpack +parcel build src/index.html # Parcel +bun build ./src/index.tsx --outdir=dist +``` + +## Example Session + +```text +User: /react-build + +Agent: +# React Build Resolution + +## Build System Detected +Vite (vite.config.ts present, @vitejs/plugin-react in deps) + +## Initial Diagnostics + +```bash +$ npm run build +> tsc -b && vite build + +src/components/UserCard.tsx:1:8 - error TS6133: 'React' is declared but its value is never read. +src/components/Modal.tsx:12:15 - error TS7016: Could not find a declaration file for module 'react-portal'. +src/pages/Home.tsx:42:5 - error: 'useState' is not defined +``` + +Errors found: 3 + +## Fix 1: Old JSX transform leftover + +File: src/components/UserCard.tsx:1 +Cause: `tsconfig.json` already uses `"jsx": "react-jsx"`; the explicit `import React` is unused. + +```tsx +// Removed +- import React from 'react'; +``` + +```bash +$ npm run build +# 2 errors remaining +``` + +## Fix 2: Missing types + +File: src/components/Modal.tsx +Cause: `@types/react-portal` not installed. + +```bash +$ npm i -D @types/react-portal +added 1 package +``` + +```bash +$ npm run build +# 1 error remaining +``` + +## Fix 3: Missing hook import + +File: src/pages/Home.tsx +Cause: `useState` referenced but not imported. + +```tsx +- import { useEffect } from "react"; ++ import { useEffect, useState } from "react"; +``` + +```bash +$ npm run build +# Build successful! +``` + +## Final Verification + +```bash +$ npm run build +✓ built in 2.34s + +$ npm test +✓ 47 tests passed +``` + +## Summary + +| Metric | Count | +|--------|-------| +| Build errors fixed | 3 | +| Files modified | 2 | +| Dependencies added | 1 (@types/react-portal) | +| Remaining issues | 0 | + +Build Status: PASS: SUCCESS +``` + +## Common Errors Fixed + +| Error | Typical Fix | +|---|---| +| `'React' is not defined` | Set `"jsx": "react-jsx"` in tsconfig (React 17+) | +| Missing `@types/react` | `npm i -D @types/react @types/react-dom` | +| `Unexpected token '<'` | Add `@vitejs/plugin-react` / `babel-loader` | +| `You're importing a component that needs useState` (Next.js) | Add `"use client"` or move hook to a Client Component child | +| `Module not found: Can't resolve 'fs'` (Next.js) | Remove `fs` import or move logic into Server Component / API route | +| `Hydration failed because the initial UI does not match` | Move `Date.now()`/`Math.random()`/`window.*` to `useEffect` | +| `Invalid hook call` | Multiple React copies — dedupe via `resolutions`/`overrides` | +| `Element type is invalid` | Default vs named import mismatch | + +## Fix Strategy + +1. **Compile errors first** — code must build +2. **Hydration errors second** — affects production correctness +3. **Bundler config third** — restore plugin/loader correctness +4. **One fix at a time** — verify each change +5. **Minimal changes** — never `// @ts-ignore` without explanation +6. **Re-run after each fix** — surface new errors immediately + +## Stop Conditions + +The agent will stop and report if: + +- Same error persists after 3 attempts +- Fix introduces more errors than it resolves +- Requires architectural change beyond build resolution (e.g., redesigning the RSC boundary) +- Bundler version no longer supports the installed React major + +## Related Commands + +- `/react-test` — run tests after the build is green +- `/react-review` — review code quality after the build succeeds +- `/build-fix` — generic build fixer (non-React) +- `verification-loop` skill — full verification loop + +## Related + +- Agent: `agents/react-build-resolver.md` +- Skills: `skills/react-patterns/`, `skills/frontend-patterns/` +- Rules: `rules/react/coding-style.md`, `rules/react/patterns.md` diff --git a/commands/react-review.md b/commands/react-review.md new file mode 100644 index 00000000..646a51b1 --- /dev/null +++ b/commands/react-review.md @@ -0,0 +1,170 @@ +--- +description: Comprehensive React/JSX code review for hook correctness, render performance, server/client component boundaries, accessibility, and React-specific security. Invokes the react-reviewer agent (and typescript-reviewer alongside on TSX/JSX changes). +--- + +# React Code Review + +This command invokes the **react-reviewer** agent for React-specific code review. For pull requests touching `.tsx`/`.jsx` files, both `react-reviewer` and `typescript-reviewer` should run — each owns a distinct lane. + +## What This Command Does + +1. **Identify React Changes**: Find modified `.tsx`/`.jsx` files (and React-containing `.ts`/`.js` files) via `git diff` +2. **Run Lint**: Execute `eslint` with `eslint-plugin-react-hooks` and `eslint-plugin-jsx-a11y` +3. **Typecheck**: Run `tsc --noEmit` or the project's canonical typecheck command +4. **Review React Lanes Only**: Hook rules, RSC boundaries, accessibility, render performance, React-specific security +5. **Generate Report**: Categorize issues by severity (CRITICAL / HIGH / MEDIUM) + +## When to Use + +Use `/react-review` when: + +- A PR or commit touches `.tsx`/`.jsx` files +- After writing or modifying React components, custom hooks, or pages +- Before merging React code +- Auditing accessibility on UI components +- Reviewing a new hook for rules-of-hooks and dependency correctness +- Auditing a Next.js App Router server/client component boundary + +For pure `.ts`/`.js` changes with no React imports, use `/code-review` (general) or invoke `typescript-reviewer` directly. + +## Scope vs `/code-review` and TypeScript Review + +| Tool | Scope | +|---|---| +| `react-reviewer` (this command) | Hooks rules, JSX, RSC, a11y, React-specific security, render perf | +| `typescript-reviewer` | Generic TS/JS — `any` abuse, async correctness, Node security | +| `security-reviewer` | Project-wide security audit | +| `/code-review` | Generic uncommitted-changes or PR review | + +On a TSX/JSX PR, invoke both `react-reviewer` and `typescript-reviewer`. Findings from each are non-overlapping by design. + +## Review Categories + +### CRITICAL (Must Fix) + +- `dangerouslySetInnerHTML` with unsanitized input +- `href`/`src` with unvalidated user URLs (`javascript:`, `data:`) +- Server Action without input validation +- Secret in client bundle (`NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`) +- `localStorage`/`sessionStorage` for session tokens +- Conditional hook calls (violates Rules of Hooks) +- Direct state mutation +- Hook called outside a component or custom hook + +### HIGH (Should Fix) + +- Missing `useEffect`/`useMemo`/`useCallback` deps (disabled `exhaustive-deps` without justification) +- Effect for derived state +- Effect missing cleanup +- Stale closures in handlers/intervals +- Server-only imports in Client Components +- Sensitive data leaked via props to Client Components +- Server Actions without auth checks +- Accessibility violations (missing labels, non-semantic interactive elements, ARIA misuse) +- `key={index}` in dynamic lists +- Duplicated state, useEffect chains + +### MEDIUM (Consider) + +- Over-memoization without measured win +- Inline new object/function as prop to memoized child +- Suspense at route root only (no progressive reveal) +- Long lists without virtualization +- High-frequency value via `useContext` +- Roll-your-own validation in non-trivial forms +- Prop drilling beyond 3 levels +- Component over 200 lines +- Class components in new code + +## Automated Checks Run + +```bash +# Lint (required for any meaningful review) +npx eslint . --ext .tsx,.jsx,.ts,.js + +# Typecheck (skip cleanly for JS-only projects) +npm run typecheck --if-present +tsc --noEmit -p tsconfig.json + +# Targeted a11y rules +npx eslint . --rule 'jsx-a11y/alt-text: error' \ + --rule 'jsx-a11y/anchor-is-valid: error' \ + --rule 'jsx-a11y/click-events-have-key-events: error' + +# Supply-chain +npm audit +``` + +If `eslint-plugin-react-hooks` or `eslint-plugin-jsx-a11y` is not configured, the review will flag the gap as a HIGH config issue and continue. + +## Example Usage + +```text +User: /react-review + +Agent: +# React Code Review Report + +## Files Reviewed +- src/components/UserCard.tsx (modified) +- src/hooks/useUser.ts (new) + +## Lint Results +PASS: eslint clean +PASS: typecheck clean + +## Issues Found + +[CRITICAL] Unsanitized dangerouslySetInnerHTML +File: src/components/UserCard.tsx:42 +Issue: User-controlled bio rendered as raw HTML. +Why: XSS via stored script tags in user input. +Fix: Sanitize with DOMPurify or render as text: +```tsx +import DOMPurify from "isomorphic-dompurify"; +
+``` + +[HIGH] Effect cleanup missing +File: src/hooks/useUser.ts:18 +Issue: `fetch` call without AbortController; setState on unmounted component possible. +Fix: Add AbortController and cleanup: +```ts +useEffect(() => { + const ac = new AbortController(); + fetch(`/api/users/${id}`, { signal: ac.signal }) + .then(r => r.json()) + .then(setUser); + return () => ac.abort(); +}, [id]); +``` + +## Summary +- CRITICAL: 1 +- HIGH: 1 +- MEDIUM: 0 + +Recommendation: FAIL: Block merge until CRITICAL issue is fixed +``` + +## Approval Criteria + +| Status | Condition | +|---|---| +| PASS: Approve | No CRITICAL or HIGH issues | +| WARNING: Warning | Only MEDIUM issues (merge with caution) | +| FAIL: Block | CRITICAL or HIGH issues found | + +## Integration with Other Commands + +- Run `/react-build` first if the build is broken +- Run `/react-test` to ensure component tests pass +- Run `/react-review` before merging +- Use `/code-review` for non-React-specific concerns on the same PR + +## Related + +- Agent: `agents/react-reviewer.md` +- Companion agent: `agents/typescript-reviewer.md` (run alongside for TSX/JSX PRs) +- Skills: `skills/react-patterns/`, `skills/react-testing/`, `skills/accessibility/` +- Rules: `rules/react/` diff --git a/commands/react-test.md b/commands/react-test.md new file mode 100644 index 00000000..d8f481d5 --- /dev/null +++ b/commands/react-test.md @@ -0,0 +1,265 @@ +--- +description: Enforce TDD workflow for React. Write React Testing Library tests first (behavior-focused, accessibility-first), then implement components. Detects Vitest or Jest and verifies coverage targets. +--- + +# React TDD Command + +This command enforces test-driven development for React using React Testing Library plus Vitest or Jest, detected at runtime. + +## What This Command Does + +1. **Define Component Signature**: Scaffold the component, prop type, and exports +2. **Write Behavior Tests First**: RTL queries (role-first), `userEvent`, MSW for network — RED +3. **Run Tests**: Verify they fail for the right reason +4. **Implement Minimal Code**: Just enough to pass — GREEN +5. **Refactor**: Improve while keeping tests green +6. **Check Coverage**: Hit the targets in [rules/react/testing.md](../rules/react/testing.md) + +## When to Use + +Use `/react-test` when: + +- Implementing a new React component or custom hook +- Adding test coverage to an untested component +- Fixing a bug (write failing test first that reproduces it) +- Building forms, state machines, or accessibility-critical UI +- Onboarding to RTL + Vitest/Jest workflow + +## TDD Cycle + +``` +RED -> Write failing test for the next behavior +GREEN -> Implement minimal component code to pass +REFACTOR -> Improve component, tests stay green +REPEAT -> Next behavior +``` + +## Runner Detection + +```bash +test -f vitest.config.ts -o -f vitest.config.js -o -f vite.config.ts # Vitest +grep -l '"jest"' package.json # Jest +``` + +Prefer Vitest for new Vite-based projects; respect Jest for existing setups. + +## Example Session + +```text +User: /react-test I need a SearchInput component with debounced search + +Agent: +# TDD Session: SearchInput + +## Step 1: Define Signature + +```tsx +// src/components/SearchInput.tsx +type Props = { + onSearch: (query: string) => void; + placeholder?: string; + debounceMs?: number; +}; + +export function SearchInput({ onSearch, placeholder, debounceMs }: Props) { + throw new Error("not implemented"); +} +``` + +## Step 2: Write Behavior Tests (RED) + +```tsx +// src/components/SearchInput.test.tsx +import { describe, expect, test, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { SearchInput } from "./SearchInput"; + +describe("SearchInput", () => { + test("renders with placeholder", () => { + render(