ai-workflow-init 6.6.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,15 @@
1
1
  ---
2
2
  name: react-best-practices
3
3
  description: |
4
- React and Next.js performance optimization guidelines from Vercel Engineering.
5
- Contains 45 rules across 8 categories, prioritized by impact.
4
+ React and Next.js performance optimization (NOT styling/visual design).
5
+ Contains rules for async patterns, bundle optimization, and rendering performance.
6
6
 
7
- ALWAYS load when working with React/Next.js code:
8
- - Writing new React components or Next.js pages
7
+ Use when working with React/Next.js performance:
9
8
  - Implementing data fetching (client or server-side)
10
- - Reviewing code for performance issues
11
- - Refactoring existing React/Next.js code
12
9
  - Optimizing bundle size or load times
13
10
  - Working with async operations and Promise handling
14
11
  - Implementing Suspense boundaries or streaming
12
+ - Reviewing code for performance issues
15
13
 
16
14
  Keywords: React, Next.js, performance, optimization, bundle, async, Promise,
17
15
  waterfall, rerender, memo, useMemo, useCallback, Suspense, RSC,
@@ -20,7 +18,8 @@ description: |
20
18
  Do NOT load for:
21
19
  - Non-React projects (Vue, Angular, Svelte, etc.)
22
20
  - Backend-only code without React integration
23
- - Pure CSS/styling work (use frontend-design-fundamentals)
21
+ - Pure CSS/styling/visual design work (use frontend-design-fundamentals)
22
+ - UI component styling, colors, spacing (use frontend-design-fundamentals)
24
23
 
25
24
  Works with other skills:
26
25
  - frontend-design-fundamentals: For UI/styling best practices
@@ -29,458 +28,67 @@ description: |
29
28
 
30
29
  # React Best Practices
31
30
 
