Skip to content

Commit 710030c

Browse files
committed
add skills
1 parent 0528f5d commit 710030c

212 files changed

Lines changed: 21424 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agent/skills/vercel-react-best-practices/AGENTS.md

Lines changed: 2516 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
name: vercel-react-best-practices
3+
description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
4+
license: MIT
5+
metadata:
6+
author: vercel
7+
version: "1.0.0"
8+
---
9+
10+
# Vercel React Best Practices
11+
12+
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
13+
14+
## When to Apply
15+
16+
Reference these guidelines when:
17+
- Writing new React components or Next.js pages
18+
- Implementing data fetching (client or server-side)
19+
- Reviewing code for performance issues
20+
- Refactoring existing React/Next.js code
21+
- Optimizing bundle size or load times
22+
23+
## Rule Categories by Priority
24+
25+
| Priority | Category | Impact | Prefix |
26+
|----------|----------|--------|--------|
27+
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
28+
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
29+
| 3 | Server-Side Performance | HIGH | `server-` |
30+
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
31+
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
32+
| 6 | Rendering Performance | MEDIUM | `rendering-` |
33+
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
34+
| 8 | Advanced Patterns | LOW | `advanced-` |
35+
36+
## Quick Reference
37+
38+
### 1. Eliminating Waterfalls (CRITICAL)
39+
40+
- `async-defer-await` - Move await into branches where actually used
41+
- `async-parallel` - Use Promise.all() for independent operations
42+
- `async-dependencies` - Use better-all for partial dependencies
43+
- `async-api-routes` - Start promises early, await late in API routes
44+
- `async-suspense-boundaries` - Use Suspense to stream content
45+
46+
### 2. Bundle Size Optimization (CRITICAL)
47+
48+
- `bundle-barrel-imports` - Import directly, avoid barrel files
49+
- `bundle-dynamic-imports` - Use next/dynamic for heavy components
50+
- `bundle-defer-third-party` - Load analytics/logging after hydration
51+
- `bundle-conditional` - Load modules only when feature is activated
52+
- `bundle-preload` - Preload on hover/focus for perceived speed
53+
54+
### 3. Server-Side Performance (HIGH)
55+
56+
- `server-cache-react` - Use React.cache() for per-request deduplication
57+
- `server-cache-lru` - Use LRU cache for cross-request caching
58+
- `server-serialization` - Minimize data passed to client components
59+
- `server-parallel-fetching` - Restructure components to parallelize fetches
60+
- `server-after-nonblocking` - Use after() for non-blocking operations
61+
62+
### 4. Client-Side Data Fetching (MEDIUM-HIGH)
63+
64+
- `client-swr-dedup` - Use SWR for automatic request deduplication
65+
- `client-event-listeners` - Deduplicate global event listeners
66+
67+
### 5. Re-render Optimization (MEDIUM)
68+
69+
- `rerender-defer-reads` - Don't subscribe to state only used in callbacks
70+
- `rerender-memo` - Extract expensive work into memoized components
71+
- `rerender-dependencies` - Use primitive dependencies in effects
72+
- `rerender-derived-state` - Subscribe to derived booleans, not raw values
73+
- `rerender-functional-setstate` - Use functional setState for stable callbacks
74+
- `rerender-lazy-state-init` - Pass function to useState for expensive values
75+
- `rerender-transitions` - Use startTransition for non-urgent updates
76+
77+
### 6. Rendering Performance (MEDIUM)
78+
79+
- `rendering-animate-svg-wrapper` - Animate div wrapper, not SVG element
80+
- `rendering-content-visibility` - Use content-visibility for long lists
81+
- `rendering-hoist-jsx` - Extract static JSX outside components
82+
- `rendering-svg-precision` - Reduce SVG coordinate precision
83+
- `rendering-hydration-no-flicker` - Use inline script for client-only data
84+
- `rendering-activity` - Use Activity component for show/hide
85+
- `rendering-conditional-render` - Use ternary, not && for conditionals
86+
87+
### 7. JavaScript Performance (LOW-MEDIUM)
88+
89+
- `js-batch-dom-css` - Group CSS changes via classes or cssText
90+
- `js-index-maps` - Build Map for repeated lookups
91+
- `js-cache-property-access` - Cache object properties in loops
92+
- `js-cache-function-results` - Cache function results in module-level Map
93+
- `js-cache-storage` - Cache localStorage/sessionStorage reads
94+
- `js-combine-iterations` - Combine multiple filter/map into one loop
95+
- `js-length-check-first` - Check array length before expensive comparison
96+
- `js-early-exit` - Return early from functions
97+
- `js-hoist-regexp` - Hoist RegExp creation outside loops
98+
- `js-min-max-loop` - Use loop for min/max instead of sort
99+
- `js-set-map-lookups` - Use Set/Map for O(1) lookups
100+
- `js-tosorted-immutable` - Use toSorted() for immutability
101+
102+
### 8. Advanced Patterns (LOW)
103+
104+
- `advanced-event-handler-refs` - Store event handlers in refs
105+
- `advanced-use-latest` - useLatest for stable callback refs
106+
107+
## How to Use
108+
109+
Read individual rule files for detailed explanations and code examples:
110+
111+
```
112+
rules/async-parallel.md
113+
rules/bundle-barrel-imports.md
114+
rules/_sections.md
115+
```
116+
117+
Each rule file contains:
118+
- Brief explanation of why it matters
119+
- Incorrect code example with explanation
120+
- Correct code example with explanation
121+
- Additional context and references
122+
123+
## Full Compiled Document
124+
125+
For the complete guide with all rules expanded: `AGENTS.md`
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
title: Store Event Handlers in Refs
3+
impact: LOW
4+
impactDescription: stable subscriptions
5+
tags: advanced, hooks, refs, event-handlers, optimization
6+
---
7+
8+
## Store Event Handlers in Refs
9+
10+
Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes.
11+
12+
**Incorrect (re-subscribes on every render):**
13+
14+
```tsx
15+
function useWindowEvent(event: string, handler: (e) => void) {
16+
useEffect(() => {
17+
window.addEventListener(event, handler)
18+
return () => window.removeEventListener(event, handler)
19+
}, [event, handler])
20+
}
21+
```
22+
23+
**Correct (stable subscription):**
24+
25+
```tsx
26+
function useWindowEvent(event: string, handler: (e) => void) {
27+
const handlerRef = useRef(handler)
28+
useEffect(() => {
29+
handlerRef.current = handler
30+
}, [handler])
31+
32+
useEffect(() => {
33+
const listener = (e) => handlerRef.current(e)
34+
window.addEventListener(event, listener)
35+
return () => window.removeEventListener(event, listener)
36+
}, [event])
37+
}
38+
```
39+
40+
**Alternative: use `useEffectEvent` if you're on latest React:**
41+
42+
```tsx
43+
import { useEffectEvent } from 'react'
44+
45+
function useWindowEvent(event: string, handler: (e) => void) {
46+
const onEvent = useEffectEvent(handler)
47+
48+
useEffect(() => {
49+
window.addEventListener(event, onEvent)
50+
return () => window.removeEventListener(event, onEvent)
51+
}, [event])
52+
}
53+
```
54+
55+
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: useLatest for Stable Callback Refs
3+
impact: LOW
4+
impactDescription: prevents effect re-runs
5+
tags: advanced, hooks, useLatest, refs, optimization
6+
---
7+
8+
## useLatest for Stable Callback Refs
9+
10+
Access latest values in callbacks without adding them to dependency arrays. Prevents effect re-runs while avoiding stale closures.
11+
12+
**Implementation:**
13+
14+
```typescript
15+
function useLatest<T>(value: T) {
16+
const ref = useRef(value)
17+
useLayoutEffect(() => {
18+
ref.current = value
19+
}, [value])
20+
return ref
21+
}
22+
```
23+
24+
**Incorrect (effect re-runs on every callback change):**
25+
26+
```tsx
27+
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
28+
const [query, setQuery] = useState('')
29+
30+
useEffect(() => {
31+
const timeout = setTimeout(() => onSearch(query), 300)
32+
return () => clearTimeout(timeout)
33+
}, [query, onSearch])
34+
}
35+
```
36+
37+
**Correct (stable effect, fresh callback):**
38+
39+
```tsx
40+
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
41+
const [query, setQuery] = useState('')
42+
const onSearchRef = useLatest(onSearch)
43+
44+
useEffect(() => {
45+
const timeout = setTimeout(() => onSearchRef.current(query), 300)
46+
return () => clearTimeout(timeout)
47+
}, [query])
48+
}
49+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Prevent Waterfall Chains in API Routes
3+
impact: CRITICAL
4+
impactDescription: 2-10× improvement
5+
tags: api-routes, server-actions, waterfalls, parallelization
6+
---
7+
8+
## Prevent Waterfall Chains in API Routes
9+
10+
In API routes and Server Actions, start independent operations immediately, even if you don't await them yet.
11+
12+
**Incorrect (config waits for auth, data waits for both):**
13+
14+
```typescript
15+
export async function GET(request: Request) {
16+
const session = await auth()
17+
const config = await fetchConfig()
18+
const data = await fetchData(session.user.id)
19+
return Response.json({ data, config })
20+
}
21+
```
22+
23+
**Correct (auth and config start immediately):**
24+
25+
```typescript
26+
export async function GET(request: Request) {
27+
const sessionPromise = auth()
28+
const configPromise = fetchConfig()
29+
const session = await sessionPromise
30+
const [config, data] = await Promise.all([
31+
configPromise,
32+
fetchData(session.user.id)
33+
])
34+
return Response.json({ data, config })
35+
}
36+
```
37+
38+
For operations with more complex dependency chains, use `better-all` to automatically maximize parallelism (see Dependency-Based Parallelization).
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
title: Defer Await Until Needed
3+
impact: HIGH
4+
impactDescription: avoids blocking unused code paths
5+
tags: async, await, conditional, optimization
6+
---
7+
8+
## Defer Await Until Needed
9+
10+
Move `await` operations into the branches where they're actually used to avoid blocking code paths that don't need them.
11+
12+
**Incorrect (blocks both branches):**
13+
14+
```typescript
15+
async function handleRequest(userId: string, skipProcessing: boolean) {
16+
const userData = await fetchUserData(userId)
17+
18+
if (skipProcessing) {
19+
// Returns immediately but still waited for userData
20+
return { skipped: true }
21+
}
22+
23+
// Only this branch uses userData
24+
return processUserData(userData)
25+
}
26+
```
27+
28+
**Correct (only blocks when needed):**
29+
30+
```typescript
31+
async function handleRequest(userId: string, skipProcessing: boolean) {
32+
if (skipProcessing) {
33+
// Returns immediately without waiting
34+
return { skipped: true }
35+
}
36+
37+
// Fetch only when needed
38+
const userData = await fetchUserData(userId)
39+
return processUserData(userData)
40+
}
41+
```
42+
43+
**Another example (early return optimization):**
44+
45+
```typescript
46+
// Incorrect: always fetches permissions
47+
async function updateResource(resourceId: string, userId: string) {
48+
const permissions = await fetchPermissions(userId)
49+
const resource = await getResource(resourceId)
50+
51+
if (!resource) {
52+
return { error: 'Not found' }
53+
}
54+
55+
if (!permissions.canEdit) {
56+
return { error: 'Forbidden' }
57+
}
58+
59+
return await updateResourceData(resource, permissions)
60+
}
61+
62+
// Correct: fetches only when needed
63+
async function updateResource(resourceId: string, userId: string) {
64+
const resource = await getResource(resourceId)
65+
66+
if (!resource) {
67+
return { error: 'Not found' }
68+
}
69+
70+
const permissions = await fetchPermissions(userId)
71+
72+
if (!permissions.canEdit) {
73+
return { error: 'Forbidden' }
74+
}
75+
76+
return await updateResourceData(resource, permissions)
77+
}
78+
```
79+
80+
This optimization is especially valuable when the skipped branch is frequently taken, or when the deferred operation is expensive.

0 commit comments

Comments
 (0)