Skip to content

Latest commit

 

History

History
105 lines (78 loc) · 6.7 KB

react-nextjs-ts.md

File metadata and controls

105 lines (78 loc) · 6.7 KB

Export Style

  • All exports must be named exports. Default exports are forbidden except for Next.js page.tsx and layout.tsx files.
  • Import statements must use named imports: import { Button } from '@/components/Button' never import Button from '@/components/Button'
  • Re-export barrels must use export { ComponentA } from './ComponentA' syntax, never export { default as ComponentA }

File Naming and Location

  • React components live in /app/components/ with PascalCase filenames: UserCard.tsx, LoginForm.tsx
  • Server components must have .server.tsx suffix: UserList.server.tsx
  • Client components must have .client.tsx suffix: SearchInput.client.tsx
  • Utility functions live in /lib/ with camelCase filenames: formatDate.ts, validateEmail.ts
  • API routes live in /app/api/ following Next.js App Router structure: /app/api/users/route.ts
  • Database queries live in /lib/db/ with camelCase filenames: getUser.ts, createPost.ts
  • Hooks live in /lib/hooks/ with camelCase filenames prefixed with use: useAuth.ts, usePagination.ts
  • Tests live adjacent to source files with .test.ts or .test.tsx suffix: Button.test.tsx next to Button.tsx

Data Fetching

  • Fetch data in Server Components only. Never use useEffect for data fetching in Client Components.
  • Async Server Components must render <Suspense> boundaries with explicit fallback UI: <Suspense fallback={<LoadingSpinner />}><UserList /></Suspense>
  • Every async Server Component must have a .server.tsx suffix and must export an async function.
  • Client Components that need data must receive it as props from Server Component parents.
  • Use fetch() with { cache: 'force-cache' } or { cache: 'no-store' } explicitly set — never omit cache option.

Database and External Services

  • Database clients must be imported from /lib/db/client.ts singleton, never instantiated inline.
  • Supabase client must be imported from /lib/supabase/client.ts for client-side or /lib/supabase/server.ts for server-side.
  • All database queries must be in /lib/db/ functions, never raw queries in components or API routes.
  • API routes must call database functions from /lib/db/, never instantiate clients directly.

Type Safety

  • Never use any type. Use unknown and type guard it, or use Zod .parse() for runtime validation.
  • Never use as type assertions outside of .test.ts files. Use type guards or discriminated unions instead.
  • Function parameters must have explicit types: function getName(user: User): string not function getName(user)
  • React component props must be typed with interfaces: interface ButtonProps { label: string; onClick: () => void } not inline types.
  • API request/response bodies must be validated with Zod schemas in /lib/schemas/: const UserSchema = z.object({ id: z.string(), name: z.string() })

Environment Variables and Secrets

  • Environment variables must be declared in .env.local (git-ignored) and .env.example (git-tracked with placeholder values).
  • Client-side environment variables must be prefixed with NEXT_PUBLIC_ only. All other env vars are server-only.
  • Never hardcode API keys, database URLs, or tokens in any file. Use environment variables exclusively.
  • Never log environment variables or secrets. If logging user data, redact sensitive fields.
  • API keys must never appear in Client Components. Pass data through API routes instead.

Error Handling

  • Every async function must have try/catch. Caught errors must be typed: catch (err) { if (err instanceof AppError) { ... } }
  • Never catch with catch (e: any) or bare catch (e). Always type the error.
  • API routes must return structured error responses: { error: string; code: string; statusCode: number }
  • Errors must be logged to /lib/logger.ts with context: logger.error('User fetch failed', { userId, error })
  • Client Components must display error states explicitly: {error && <ErrorBoundary error={error} />}

Loading and Empty States

  • Every async Server Component must have a loading state. Use <Suspense fallback={<Skeleton />}>
  • Every data list must have an empty state: {items.length === 0 ? <EmptyState /> : <ItemList items={items} />}
  • Every form submission must show loading state: <button disabled={isLoading}>{isLoading ? 'Saving...' : 'Save'}</button>
  • Pagination components must show current page and total count: Page {currentPage} of {totalPages}

Input Validation

  • All form inputs must be validated with Zod schemas before submission.
  • API route handlers must validate request bodies: const data = UserSchema.parse(req.body)
  • URL search parameters must be validated: const page = z.coerce.number().parse(searchParams.page)
  • Never trust user input. Validate at the boundary (API routes, form handlers).

Component Structure

  • Client Components must use 'use client' directive at the top of the file.
  • Server Components must never import Client Components directly. Use composition with children prop.
  • Components larger than 300 lines must be split into smaller components in a subdirectory.
  • Prop drilling deeper than 3 levels requires context or state management, never pass through 4+ levels.

Testing

  • Every utility function in /lib/ must have a .test.ts file with minimum 80% line coverage.
  • Every API route must have a .test.ts file testing success and error paths.
  • Component tests must use React Testing Library, never Enzyme or Snapshot testing.
  • Tests must use describe() blocks organized by function: describe('formatDate', () => { it('formats ISO dates', () => {...}) })
  • Mock external services (Supabase, APIs) with Jest mocks in test files, never in source code.

Next.js App Router Specifics

  • Never use /pages directory. All routes must be in /app directory.
  • Route segments must use lowercase with hyphens: /app/user-profile/page.tsx not /app/UserProfile/page.tsx
  • Dynamic routes must use bracket syntax: /app/posts/[id]/page.tsx not /app/posts/:id/page.tsx
  • Layout files must be named layout.tsx and wrap all child routes.
  • Metadata must be exported from layout.tsx or page.tsx: export const metadata = { title: '...' }

Logging and Debugging

  • Use /lib/logger.ts for all logging. Never use console.log() in production code.
  • Log levels must be: logger.debug(), logger.info(), logger.warn(), logger.error()
  • Every error log must include context object: logger.error('message', { userId, action, error })
  • Remove all console.log() statements before committing. Use linter rule to enforce.

Source: Codelibrium — the marketplace for AI behaviour files. Browse multiple rulesets at codelibrium.com or install via CLI: npx codelibrium-cli install <ruleset-name>