32
- Comprehensive performance optimization guide for React and Next.js applications.
33
-
34
- ---
35
-
36
- ## Rule Categories by Priority
37
-
38
- | Priority | Category | Impact | Prefix |
39
- |----------|----------|--------|--------|
40
- | 1 | Eliminating Waterfalls | CRITICAL | `async-` |
41
- | 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
42
- | 3 | Server-Side Performance | HIGH | `server-` |
43
- | 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
44
- | 5 | Re-render Optimization | MEDIUM | `rerender-` |
45
- | 6 | Rendering Performance | MEDIUM | `rendering-` |
46
- | 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
47
- | 8 | Advanced Patterns | LOW | `advanced-` |
48
-
49
- ---
50
-
51
- ## 1. Eliminating Waterfalls (CRITICAL)
52
-
53
- Waterfalls are the #1 performance killer. Each sequential await adds full network latency.
54
-
55
- ### Promise.all() for Independent Operations
56
-
57
- **Impact:** 2-10× improvement
58
-
59
- When async operations have no interdependencies, execute them concurrently.
60
-
61
- **❌ Incorrect (sequential execution, 3 round trips):**
62
-
63
- ```typescript
64
- const user = await fetchUser()
65
- const posts = await fetchPosts()
66
- const comments = await fetchComments()
67
- ```
68
-
69
- **✅ Correct (parallel execution, 1 round trip):**
70
-
71
- ```typescript
72
- const [user, posts, comments] = await Promise.all([
73
- fetchUser(),
74
- fetchPosts(),
75
- fetchComments()
76
- ])
77
- ```
78
-
79
- ### Strategic Suspense Boundaries
80
-
81
- **Impact:** Faster initial paint
82
-
83
- Instead of awaiting data before returning JSX, use Suspense to show wrapper UI faster.
84
-
85
- **❌ Incorrect (wrapper blocked by data fetching):**
86
-
87
- ```tsx
88
- async function Page() {
89
- const data = await fetchData() // Blocks entire page
90
-
91
- return (
92
- <div>
93
- <div>Sidebar</div>
94
- <div>Header</div>
95
- <div>
96
- <DataDisplay data={data} />
97
- </div>
98
- <div>Footer</div>
99
- </div>
100
- )
101
- }
102
- ```
103
-
104
- **✅ Correct (wrapper shows immediately, data streams in):**
105
-
106
- ```tsx
107
- function Page() {
108
- return (
109
- <div>
110
- <div>Sidebar</div>
111
- <div>Header</div>
112
- <div>
113
- <Suspense fallback={<Skeleton />}>
114
- <DataDisplay />
115
- </Suspense>
116
- </div>
117
- <div>Footer</div>
118
- </div>
119
- )
120
- }
121
-
122
- async function DataDisplay() {
123
- const data = await fetchData() // Only blocks this component
124
- return <div>{data.content}</div>
125
- }
126
- ```
127
-
128
- **Alternative (share promise across components):**
129
-
130
- ```tsx
131
- function Page() {
132
- const dataPromise = fetchData() // Start fetch immediately, don't await
133
-
134
- return (
135
- <div>
136
- <div>Sidebar</div>
137
- <Suspense fallback={<Skeleton />}>
138
- <DataDisplay dataPromise={dataPromise} />
139
- <DataSummary dataPromise={dataPromise} />
140
- </Suspense>
141
- </div>
142
- )
143
- }
144
-
145
- function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
146
- const data = use(dataPromise) // Unwraps the promise
147
- return <div>{data.content}</div>
148
- }
149
- ```
150
-
151
- ---
152
-
153
- ## 2. Bundle Size Optimization (CRITICAL)
154
-
155
- Reducing initial bundle size improves Time to Interactive and Largest Contentful Paint.
156
-
157
- ### Avoid Barrel File Imports
158
-
159
- **Impact:** 200-800ms import cost, slow builds
160
-
161
- Import directly from source files instead of barrel files.
162
-
163
- **❌ Incorrect (imports entire library):**
164
-
165
- ```tsx
166
- import { Check, X, Menu } from 'lucide-react'
167
- // Loads 1,583 modules, takes ~2.8s extra in dev
168
-
169
- import { Button, TextField } from '@mui/material'
170
- // Loads 2,225 modules, takes ~4.2s extra in dev
171
- ```
172
-
173
- **✅ Correct (imports only what you need):**
174
-
175
- ```tsx
176
- import Check from 'lucide-react/dist/esm/icons/check'
177
- import X from 'lucide-react/dist/esm/icons/x'
178
- import Menu from 'lucide-react/dist/esm/icons/menu'
179
-
180
- import Button from '@mui/material/Button'
181
- import TextField from '@mui/material/TextField'
182
- ```
183
-
184
- **Alternative (Next.js 13.5+):**
185
-
186
- ```js
187
- // next.config.js
188
- module.exports = {
189
- experimental: {
190
- optimizePackageImports: ['lucide-react', '@mui/material']
191
- }
192
- }
193
- ```
194
-
195
- **Commonly affected libraries:** `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `date-fns`.
196
-
197
- ### Dynamic Imports for Heavy Components
198
-
199
- **Impact:** Directly affects TTI and LCP
200
-
201
- Use `next/dynamic` to lazy-load large components not needed on initial render.
202
-
203
- **❌ Incorrect (Monaco bundles with main chunk ~300KB):**
204
-
205
- ```tsx
206
- import { MonacoEditor } from './monaco-editor'
207
-
208
- function CodePanel({ code }: { code: string }) {
209
- return <MonacoEditor value={code} />
210
- }
211
- ```
212
-
213
- **✅ Correct (Monaco loads on demand):**
214
-
215
- ```tsx
216
- import dynamic from 'next/dynamic'
217
-
218
- const MonacoEditor = dynamic(
219
- () => import('./monaco-editor').then(m => m.MonacoEditor),
220
- { ssr: false }
221
- )
222
-
223
- function CodePanel({ code }: { code: string }) {
224
- return <MonacoEditor value={code} />
225
- }
226
- ```
227
-
228
- ---
229
-
230
- ## 3. Server-Side Performance (HIGH)
231
-
232
- Optimizing server-side rendering reduces response times.
233
-
234
- ### Per-Request Deduplication with React.cache()
235
-
236
- **Impact:** Deduplicates within request
237
-
238
- Use `React.cache()` for server-side request deduplication.
239
-
240
- ```typescript
241
- import { cache } from 'react'
31
+ Performance optimization guide for React and Next.js applications.
242
32
 
