This document provides comprehensive context about the react-playround project to enable AI agents to understand the codebase architecture, conventions, and development patterns effectively.
A modern React development playground focused on testing and validating the Vibe coding workflow. The project is collaboratively maintained by AI coding tools and human developers. It demonstrates a production-ready React application with TypeScript, GraphQL/Relay, multiple styling approaches, and comprehensive testing infrastructure.
Key Characteristics:
- Focus: Vibe coding workflow validation and AI/human collaboration
- Build System: Rsbuild (Rspack-based) for high-performance builds
- State/Data: React hooks for local state, Relay for GraphQL data management
- UI Layer: Tailwind CSS utilities with Ant Design components
- Testing: Vitest + React Testing Library with 70% coverage requirement
- Type Safety: Strict TypeScript with generated GraphQL types
- React: 19.2.1 (latest major version with concurrent features)
- TypeScript: 5.9.3 (strict mode with comprehensive type checking)
- Package Manager: pnpm (efficient disk space usage, fast installs)
- Rsbuild: 1.6.14 (modern build tool powered by Rspack)
- Rspack: High-performance webpack-compatible bundler
- Babel: 7.26.0 (custom transformations via rsbuild-plugin-babel)
- Relay Compiler: 19.0.0 (GraphQL query compilation)
- React Relay: 19.0.0 (GraphQL client for React)
- Relay Runtime: 19.0.0 (normalized data caching)
- GraphQL: 16.9.0 (query language)
- Ant Design: 6.1.0 (comprehensive component library)
- Tailwind CSS: 3.4.10 (utility-first CSS framework)
- SCSS: 1.96.0 (via @rsbuild/plugin-sass)
- PostCSS: 8.5.6 (CSS processing)
- React Router DOM: 6.x (declarative routing)
- Vitest: 2.1.8 (fast test framework based on Vite)
- React Testing Library: 16.1.0 (component testing utilities)
- Jest DOM: 6.6.3 (DOM-specific assertions)
- User Event: 14.5.2 (user interaction simulation)
- jsdom: 25.0.1 (browser environment simulation)
- Happy DOM: 15.11.7 (alternative DOM implementation)
- @vitest/ui: 2.1.8 (visual test interface)
- @vitest/coverage-v8: 2.1.8 (V8 coverage provider)
- ESLint: 9.0.0 (code linting)
- @typescript-eslint: 8.0.0 (TypeScript linting rules)
- Husky: 9.0.0 (Git hooks)
- lint-staged: 15.2.0 (pre-commit linting)
react-playround/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── Header.tsx # Application header with navigation
│ │ ├── Header.test.tsx # Header unit tests
│ │ ├── Footer.tsx # Application footer
│ │ └── PostCard.tsx # Blog post card component
│ │
│ ├── pages/ # Route-level components
│ │ ├── Home.tsx # Landing page with featured posts
│ │ ├── Posts.tsx # All posts listing with pagination
│ │ ├── ShoppingCart/ # Shopping cart feature module
│ │ │ ├── index.tsx # Main page component with state
│ │ │ ├── ProductList.tsx # Product listing with categorization
│ │ │ ├── SearchBar.tsx # Search and filter controls
│ │ │ ├── interface.ts # TypeScript interfaces and enums
│ │ │ └── allShoppingCartProducts.tsx # Mock product data
│ │ │
│ │ └── RelayExample.tsx # GraphQL/Relay demonstration page
│ │
│ ├── relay/ # GraphQL configuration
│ │ └── Environment.ts # Relay Environment setup with mock data
│ │
│ ├── __generated__/ # Auto-generated GraphQL types (DO NOT EDIT)
│ │ └── RelayExampleQuery.graphql.ts
│ │
│ ├── test/ # Testing infrastructure
│ │ ├── setupTests.ts # Global test setup and mocks
│ │ └── utils.tsx # Custom render function and utilities
│ │
│ ├── App.tsx # Root component with routing configuration
│ ├── index.tsx # Application entry point
│ ├── index.css # Global styles (Tailwind imports)
│ ├── env.d.ts # Environment type declarations
│ └── vitest.d.ts # Vitest type declarations
│
├── public/ # Static assets
├── rsbuild.config.ts # Build configuration
├── vitest.config.ts # Test configuration
├── tsconfig.json # TypeScript configuration
├── relay.config.json # Relay compiler configuration
├── tailwind.config.js # Tailwind CSS configuration
├── postcss.config.js # PostCSS configuration
├── eslint.config.js # ESLint configuration
├── package.json # Dependencies and scripts
└── pnpm-lock.yaml # Locked dependency versions
components/:
- Contains reusable UI elements used across multiple pages
- Each component typically has: source file (.tsx), optional test file (.test.tsx)
- Naming: PascalCase (e.g.,
Header.tsx,PostCard.tsx) - All components use
React.memo()for performance optimization - All memoized components set
displayNamefor debugging
pages/:
- Route-level components that map to URL paths
- Feature modules (like ShoppingCart) contain related components and data
- Complex pages may have internal sub-components defined in same directory
- Data models and interfaces co-located with related functionality
relay/:
- GraphQL-specific configuration
- Environment.ts contains network layer setup and mock data
- Query compilation artifacts stored in
__generated__/
test/:
- Shared test utilities and configuration
- setupTests.ts runs before all tests (mocks, global setup)
- utils.tsx provides custom render function with common providers
Standard Functional Component:
// Always use React.FC for explicit typing
// Always wrap in React.memo() for performance
// Always set displayName for debugging
// Always use TypeScript interfaces for props
/**
* @file Component description
* @description Detailed description for documentation tools
*/
import React, { memo } from 'react';
interface ComponentNameProps {
// Required props first
title: string;
// Optional props with default handling
subtitle?: string;
// Callback props
onClick?: () => void;
// Complex prop types
items: Array<{ id: string; name: string }>;
}
/**
* @example
* <ComponentName title="Hello" items={[{id: '1', name: 'Item'}]} />
*/
const ComponentName: React.FC<ComponentNameProps> = memo(({
title,
subtitle,
onClick,
items
}) => {
return (
<div className="component-classes">
<h1>{title}</h1>
{subtitle && <p>{subtitle}</p>}
</div>
);
});
ComponentName.displayName = 'ComponentName';
export default ComponentName;Component with Internal State:
// Use useState for component-level state
// Use useCallback for callback functions to maintain referential equality
// Use useMemo for expensive computed values
// Always type state explicitly
const [state, setState] = useState<StateType>(initialValue);
const handleAction = useCallback((param: ParamType) => {
// Implementation
}, [dependencies]);Local Component State:
- React
useStatefor component-level state - State updates trigger re-renders
- State colocated with component using it
Computed Values:
useMemofor expensive calculations- Dependencies array controls when recomputation occurs
- Example: filtering lists, derived data
Callback Stability:
useCallbackfor functions passed as props- Prevents unnecessary re-renders of child components
- Critical for performance optimization
No Global State Library:
- Currently no Redux, Zustand, or Context for global state
- All state is either local or managed by Relay's normalized cache
- Simpler architecture, less boilerplate
Query Definition:
import { graphql, useLazyLoadQuery } from 'react-relay';
import type { GeneratedQueryType } from '../__generated__/QueryName.graphql';
const data = useLazyLoadQuery<GeneratedQueryType>(
graphql`
query QueryName {
field {
subfield
}
}
`,
variables
);GraphQL Types:
- Generated automatically by Relay Compiler
- Stored in
src/__generated__/directory - Types follow pattern:
{QueryName}Query.graphql.ts - NEVER manually edit generated files
Environment Configuration:
src/relay/Environment.tsdefines the Relay Environment- Network layer handles GraphQL requests
- Mock data function (
fetchQueryWithMock) used for development - To use real GraphQL: uncomment Authorization header, point to real API
Suspense Integration:
- Relay components wrapped in
Suspensefor loading states - Fallback prop provides loading UI
- Automatic loading state management
Primary: Tailwind CSS:
- Utility-first CSS framework
- Classes applied via
classNameprop - Responsive design with mobile-first breakpoints
- Example:
className="bg-white shadow-md p-6 hover:shadow-lg transition-shadow"
Secondary: SCSS:
- Available via @rsbuild/plugin-sass
- For complex component-specific styles
- File extension:
.scssor.module.scss
Ant Design Components:
- Used for complex UI elements (Input, Button, Checkbox, etc.)
- Imported directly from 'antd'
- Styled via Ant Design theming (minimal custom overrides)
Styling Patterns:
- Tailwind for layout, spacing, typography, colors
- Ant Design for form controls, complex components
- Inline styles only for dynamic values (e.g.,
style={{ width: progress }})
Strict Mode Enabled:
- All strict flags in tsconfig.json are enabled
- No implicit any types
- Strict null checks
- Strict function types
No Unused Variables:
noUnusedLocals: true- errors on unused local variablesnoUnusedParameters: true- errors on unused function parameters- Exception: underscore prefix (e.g.,
_unusedParam) allowed - Exception: test files have more relaxed rules
Interface vs Type:
- Use
interfacefor object shapes and prop types - Use
typefor unions, intersections, primitive aliases - Export interfaces from dedicated
interface.tsfiles in feature directories
Import Patterns:
- Named imports for individual exports
- Default imports for main module exports
- Type-only imports with
import type(TypeScript 5.0+)
Feature Modules:
- Related files grouped in same directory
- Example:
pages/ShoppingCart/contains:index.tsx(main component)ProductList.tsx(child component)SearchBar.tsx(child component)interface.ts(types)allShoppingCartProducts.tsx(data)
Type Co-location:
- Types defined near where they're used
- Feature-specific types in feature directory
- Shared types in common location or co-located
Data Co-location:
- Static data defined outside component (module level)
- Prevents recreation on each render
- Example: mock data arrays, constant configurations
Test Co-location:
- Test files alongside source files
- Naming:
*.test.tsor*.test.tsx - Setup files in
src/test/directory
Purpose: Build tool configuration for Rsbuild
Key Configuration:
// React plugin enables JSX, HMR, Fast Refresh
plugins: [pluginReact()]
// Babel plugin with custom configuration
pluginBabel({
babelLoaderOptions: {
plugins: [
['relay', { artifactDirectory: './src/__generated__' }]
]
}
})Special Notes:
- Relay Babel plugin compiles GraphQL queries to artifacts
- Artifacts output to
src/__generated__/directory - Supports HMR for rapid development
- Production builds optimized automatically
Purpose: Test runner configuration
Key Configuration:
// Test environment
environment: 'jsdom'
// File patterns
include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}']
exclude: ['node_modules', 'dist', '__generated__/**']
// Global setup
setupFiles: ['./src/test/setupTests.ts']
// Coverage configuration
coverage: {
provider: 'v8',
thresholds: { lines: 70, functions: 70, branches: 70, statements: 70 },
exclude: ['node_modules/', 'src/test/', '**/*.d.ts', '__generated__/**']
}
// Path alias
resolve: { alias: { '@': path.resolve(__dirname, './src') } }Coverage Requirements:
- 70% minimum for lines, functions, branches, statements
- Coverage reports generated in
coverage/directory - Test commands:
test:run,test:ui,test:coverage
Purpose: TypeScript compiler options
Key Configuration:
{
"compilerOptions": {
"jsx": "react-jsx",
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"verbatimModuleSyntax": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": true
},
"include": ["src", "vitest.config.ts", "src/vitest.d.ts"],
"exclude": ["node_modules", "dist", "__generated__/**"]
}Important Rules:
strict: trueenables all strict type checkingnoUnusedLocals/Parameterscatches dead codenoEmitonly type-checks (build handled by Rsbuild)ESNextmodules withbundlerresolution for modern tooling
Purpose: Relay Compiler configuration
Configuration:
{
"src": "./src",
"schema": "./src/schema.graphql",
"language": "typescript",
"artifactDirectory": "./src/__generated__",
"eagerEsModules": true
}Key Points:
schemapoints to GraphQL schema fileartifactDirectorydefines generated type outputeagerEsModulesenables ES module imports- Run
pnpm relayto compile queries
Purpose: Tailwind CSS configuration
Configuration:
module.exports = {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}"
],
theme: { extend: {} },
plugins: []
}Key Points:
- Scans all source files for class names
- Default theme (no customization in this project)
- No custom plugins configured
Purpose: Code linting rules
Key Rules:
// TypeScript
'@typescript-eslint/no-unused-vars': ['warn', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}]
'@typescript-eslint/no-explicit-any': 'warn'
'@typescript-eslint/no-non-null-assertion': 'warn'
// React
'react/react-in-jsx-scope': 'off' // React 17+
'react/prop-types': 'off' // TypeScript handles types
'react-hooks/rules-of-hooks': 'error'
'react-hooks/exhaustive-deps': 'warn'
// General
'no-console': ['warn', { allow: ['warn', 'error'] }]
'prefer-const': 'warn'Test File Exceptions:
- Test files can use
console.log - Test files can use
anytype - Test files can use non-null assertions
pnpm run dev # Start development server with HMR
# Opens http://localhost:3000
# Supports hot module replacement
pnpm run build # Production build
# Output to dist/ directory
# Optimized and minified
pnpm run preview # Preview production build locally
# Serves dist/ directory
# Useful to test production buildpnpm run relay # Compile GraphQL queries
# Updates src/__generated__/
# Required after query changespnpm run lint # Run ESLint
# Checks all .ts, .tsx files
# Reports issues
pnpm run lint:fix # Run ESLint with auto-fix
# Fixes fixable issues
# Requires review for changespnpm test # Run tests in watch mode
# Re-runs on file changes
# Interactive test selection
pnpm test:run # Run tests once (CI mode)
# No watch mode
# Returns exit code
pnpm test:ui # Run tests with Vitest UI
# Visual interface
# Browse test results
pnpm test:watch # Run tests in watch mode
# Waits for file changes
# Manual control
pnpm test:coverage # Generate coverage report
# Outputs to coverage/ directory
# Checks against thresholdspnpm prepare # Install Husky git hooks
# Runs automatically after install
# Enables pre-commit lintingLocation: src/App.tsx
Route Map:
// Route configuration in App.tsx
<Routes>
<Route path="/" element={<Home />} />
<Route path="/posts" element={<Posts />} />
<Route path="/shopping-cart" element={<ShoppingCart />} />
<Route path="/relay-example" element={<RelayExample />} />
</Routes>Route Details:
| Path | Component | Description |
|---|---|---|
/ |
Home | Landing page with featured posts and Teek branding |
/posts |
Posts | All blog posts listing with pagination |
/shopping-cart |
ShoppingCart | Shopping cart demo with search and filtering |
/relay-example |
RelayExample | GraphQL/Relay data fetching demonstration |
Location: src/components/Header.tsx
Implementation:
- Uses anchor tags (
<a>) for navigation - Links match route paths exactly
- Active state via CSS (hover effects)
- No client-side routing hook usage (simple anchor tags)
Location: src/App.tsx
Pattern:
- Wrapped in
BrowserRouter(aliased as Router) - Routes component defines all routes
- Route elements are page components
- No nested routes currently implemented
Entry Point: src/index.tsx
- Wraps App in
RelayEnvironmentProvider - Wraps in
React.StrictMode - Uses
ReactDOM.createRoot()for concurrent rendering
Framework: Vitest
- Vite-native test runner
- Jest-compatible API
- Fast execution with worker threads
- Built-in watch mode
Renderer: React Testing Library
- Component-centric testing
- User-centric assertions
- No testing implementation details
- Accessible by role, text, label
Assertions: Jest DOM
toBeInTheDocument()toHaveTextContent()toHaveAttribute()toHaveClass()
Environment: jsdom
- Simulates browser DOM
- Lightweight alternative to real browser
- Sufficient for unit tests
Custom Render Function: src/test/utils.tsx
// Provides BrowserRouter automatically
// Includes all common providers
// Usage: render(<Component />) instead of rtlRender()
export { customRender as render }
// Re-exports all @testing-library/react exportsGlobal Setup: src/test/setupTests.ts
- Imports
@testing-library/jest-dom - Extends Vitest expect with matchers
- Mocks
window.matchMedia - Mocks
IntersectionObserver - Mocks
ResizeObserver - Filters console errors/warnings
- Auto-cleansup after each test
Wait Utility: src/test/utils.tsx
export const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));Mock Function: src/test/utils.tsx
export const createMockFunction = <T extends (...args: any[]) => any>(
implementation?: T
) => vi.fn(implementation);Naming Conventions:
*.test.ts- Unit tests*.test.tsx- Component tests*.spec.ts- Alternative naming- Location: Alongside source files
Test Structure:
import { describe, it, expect } from 'vitest';
import { render, screen } from '../test/utils';
import Component from './Component';
describe('Component', () => {
it('should render correctly', () => {
render(<Component prop="value" />);
expect(screen.getByText('expected')).toBeInTheDocument();
});
it('should handle interactions', async () => {
const user = userEvent.setup();
render(<Component />);
await user.click(screen.getByRole('button'));
// assertions
});
});Coverage Requirements:
- Minimum 70% for: lines, functions, branches, statements
- Excludes: node_modules, test files, generated files, config files
- Reports generated in
coverage/directory - Enforced in CI/CD pipeline
Component Mock:
// Simple component mock for testing parents
const MockComponent = () => <div>Mock</div>;Function Mock:
const handleClick = vi.fn();
render(<Component onClick={handleClick} />);
fireEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);API Mock (in tests):
- Use
vi.spyOn()to mock module functions - Use
vi.mock()to mock modules (requires hoisting) - Return mock data for async operations
Location: src/relay/Environment.ts
Configuration:
export const environment = new Environment({
network: Network.create(fetchQueryWithMock),
store: new Store(new RecordSource())
});Network Layer Options:
-
fetchQuery- Real GraphQL API calls- Points to
https://api.github.com/graphql - Requires Authorization header (commented out)
- Replace with actual GraphQL server
- Points to
-
fetchQueryWithMock- Development mock data- Returns Promise resolving after 300ms delay
- Simulates users and posts data
- Used for development without real API
Mock Data Structure:
const mockUsers = [
{ id: '1', name: 'Alice', email: 'alice@example.com', avatar: null }
];
const mockPosts = [
{
id: '1',
title: 'Hello Relay',
content: 'Sample post content',
author: { id: '1', name: 'Alice', email: 'alice@example.com' },
createdAt: new Date().toISOString()
}
];Pattern:
import { graphql, useLazyLoadQuery } from 'react-relay';
const data = useLazyLoadQuery<QueryType>(
graphql`
query QueryName($variable: Type!) {
field(arg: $variable) {
subfield
}
}
`,
{ variable: value }
);Compilation Process:
- Write GraphQL query with
graphqltag - Run
pnpm relayto compile - Generated types appear in
src/__generated__/ - Import generated types for type safety
Location: src/__generated__/
Naming Pattern: {QueryName}Query.graphql.ts
Usage:
import type { RelayExampleQuery } from '../__generated__/RelayExampleQuery.graphql';
const data = useLazyLoadQuery<RelayExampleQuery>(graphql`...`, {});Important:
- NEVER manually edit generated files
- Re-run
pnpm relayafter query changes - Include in version control (generated artifacts)
With Suspense:
import { Suspense } from 'react';
const PageWithData = () => (
<Suspense fallback={<LoadingUI />}>
<DataComponent />
</Suspense>
);Query in Component:
const Component = () => {
const data = useLazyLoadQuery<QueryType>(query, variables);
return <div>{data.field}</div>;
};Pattern: Define data at module level (outside component)
// Outside component - created once
const CONSTANT_DATA = [...];
// Inside component - reference only
const MyComponent = () => {
const items = CONSTANT_DATA; // No recreation
};Benefits:
- No recreation on each render
- Better memory efficiency
- Clearer code structure
Location: src/pages/ShoppingCart/allShoppingCartProducts.tsx
Data Structure:
export const allShoppingCartProducts: ProductItem[] = [
{
id: '001',
name: 'Apple',
category: Category.FreshFruit,
price: 8.5,
stock: 100,
description: 'Fresh red apples from Fuji'
},
// ... more products
];
// Type definition in interface.ts
export interface ProductItem {
id: string;
name: string;
category: Category;
price: number;
stock: number;
description?: string;
}
export enum Category {
FreshFruit = '新鲜水果',
MeatEggs = '肉禽蛋',
Vegetables = '蔬菜',
Others = '其他'
}Pattern: Async function returning Promise
async function fetchData(): Promise<MockData> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ /* data */ });
}, 300);
});
}Relay Mock (in Environment.ts):
- 300ms delay simulates network latency
- Checks operation text to determine data to return
- Conditional responses based on query content
- Create page component in
src/pages/PageName/ - Add route in
src/App.tsx - Add navigation link in
src/components/Header.tsx - Create tests if needed
- Commit changes
- Create component file in
src/components/ - Use
React.FC<Props>typing - Wrap in
React.memo() - Set
displayName - Create test file alongside
- Add JSDoc comments with
@file,@description,@example
- Write query using
graphqltag in component - Run
pnpm relayto compile - Import generated types
- Use
useLazyLoadQueryhook - Wrap component in Suspense for loading state
# All tests
pnpm test:run
# With coverage
pnpm test:coverage
# UI mode
pnpm test:uipnpm run build
# Output in dist/ directory- Follow the established component patterns (React.FC, memo, displayName)
- Use TypeScript interfaces for all props
- Use Tailwind CSS classes for styling
- Co-locate types and data with related functionality
- Write tests for new components
- Run
pnpm relayafter modifying GraphQL queries - Use the custom render function from
test/utils.tsx - Maintain 70% test coverage minimum
- Manually edit files in
src/__generated__/ - Use
anytype (useunknownor proper types) - Leave unused variables or parameters
- Use JavaScript-only imports in TypeScript files
- Skip type annotations on state and props
- Use CSS files when Tailwind classes suffice
- Mix different styling approaches unnecessarily
- Feature modules with co-located types and data
- Memoized components with displayName
- useCallback for callback props
- useMemo for expensive computations
- GraphQL queries compiled to types
- Test files alongside source files
- Custom render with BrowserRouter
- Check existing similar components for patterns
- Review
src/components/Header.tsxfor component structure - Review
src/pages/ShoppingCart/index.tsxfor state patterns - Review
src/pages/RelayExample.tsxfor GraphQL patterns - Review
src/components/Header.test.tsxfor test patterns
- Rsbuild: https://rsbuild.rs/llms.txt
- Rspack: https://rspack.rs/llms.txt
- React: https://react.dev/
- TypeScript: https://www.typescriptlang.org/docs/
- Relay: https://relay.dev/
- Vitest: https://vitest.dev/
- React Testing Library: https://testing-library.com/docs/react-testing-library/
- Tailwind CSS: https://tailwindcss.com/docs
- Ant Design: https://ant.design/components
- React Router: https://reactrouter.com/en/main