init
This commit is contained in:
403
.opencode/skills/frontend-development/SKILL.md
Normal file
403
.opencode/skills/frontend-development/SKILL.md
Normal file
@@ -0,0 +1,403 @@
|
||||
---
|
||||
name: ck:frontend-development
|
||||
description: Build React/TypeScript frontends with modern patterns. Use for components, Suspense, lazy loading, useSuspenseQuery, MUI v7 styling, TanStack Router, performance optimization.
|
||||
argument-hint: "[component or feature]"
|
||||
metadata:
|
||||
author: claudekit
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# Frontend Development Guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
Comprehensive guide for modern React development, emphasizing Suspense-based data fetching, lazy loading, proper file organization, and performance optimization.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Creating new components or pages
|
||||
- Building new features
|
||||
- Fetching data with TanStack Query
|
||||
- Setting up routing with TanStack Router
|
||||
- Styling components with MUI v7
|
||||
- Performance optimization
|
||||
- Organizing frontend code
|
||||
- TypeScript best practices
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### New Component Checklist
|
||||
|
||||
Creating a component? Follow this checklist:
|
||||
|
||||
- [ ] Use `React.FC<Props>` pattern with TypeScript
|
||||
- [ ] Lazy load if heavy component: `React.lazy(() => import())`
|
||||
- [ ] Wrap in `<SuspenseLoader>` for loading states
|
||||
- [ ] Use `useSuspenseQuery` for data fetching
|
||||
- [ ] Import aliases: `@/`, `~types`, `~components`, `~features`
|
||||
- [ ] Styles: Inline if <100 lines, separate file if >100 lines
|
||||
- [ ] Use `useCallback` for event handlers passed to children
|
||||
- [ ] Default export at bottom
|
||||
- [ ] No early returns with loading spinners
|
||||
- [ ] Use `useMuiSnackbar` for user notifications
|
||||
|
||||
### New Feature Checklist
|
||||
|
||||
Creating a feature? Set up this structure:
|
||||
|
||||
- [ ] Create `features/{feature-name}/` directory
|
||||
- [ ] Create subdirectories: `api/`, `components/`, `hooks/`, `helpers/`, `types/`
|
||||
- [ ] Create API service file: `api/{feature}Api.ts`
|
||||
- [ ] Set up TypeScript types in `types/`
|
||||
- [ ] Create route in `routes/{feature-name}/index.tsx`
|
||||
- [ ] Lazy load feature components
|
||||
- [ ] Use Suspense boundaries
|
||||
- [ ] Export public API from feature `index.ts`
|
||||
|
||||
---
|
||||
|
||||
## Import Aliases Quick Reference
|
||||
|
||||
| Alias | Resolves To | Example |
|
||||
|-------|-------------|---------|
|
||||
| `@/` | `src/` | `import { apiClient } from '@/lib/apiClient'` |
|
||||
| `~types` | `src/types` | `import type { User } from '~types/user'` |
|
||||
| `~components` | `src/components` | `import { SuspenseLoader } from '~components/SuspenseLoader'` |
|
||||
| `~features` | `src/features` | `import { authApi } from '~features/auth'` |
|
||||
|
||||
Defined in: [vite.config.ts](../../vite.config.ts) lines 180-185
|
||||
|
||||
---
|
||||
|
||||
## Common Imports Cheatsheet
|
||||
|
||||
```typescript
|
||||
// React & Lazy Loading
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
const Heavy = React.lazy(() => import('./Heavy'));
|
||||
|
||||
// MUI Components
|
||||
import { Box, Paper, Typography, Button, Grid } from '@mui/material';
|
||||
import type { SxProps, Theme } from '@mui/material';
|
||||
|
||||
// TanStack Query (Suspense)
|
||||
import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
// TanStack Router
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
|
||||
// Project Components
|
||||
import { SuspenseLoader } from '~components/SuspenseLoader';
|
||||
|
||||
// Hooks
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';
|
||||
|
||||
// Types
|
||||
import type { Post } from '~types/post';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Topic Guides
|
||||
|
||||
### 🎨 Component Patterns
|
||||
|
||||
**Modern React components use:**
|
||||
- `React.FC<Props>` for type safety
|
||||
- `React.lazy()` for code splitting
|
||||
- `SuspenseLoader` for loading states
|
||||
- Named const + default export pattern
|
||||
|
||||
**Key Concepts:**
|
||||
- Lazy load heavy components (DataGrid, charts, editors)
|
||||
- Always wrap lazy components in Suspense
|
||||
- Use SuspenseLoader component (with fade animation)
|
||||
- Component structure: Props → Hooks → Handlers → Render → Export
|
||||
|
||||
**[📖 Complete Guide: resources/component-patterns.md](resources/component-patterns.md)**
|
||||
|
||||
---
|
||||
|
||||
### 📊 Data Fetching
|
||||
|
||||
**PRIMARY PATTERN: useSuspenseQuery**
|
||||
- Use with Suspense boundaries
|
||||
- Cache-first strategy (check grid cache before API)
|
||||
- Replaces `isLoading` checks
|
||||
- Type-safe with generics
|
||||
|
||||
**API Service Layer:**
|
||||
- Create `features/{feature}/api/{feature}Api.ts`
|
||||
- Use `apiClient` axios instance
|
||||
- Centralized methods per feature
|
||||
- Route format: `/form/route` (NOT `/api/form/route`)
|
||||
|
||||
**[📖 Complete Guide: resources/data-fetching.md](resources/data-fetching.md)**
|
||||
|
||||
---
|
||||
|
||||
### 📁 File Organization
|
||||
|
||||
**features/ vs components/:**
|
||||
- `features/`: Domain-specific (posts, comments, auth)
|
||||
- `components/`: Truly reusable (SuspenseLoader, CustomAppBar)
|
||||
|
||||
**Feature Subdirectories:**
|
||||
```
|
||||
features/
|
||||
my-feature/
|
||||
api/ # API service layer
|
||||
components/ # Feature components
|
||||
hooks/ # Custom hooks
|
||||
helpers/ # Utility functions
|
||||
types/ # TypeScript types
|
||||
```
|
||||
|
||||
**[📖 Complete Guide: resources/file-organization.md](resources/file-organization.md)**
|
||||
|
||||
---
|
||||
|
||||
### 🎨 Styling
|
||||
|
||||
**Inline vs Separate:**
|
||||
- <100 lines: Inline `const styles: Record<string, SxProps<Theme>>`
|
||||
- >100 lines: Separate `.styles.ts` file
|
||||
|
||||
**Primary Method:**
|
||||
- Use `sx` prop for MUI components
|
||||
- Type-safe with `SxProps<Theme>`
|
||||
- Theme access: `(theme) => theme.palette.primary.main`
|
||||
|
||||
**MUI v7 Grid:**
|
||||
```typescript
|
||||
<Grid size={{ xs: 12, md: 6 }}> // ✅ v7 syntax
|
||||
<Grid xs={12} md={6}> // ❌ Old syntax
|
||||
```
|
||||
|
||||
**[📖 Complete Guide: resources/styling-guide.md](resources/styling-guide.md)**
|
||||
|
||||
---
|
||||
|
||||
### 🛣️ Routing
|
||||
|
||||
**TanStack Router - Folder-Based:**
|
||||
- Directory: `routes/my-route/index.tsx`
|
||||
- Lazy load components
|
||||
- Use `createFileRoute`
|
||||
- Breadcrumb data in loader
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { lazy } from 'react';
|
||||
|
||||
const MyPage = lazy(() => import('@/features/my-feature/components/MyPage'));
|
||||
|
||||
export const Route = createFileRoute('/my-route/')({
|
||||
component: MyPage,
|
||||
loader: () => ({ crumb: 'My Route' }),
|
||||
});
|
||||
```
|
||||
|
||||
**[📖 Complete Guide: resources/routing-guide.md](resources/routing-guide.md)**
|
||||
|
||||
---
|
||||
|
||||
### ⏳ Loading & Error States
|
||||
|
||||
**CRITICAL RULE: No Early Returns**
|
||||
|
||||
```typescript
|
||||
// ❌ NEVER - Causes layout shift
|
||||
if (isLoading) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
// ✅ ALWAYS - Consistent layout
|
||||
<SuspenseLoader>
|
||||
<Content />
|
||||
</SuspenseLoader>
|
||||
```
|
||||
|
||||
**Why:** Prevents Cumulative Layout Shift (CLS), better UX
|
||||
|
||||
**Error Handling:**
|
||||
- Use `useMuiSnackbar` for user feedback
|
||||
- NEVER `react-toastify`
|
||||
- TanStack Query `onError` callbacks
|
||||
|
||||
**[📖 Complete Guide: resources/loading-and-error-states.md](resources/loading-and-error-states.md)**
|
||||
|
||||
---
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
**Optimization Patterns:**
|
||||
- `useMemo`: Expensive computations (filter, sort, map)
|
||||
- `useCallback`: Event handlers passed to children
|
||||
- `React.memo`: Expensive components
|
||||
- Debounced search (300-500ms)
|
||||
- Memory leak prevention (cleanup in useEffect)
|
||||
|
||||
**[📖 Complete Guide: resources/performance.md](resources/performance.md)**
|
||||
|
||||
---
|
||||
|
||||
### 📘 TypeScript
|
||||
|
||||
**Standards:**
|
||||
- Strict mode, no `any` type
|
||||
- Explicit return types on functions
|
||||
- Type imports: `import type { User } from '~types/user'`
|
||||
- Component prop interfaces with JSDoc
|
||||
|
||||
**[📖 Complete Guide: resources/typescript-standards.md](resources/typescript-standards.md)**
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Common Patterns
|
||||
|
||||
**Covered Topics:**
|
||||
- React Hook Form with Zod validation
|
||||
- DataGrid wrapper contracts
|
||||
- Dialog component standards
|
||||
- `useAuth` hook for current user
|
||||
- Mutation patterns with cache invalidation
|
||||
|
||||
**[📖 Complete Guide: resources/common-patterns.md](resources/common-patterns.md)**
|
||||
|
||||
---
|
||||
|
||||
### 📚 Complete Examples
|
||||
|
||||
**Full working examples:**
|
||||
- Modern component with all patterns
|
||||
- Complete feature structure
|
||||
- API service layer
|
||||
- Route with lazy loading
|
||||
- Suspense + useSuspenseQuery
|
||||
- Form with validation
|
||||
|
||||
**[📖 Complete Guide: resources/complete-examples.md](resources/complete-examples.md)**
|
||||
|
||||
---
|
||||
|
||||
## Navigation Guide
|
||||
|
||||
| Need to... | Read this resource |
|
||||
|------------|-------------------|
|
||||
| Create a component | [component-patterns.md](resources/component-patterns.md) |
|
||||
| Fetch data | [data-fetching.md](resources/data-fetching.md) |
|
||||
| Organize files/folders | [file-organization.md](resources/file-organization.md) |
|
||||
| Style components | [styling-guide.md](resources/styling-guide.md) |
|
||||
| Set up routing | [routing-guide.md](resources/routing-guide.md) |
|
||||
| Handle loading/errors | [loading-and-error-states.md](resources/loading-and-error-states.md) |
|
||||
| Optimize performance | [performance.md](resources/performance.md) |
|
||||
| TypeScript types | [typescript-standards.md](resources/typescript-standards.md) |
|
||||
| Forms/Auth/DataGrid | [common-patterns.md](resources/common-patterns.md) |
|
||||
| See full examples | [complete-examples.md](resources/complete-examples.md) |
|
||||
|
||||
---
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **Lazy Load Everything Heavy**: Routes, DataGrid, charts, editors
|
||||
2. **Suspense for Loading**: Use SuspenseLoader, not early returns
|
||||
3. **useSuspenseQuery**: Primary data fetching pattern for new code
|
||||
4. **Features are Organized**: api/, components/, hooks/, helpers/ subdirs
|
||||
5. **Styles Based on Size**: <100 inline, >100 separate
|
||||
6. **Import Aliases**: Use @/, ~types, ~components, ~features
|
||||
7. **No Early Returns**: Prevents layout shift
|
||||
8. **useMuiSnackbar**: For all user notifications
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference: File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
features/
|
||||
my-feature/
|
||||
api/
|
||||
myFeatureApi.ts # API service
|
||||
components/
|
||||
MyFeature.tsx # Main component
|
||||
SubComponent.tsx # Related components
|
||||
hooks/
|
||||
useMyFeature.ts # Custom hooks
|
||||
useSuspenseMyFeature.ts # Suspense hooks
|
||||
helpers/
|
||||
myFeatureHelpers.ts # Utilities
|
||||
types/
|
||||
index.ts # TypeScript types
|
||||
index.ts # Public exports
|
||||
|
||||
components/
|
||||
SuspenseLoader/
|
||||
SuspenseLoader.tsx # Reusable loader
|
||||
CustomAppBar/
|
||||
CustomAppBar.tsx # Reusable app bar
|
||||
|
||||
routes/
|
||||
my-route/
|
||||
index.tsx # Route component
|
||||
create/
|
||||
index.tsx # Nested route
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Modern Component Template (Quick Copy)
|
||||
|
||||
```typescript
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Box, Paper } from '@mui/material';
|
||||
import { useSuspenseQuery } from '@tanstack/react-query';
|
||||
import { featureApi } from '../api/featureApi';
|
||||
import type { FeatureData } from '~types/feature';
|
||||
|
||||
interface MyComponentProps {
|
||||
id: number;
|
||||
onAction?: () => void;
|
||||
}
|
||||
|
||||
export const MyComponent: React.FC<MyComponentProps> = ({ id, onAction }) => {
|
||||
const [state, setState] = useState<string>('');
|
||||
|
||||
const { data } = useSuspenseQuery({
|
||||
queryKey: ['feature', id],
|
||||
queryFn: () => featureApi.getFeature(id),
|
||||
});
|
||||
|
||||
const handleAction = useCallback(() => {
|
||||
setState('updated');
|
||||
onAction?.();
|
||||
}, [onAction]);
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Paper sx={{ p: 3 }}>
|
||||
{/* Content */}
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
For complete examples, see [resources/complete-examples.md](resources/complete-examples.md)
|
||||
|
||||
---
|
||||
|
||||
## Related Skills
|
||||
|
||||
- **error-tracking**: Error tracking with Sentry (applies to frontend too)
|
||||
- **backend-dev-guidelines**: Backend API patterns that frontend consumes
|
||||
|
||||
---
|
||||
|
||||
**Skill Status**: Modular structure with progressive loading for optimal context management
|
||||
Reference in New Issue
Block a user