cursor-kit-cli 1.2.0-beta → 1.2.0-beta.3
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.
- package/bin/cursor-reinstall-instance.sh +102 -0
- package/dist/cli.cjs +366 -69
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +367 -70
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/commands/docs.md +5 -3
- package/templates/commands/explain.md +5 -3
- package/templates/commands/fix.md +5 -3
- package/templates/commands/implement.md +5 -3
- package/templates/commands/refactor.md +5 -3
- package/templates/commands/review.md +5 -3
- package/templates/commands/test.md +5 -3
- package/templates/manifest.json +11 -8
- package/templates/rules/git.mdc +0 -2
- package/templates/rules/toc.mdc +17 -9
- package/templates/skills/aesthetic/SKILL.md +121 -0
- package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
- package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
- package/templates/skills/aesthetic/references/design-principles.md +62 -0
- package/templates/skills/aesthetic/references/design-resources.md +75 -0
- package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
- package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
- package/templates/skills/backend-development/SKILL.mdc +95 -0
- package/templates/skills/backend-development/references/backend-api-design.md +495 -0
- package/templates/skills/backend-development/references/backend-architecture.md +454 -0
- package/templates/skills/backend-development/references/backend-authentication.md +338 -0
- package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
- package/templates/skills/backend-development/references/backend-debugging.md +904 -0
- package/templates/skills/backend-development/references/backend-devops.md +494 -0
- package/templates/skills/backend-development/references/backend-mindset.md +387 -0
- package/templates/skills/backend-development/references/backend-performance.md +397 -0
- package/templates/skills/backend-development/references/backend-security.md +290 -0
- package/templates/skills/backend-development/references/backend-technologies.md +256 -0
- package/templates/skills/backend-development/references/backend-testing.md +429 -0
- package/templates/skills/frontend-design/SKILL.mdc +41 -0
- package/templates/skills/frontend-design/references/animejs.md +396 -0
- package/templates/skills/frontend-development/SKILL.mdc +399 -0
- package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
- package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
- package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
- package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
- package/templates/skills/frontend-development/resources/file-organization.md +502 -0
- package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
- package/templates/skills/frontend-development/resources/performance.md +406 -0
- package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
- package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
- package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
- package/templates/skills/problem-solving/SKILL.mdc +96 -0
- package/templates/skills/problem-solving/references/attribution.md +69 -0
- package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
- package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
- package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
- package/templates/skills/problem-solving/references/scale-game.md +95 -0
- package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
- package/templates/skills/problem-solving/references/when-stuck.md +72 -0
- package/templates/skills/research/SKILL.mdc +168 -0
- package/templates/skills/sequential-thinking/.env.example +8 -0
- package/templates/skills/sequential-thinking/README.md +183 -0
- package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
- package/templates/skills/sequential-thinking/package.json +31 -0
- package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
- package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
- package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
- package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
- package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
- package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
- package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
- package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
- package/templates/skills/ui-styling/LICENSE.txt +202 -0
- package/templates/skills/ui-styling/SKILL.mdc +321 -0
- package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
- package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/templates/rules/frontend-design.mdc +0 -48
- package/templates/rules/performance.mdc +0 -54
- package/templates/rules/react.mdc +0 -58
- package/templates/rules/security.mdc +0 -50
- package/templates/rules/testing.mdc +0 -54
- package/templates/rules/typescript.mdc +0 -36
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# Performance Optimization
|
|
2
|
+
|
|
3
|
+
Patterns for optimizing React component performance, preventing unnecessary re-renders, and avoiding memory leaks.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Memoization Patterns
|
|
8
|
+
|
|
9
|
+
### useMemo for Expensive Computations
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { useMemo } from 'react';
|
|
13
|
+
|
|
14
|
+
export const DataDisplay: React.FC<{ items: Item[], searchTerm: string }> = ({
|
|
15
|
+
items,
|
|
16
|
+
searchTerm,
|
|
17
|
+
}) => {
|
|
18
|
+
// ❌ AVOID - Runs on every render
|
|
19
|
+
const filteredItems = items
|
|
20
|
+
.filter(item => item.name.includes(searchTerm))
|
|
21
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
22
|
+
|
|
23
|
+
// ✅ CORRECT - Memoized, only recalculates when dependencies change
|
|
24
|
+
const filteredItems = useMemo(() => {
|
|
25
|
+
return items
|
|
26
|
+
.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase()))
|
|
27
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
28
|
+
}, [items, searchTerm]);
|
|
29
|
+
|
|
30
|
+
return <List items={filteredItems} />;
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**When to use useMemo:**
|
|
35
|
+
- Filtering/sorting large arrays
|
|
36
|
+
- Complex calculations
|
|
37
|
+
- Transforming data structures
|
|
38
|
+
- Expensive computations (loops, recursion)
|
|
39
|
+
|
|
40
|
+
**When NOT to use useMemo:**
|
|
41
|
+
- Simple string concatenation
|
|
42
|
+
- Basic arithmetic
|
|
43
|
+
- Premature optimization (profile first!)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## useCallback for Event Handlers
|
|
48
|
+
|
|
49
|
+
### The Problem
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// ❌ AVOID - Creates new function on every render
|
|
53
|
+
export const Parent: React.FC = () => {
|
|
54
|
+
const handleClick = (id: string) => {
|
|
55
|
+
console.log('Clicked:', id);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Child re-renders every time Parent renders
|
|
59
|
+
// because handleClick is a new function reference each time
|
|
60
|
+
return <Child onClick={handleClick} />;
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### The Solution
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { useCallback } from 'react';
|
|
68
|
+
|
|
69
|
+
export const Parent: React.FC = () => {
|
|
70
|
+
// ✅ CORRECT - Stable function reference
|
|
71
|
+
const handleClick = useCallback((id: string) => {
|
|
72
|
+
console.log('Clicked:', id);
|
|
73
|
+
}, []); // Empty deps = function never changes
|
|
74
|
+
|
|
75
|
+
// Child only re-renders when props actually change
|
|
76
|
+
return <Child onClick={handleClick} />;
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**When to use useCallback:**
|
|
81
|
+
- Functions passed as props to children
|
|
82
|
+
- Functions used as dependencies in useEffect
|
|
83
|
+
- Functions passed to memoized components
|
|
84
|
+
- Event handlers in lists
|
|
85
|
+
|
|
86
|
+
**When NOT to use useCallback:**
|
|
87
|
+
- Event handlers not passed to children
|
|
88
|
+
- Simple inline handlers: `onClick={() => doSomething()}`
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## React.memo for Component Memoization
|
|
93
|
+
|
|
94
|
+
### Basic Usage
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import React from 'react';
|
|
98
|
+
|
|
99
|
+
interface ExpensiveComponentProps {
|
|
100
|
+
data: ComplexData;
|
|
101
|
+
onAction: () => void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ✅ Wrap expensive components in React.memo
|
|
105
|
+
export const ExpensiveComponent = React.memo<ExpensiveComponentProps>(
|
|
106
|
+
function ExpensiveComponent({ data, onAction }) {
|
|
107
|
+
// Complex rendering logic
|
|
108
|
+
return <ComplexVisualization data={data} />;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**When to use React.memo:**
|
|
114
|
+
- Component renders frequently
|
|
115
|
+
- Component has expensive rendering
|
|
116
|
+
- Props don't change often
|
|
117
|
+
- Component is a list item
|
|
118
|
+
- DataGrid cells/renderers
|
|
119
|
+
|
|
120
|
+
**When NOT to use React.memo:**
|
|
121
|
+
- Props change frequently anyway
|
|
122
|
+
- Rendering is already fast
|
|
123
|
+
- Premature optimization
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Debounced Search
|
|
128
|
+
|
|
129
|
+
### Using use-debounce Hook
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { useState } from 'react';
|
|
133
|
+
import { useDebounce } from 'use-debounce';
|
|
134
|
+
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
135
|
+
|
|
136
|
+
export const SearchComponent: React.FC = () => {
|
|
137
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
138
|
+
|
|
139
|
+
// Debounce for 300ms
|
|
140
|
+
const [debouncedSearchTerm] = useDebounce(searchTerm, 300);
|
|
141
|
+
|
|
142
|
+
// Query uses debounced value
|
|
143
|
+
const { data } = useSuspenseQuery({
|
|
144
|
+
queryKey: ['search', debouncedSearchTerm],
|
|
145
|
+
queryFn: () => api.search(debouncedSearchTerm),
|
|
146
|
+
enabled: debouncedSearchTerm.length > 0,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<input
|
|
151
|
+
value={searchTerm}
|
|
152
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
153
|
+
placeholder='Search...'
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Optimal Debounce Timing:**
|
|
160
|
+
- **300-500ms**: Search/filtering
|
|
161
|
+
- **1000ms**: Auto-save
|
|
162
|
+
- **100-200ms**: Real-time validation
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Memory Leak Prevention
|
|
167
|
+
|
|
168
|
+
### Cleanup Timeouts/Intervals
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { useEffect, useState } from 'react';
|
|
172
|
+
|
|
173
|
+
export const MyComponent: React.FC = () => {
|
|
174
|
+
const [count, setCount] = useState(0);
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
// ✅ CORRECT - Cleanup interval
|
|
178
|
+
const intervalId = setInterval(() => {
|
|
179
|
+
setCount(c => c + 1);
|
|
180
|
+
}, 1000);
|
|
181
|
+
|
|
182
|
+
return () => {
|
|
183
|
+
clearInterval(intervalId); // Cleanup!
|
|
184
|
+
};
|
|
185
|
+
}, []);
|
|
186
|
+
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
// ✅ CORRECT - Cleanup timeout
|
|
189
|
+
const timeoutId = setTimeout(() => {
|
|
190
|
+
console.log('Delayed action');
|
|
191
|
+
}, 5000);
|
|
192
|
+
|
|
193
|
+
return () => {
|
|
194
|
+
clearTimeout(timeoutId); // Cleanup!
|
|
195
|
+
};
|
|
196
|
+
}, []);
|
|
197
|
+
|
|
198
|
+
return <div>{count}</div>;
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Cleanup Event Listeners
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
const handleResize = () => {
|
|
207
|
+
console.log('Resized');
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
window.addEventListener('resize', handleResize);
|
|
211
|
+
|
|
212
|
+
return () => {
|
|
213
|
+
window.removeEventListener('resize', handleResize); // Cleanup!
|
|
214
|
+
};
|
|
215
|
+
}, []);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Abort Controllers for Fetch
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
const abortController = new AbortController();
|
|
223
|
+
|
|
224
|
+
fetch('/api/data', { signal: abortController.signal })
|
|
225
|
+
.then(response => response.json())
|
|
226
|
+
.then(data => setState(data))
|
|
227
|
+
.catch(error => {
|
|
228
|
+
if (error.name === 'AbortError') {
|
|
229
|
+
console.log('Fetch aborted');
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return () => {
|
|
234
|
+
abortController.abort(); // Cleanup!
|
|
235
|
+
};
|
|
236
|
+
}, []);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Note**: With TanStack Query, this is handled automatically.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Form Performance
|
|
244
|
+
|
|
245
|
+
### Watch Specific Fields (Not All)
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { useForm } from 'react-hook-form';
|
|
249
|
+
|
|
250
|
+
export const MyForm: React.FC = () => {
|
|
251
|
+
const { register, watch, handleSubmit } = useForm();
|
|
252
|
+
|
|
253
|
+
// ❌ AVOID - Watches all fields, re-renders on any change
|
|
254
|
+
const formValues = watch();
|
|
255
|
+
|
|
256
|
+
// ✅ CORRECT - Watch only what you need
|
|
257
|
+
const username = watch('username');
|
|
258
|
+
const email = watch('email');
|
|
259
|
+
|
|
260
|
+
// Or multiple specific fields
|
|
261
|
+
const [username, email] = watch(['username', 'email']);
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
265
|
+
<input {...register('username')} />
|
|
266
|
+
<input {...register('email')} />
|
|
267
|
+
<input {...register('password')} />
|
|
268
|
+
|
|
269
|
+
{/* Only re-renders when username/email change */}
|
|
270
|
+
<p>Username: {username}, Email: {email}</p>
|
|
271
|
+
</form>
|
|
272
|
+
);
|
|
273
|
+
};
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## List Rendering Optimization
|
|
279
|
+
|
|
280
|
+
### Key Prop Usage
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// ✅ CORRECT - Stable unique keys
|
|
284
|
+
{items.map(item => (
|
|
285
|
+
<ListItem key={item.id}>
|
|
286
|
+
{item.name}
|
|
287
|
+
</ListItem>
|
|
288
|
+
))}
|
|
289
|
+
|
|
290
|
+
// ❌ AVOID - Index as key (unstable if list changes)
|
|
291
|
+
{items.map((item, index) => (
|
|
292
|
+
<ListItem key={index}> // WRONG if list reorders
|
|
293
|
+
{item.name}
|
|
294
|
+
</ListItem>
|
|
295
|
+
))}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Memoized List Items
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
const ListItem = React.memo<ListItemProps>(({ item, onAction }) => {
|
|
302
|
+
return (
|
|
303
|
+
<Box onClick={() => onAction(item.id)}>
|
|
304
|
+
{item.name}
|
|
305
|
+
</Box>
|
|
306
|
+
);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
export const List: React.FC<{ items: Item[] }> = ({ items }) => {
|
|
310
|
+
const handleAction = useCallback((id: string) => {
|
|
311
|
+
console.log('Action:', id);
|
|
312
|
+
}, []);
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<Box>
|
|
316
|
+
{items.map(item => (
|
|
317
|
+
<ListItem
|
|
318
|
+
key={item.id}
|
|
319
|
+
item={item}
|
|
320
|
+
onAction={handleAction}
|
|
321
|
+
/>
|
|
322
|
+
))}
|
|
323
|
+
</Box>
|
|
324
|
+
);
|
|
325
|
+
};
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Preventing Component Re-initialization
|
|
331
|
+
|
|
332
|
+
### The Problem
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// ❌ AVOID - Component recreated on every render
|
|
336
|
+
export const Parent: React.FC = () => {
|
|
337
|
+
// New component definition each render!
|
|
338
|
+
const ChildComponent = () => <div>Child</div>;
|
|
339
|
+
|
|
340
|
+
return <ChildComponent />; // Unmounts and remounts every render
|
|
341
|
+
};
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### The Solution
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// ✅ CORRECT - Define outside or use useMemo
|
|
348
|
+
const ChildComponent: React.FC = () => <div>Child</div>;
|
|
349
|
+
|
|
350
|
+
export const Parent: React.FC = () => {
|
|
351
|
+
return <ChildComponent />; // Stable component
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// ✅ OR if dynamic, use useMemo
|
|
355
|
+
export const Parent: React.FC<{ config: Config }> = ({ config }) => {
|
|
356
|
+
const DynamicComponent = useMemo(() => {
|
|
357
|
+
return () => <div>{config.title}</div>;
|
|
358
|
+
}, [config.title]);
|
|
359
|
+
|
|
360
|
+
return <DynamicComponent />;
|
|
361
|
+
};
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Lazy Loading Heavy Dependencies
|
|
367
|
+
|
|
368
|
+
### Code Splitting
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// ❌ AVOID - Import heavy libraries at top level
|
|
372
|
+
import jsPDF from 'jspdf'; // Large library loaded immediately
|
|
373
|
+
import * as XLSX from 'xlsx'; // Large library loaded immediately
|
|
374
|
+
|
|
375
|
+
// ✅ CORRECT - Dynamic import when needed
|
|
376
|
+
const handleExportPDF = async () => {
|
|
377
|
+
const { jsPDF } = await import('jspdf');
|
|
378
|
+
const doc = new jsPDF();
|
|
379
|
+
// Use it
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const handleExportExcel = async () => {
|
|
383
|
+
const XLSX = await import('xlsx');
|
|
384
|
+
// Use it
|
|
385
|
+
};
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Summary
|
|
391
|
+
|
|
392
|
+
**Performance Checklist:**
|
|
393
|
+
- ✅ `useMemo` for expensive computations (filter, sort, map)
|
|
394
|
+
- ✅ `useCallback` for functions passed to children
|
|
395
|
+
- ✅ `React.memo` for expensive components
|
|
396
|
+
- ✅ Debounce search/filter (300-500ms)
|
|
397
|
+
- ✅ Cleanup timeouts/intervals in useEffect
|
|
398
|
+
- ✅ Watch specific form fields (not all)
|
|
399
|
+
- ✅ Stable keys in lists
|
|
400
|
+
- ✅ Lazy load heavy libraries
|
|
401
|
+
- ✅ Code splitting with React.lazy
|
|
402
|
+
|
|
403
|
+
**See Also:**
|
|
404
|
+
- [component-patterns.md](component-patterns.md) - Lazy loading
|
|
405
|
+
- [data-fetching.md](data-fetching.md) - TanStack Query optimization
|
|
406
|
+
- [complete-examples.md](complete-examples.md) - Performance patterns in context
|