243
- export const getCurrentUser = cache(async () => {
244
- const session = await auth()
245
- if (!session?.user?.id) return null
246
- return await db.user.findUnique({
247
- where: { id: session.user.id }
248
- })
249
- })
250
- ```
251
-
252
- **Avoid inline objects as arguments** - use primitives for cache hits:
253
-
254
- ```typescript
255
- // ❌ Always cache miss
256
- const getUser = cache(async (params: { uid: number }) => {...})
257
- getUser({ uid: 1 })
258
- getUser({ uid: 1 }) // Cache miss, runs query again
259
-
260
- // ✅ Cache hit
261
- const getUser = cache(async (uid: number) => {...})
262
- getUser(1)
263
- getUser(1) // Cache hit, returns cached result
264
- ```
265
-
266
- **Note:** Next.js `fetch` has automatic memoization. Use `React.cache()` for:
267
- - Database queries (Prisma, Drizzle, etc.)
268
- - Heavy computations
269
- - Authentication checks
270
- - File system operations
271
-
272
- ### Parallel Data Fetching with Component Composition
273
-
274
- **Impact:** Eliminates server-side waterfalls
275
-
276
- React Server Components execute sequentially within a tree. Restructure with composition to parallelize.
277
-
278
- **❌ Incorrect (Sidebar waits for Page's fetch):**
279
-
280
- ```tsx
281
- export default async function Page() {
282
- const header = await fetchHeader()
283
- return (
284
- <div>
285
- <div>{header}</div>
286
- <Sidebar />
287
- </div>
288
- )
289
- }
290
-
291
- async function Sidebar() {
292
- const items = await fetchSidebarItems()
293
- return <nav>{items.map(renderItem)}</nav>
294
- }
295
- ```
296
-
297
- **✅ Correct (both fetch simultaneously):**
298
-
299
- ```tsx
300
- async function Header() {
301
- const data = await fetchHeader()
302
- return <div>{data}</div>
303
- }
304
-
305
- async function Sidebar() {
306
- const items = await fetchSidebarItems()
307
- return <nav>{items.map(renderItem)}</nav>
308
- }
309
-
310
- export default function Page() {
311
- return (
312
- <div>
313
- <Header />
314
- <Sidebar />
315
- </div>
316
- )
317
- }
318
- ```
319
-
320
- ---
321
-
322
- ## 4. Client-Side Data Fetching (MEDIUM-HIGH)
323
-
324
- ### Use SWR for Automatic Deduplication
325
-
326
- **Impact:** Automatic deduplication and caching
327
-
328
- **❌ Incorrect (no deduplication, each instance fetches):**
329
-
330
- ```tsx
331
- function UserList() {
332
- const [users, setUsers] = useState([])
333
- useEffect(() => {
334
- fetch('/api/users')
335
- .then(r => r.json())
336
- .then(setUsers)
337
- }, [])
338
- }
339
- ```
340
-
341
- **✅ Correct (multiple instances share one request):**
342
-
343
- ```tsx
344
- import useSWR from 'swr'
345
-
346
- function UserList() {
347
- const { data: users } = useSWR('/api/users', fetcher)
348
- }
349
- ```
33
+ For detailed code examples, see `references/code-patterns.md`.
350
34
 
351
35
  ---
352
36
 
353
- ## 5. Re-render Optimization (MEDIUM)
354
-
355
- Reducing unnecessary re-renders minimizes wasted computation.
356
-
357
- ### Extract to Memoized Components
358
-
359
- **Impact:** Enables early returns
360
-
361
- **❌ Incorrect (computes avatar even when loading):**
362
-
363
- ```tsx
364
- function Profile({ user, loading }: Props) {
365
- const avatar = useMemo(() => {
366
- const id = computeAvatarId(user)
367
- return <Avatar id={id} />
368
- }, [user])
369
-
370
- if (loading) return <Skeleton />
371
- return <div>{avatar}</div>
372
- }
373
- ```
374
-
375
- **✅ Correct (skips computation when loading):**
376
-
377
- ```tsx
378
- const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
379
- const id = useMemo(() => computeAvatarId(user), [user])
380
- return <Avatar id={id} />
381
- })
382
-
383
- function Profile({ user, loading }: Props) {
384
- if (loading) return <Skeleton />
385
- return (
386
- <div>
387
- <UserAvatar user={user} />
388
- </div>
389
- )
390
- }
391
- ```
392
-
393
- **Note:** If React Compiler is enabled, manual memoization is not necessary.
394
-
395
- ### Subscribe to Derived State
396
-
397
- **Impact:** Reduces re-render frequency
398
-
399
- **❌ Incorrect (re-renders on every pixel change):**
400
-
401
- ```tsx
402
- function Sidebar() {
403
- const width = useWindowWidth() // updates continuously
404
- const isMobile = width < 768
405
- return <nav className={isMobile ? 'mobile' : 'desktop'} />
406
- }
407
- ```
408
-
409
- **✅ Correct (re-renders only when boolean changes):**
37
+ ## Rule Categories by Priority
410
38
 
411
- ```tsx
412
- function Sidebar() {
413
- const isMobile = useMediaQuery('(max-width: 767px)')
414
- return <nav className={isMobile ? 'mobile' : 'desktop'} />
415
- }
416
- ```
39
+ | Priority | Category | Impact |
40
+ |----------|----------|--------|
41
+ | 1 | Eliminating Waterfalls | CRITICAL |
42
+ | 2 | Bundle Size Optimization | CRITICAL |
43
+ | 3 | Server-Side Performance | HIGH |
44
+ | 4 | Client-Side Data Fetching | MEDIUM-HIGH |
45
+ | 5 | Re-render Optimization | MEDIUM |
46
+ | 6 | Rendering Performance | MEDIUM |
47
+ | 7 | JavaScript Performance | LOW-MEDIUM |
417
48
 
418
49
  ---
419
50
 
420
- ## 6. Rendering Performance (MEDIUM)
421
-
422
- ### Use Explicit Conditional Rendering
51
+ ## Quick Rules Summary
423
52
 
424
- **Impact:** Prevents rendering 0 or NaN
53
+ ### 1. Eliminating Waterfalls (CRITICAL)
425
54
 
426
- **❌ Incorrect (renders "0" when count is 0):**
55
+ - **Use `Promise.all()`** for independent async operations
56
+ - **Use Suspense boundaries** to show wrapper UI faster
57
+ - **Don't await** in parent when child can fetch independently
427
58
 
428
- ```tsx
429
- function Badge({ count }: { count: number }) {
430
- return (
431
- <div>
432
- {count && <span className="badge">{count}</span>}
433
- </div>
434
- )
435
- }
436
- // When count = 0, renders: <div>0</div>
437
- ```
59
+ ### 2. Bundle Size (CRITICAL)
438
60
 
439
- **✅ Correct (renders nothing when count is 0):**
61
+ - **Avoid barrel imports** - import directly from source files
62
+ - **Use `next/dynamic`** for heavy components (Monaco, charts, etc.)
63
+ - **Configure `optimizePackageImports`** in Next.js 13.5+
64
+ - **Affected libs**: lucide-react, @mui/material, lodash, date-fns
440
65
 
441
- ```tsx
442
- function Badge({ count }: { count: number }) {
443
- return (
444
- <div>
445
- {count > 0 ? <span className="badge">{count}</span> : null}
446
- </div>
447
- )
448
- }
449
- ```
66
+ ### 3. Server-Side Performance (HIGH)
450
67
 
451
- ---
68
+ - **Use `React.cache()`** for server-side request deduplication
69
+ - **Use primitives** as cache arguments (not objects)
70
+ - **Restructure RSC** for parallel data fetching via composition
452
71
 
453
- ## 7. JavaScript Performance (LOW-MEDIUM)
72
+ ### 4. Client-Side Data Fetching (MEDIUM-HIGH)
454
73
 
455
- Micro-optimizations for hot paths.
74
+ - **Use SWR** for automatic deduplication and caching
75
+ - **Avoid useEffect + fetch** pattern
456
76
 
457
- ### Build Index Maps for Repeated Lookups
77
+ ### 5. Re-render Optimization (MEDIUM)
458
78
 
459
- **Impact:** 1M ops 2K ops
79
+ - **Extract to memoized components** for early returns
80
+ - **Subscribe to derived booleans**, not raw values
81
+ - **Note**: React Compiler makes manual memo unnecessary
460
82
 
461
- **❌ Incorrect (O(n) per lookup):**
83
+ ### 6. Rendering Performance (MEDIUM)
462
84
 
463
- ```typescript
464
- function processOrders(orders: Order[], users: User[]) {
465
- return orders.map(order => ({
466
- ...order,
467
- user: users.find(u => u.id === order.userId)
468
- }))
469
- }
470
- ```
85
+ - **Use explicit ternary** for number conditionals
86
+ - `count && <X/>` renders "0" when count is 0
87
+ - Use `count > 0 ? <X/> : null` instead
471
88
 
472
- **✅ Correct (O(1) per lookup):**
89
+ ### 7. JavaScript Performance (LOW-MEDIUM)
473
90
 
474
- ```typescript
475
- function processOrders(orders: Order[], users: User[]) {
476
- const userById = new Map(users.map(u => [u.id, u]))
477
-
478
- return orders.map(order => ({
479
- ...order,
480
- user: userById.get(order.userId)
481
- }))
482
- }
483
- ```
91
+ - **Build Map/Set** for repeated lookups (O(1) vs O(n))
484
92
 
485
93
  ---
486
94
 
@@ -517,3 +125,5 @@ function processOrders(orders: Order[], users: User[]) {
517
125
  - [SWR documentation](https://swr.vercel.app)
518
126
  - [Next.js Package Imports Optimization](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
519
127
  - [React Compiler](https://react.dev/learn/react-compiler)
128
+
129
+ For detailed code patterns and examples: `references/code-patterns.md`