@kood/claude-code 0.4.1 → 0.5.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.
- package/dist/index.js +53 -7
- package/package.json +2 -1
- package/templates/.claude/PARALLEL_AGENTS.md +737 -0
- package/templates/.claude/agents/analyst.md +416 -0
- package/templates/.claude/agents/architect.md +569 -0
- package/templates/.claude/agents/code-reviewer.md +132 -133
- package/templates/.claude/agents/dependency-manager.md +93 -94
- package/templates/.claude/agents/deployment-validator.md +64 -65
- package/templates/.claude/agents/designer.md +655 -0
- package/templates/.claude/agents/document-writer.md +500 -0
- package/templates/.claude/agents/explore.md +499 -0
- package/templates/.claude/agents/git-operator.md +74 -75
- package/templates/.claude/agents/implementation-executor.md +138 -109
- package/templates/.claude/agents/ko-to-en-translator.md +18 -22
- package/templates/.claude/agents/lint-fixer.md +250 -93
- package/templates/.claude/agents/planner.md +356 -0
- package/templates/.claude/agents/refactor-advisor.md +135 -136
- package/templates/.claude/commands/bug-fix.md +296 -207
- package/templates/.claude/commands/git-all.md +199 -46
- package/templates/.claude/commands/git-session.md +113 -57
- package/templates/.claude/commands/lint-fix.md +219 -153
- package/templates/.claude/commands/lint-init.md +113 -76
- package/templates/.claude/commands/pre-deploy.md +190 -124
- package/templates/.claude/commands/refactor.md +407 -162
- package/templates/.claude/commands/version-update.md +138 -37
- package/templates/.claude/instructions/context-engineering/ANTHROPIC_CONTEXT_ENGINEERING.md +178 -0
- package/templates/.claude/instructions/context-engineering/references/claude-4x.md +215 -0
- package/templates/.claude/instructions/context-engineering/references/core-principles.md +137 -0
- package/templates/.claude/instructions/context-engineering/references/examples.md +351 -0
- package/templates/.claude/instructions/context-engineering/references/techniques.md +162 -0
- package/templates/.claude/instructions/parallel-agent-execution.md +874 -0
- package/templates/.claude/skills/docs-creator/AGENTS.md +238 -0
- package/templates/.claude/{commands/docs-creator.md → skills/docs-creator/SKILL.md} +61 -75
- package/templates/.claude/skills/docs-refactor/AGENTS.md +270 -0
- package/templates/.claude/{commands/docs-refactor.md → skills/docs-refactor/SKILL.md} +30 -44
- package/templates/.claude/skills/execute/SKILL.md +451 -0
- package/templates/.claude/skills/figma-to-code/AGENTS.md +287 -0
- package/templates/.claude/skills/figma-to-code/SKILL.md +225 -225
- package/templates/.claude/skills/figma-to-code/references/design-tokens.md +75 -73
- package/templates/.claude/skills/figma-to-code/references/figma-mcp-tools.md +73 -73
- package/templates/.claude/skills/figma-to-code/references/layout-mapping.md +104 -104
- package/templates/.claude/skills/figma-to-code/references/responsive-design.md +99 -99
- package/templates/.claude/skills/figma-to-code/references/verification.md +91 -91
- package/templates/.claude/skills/global-uiux-design/AGENTS.md +317 -0
- package/templates/.claude/skills/global-uiux-design/SKILL.md +738 -0
- package/templates/.claude/skills/global-uiux-design/references/accessibility.md +401 -0
- package/templates/.claude/skills/global-uiux-design/references/color-system.md +275 -0
- package/templates/.claude/skills/global-uiux-design/references/design-philosophy.md +206 -0
- package/templates/.claude/skills/global-uiux-design/references/design-systems.md +446 -0
- package/templates/.claude/skills/korea-uiux-design/AGENTS.md +307 -0
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +170 -0
- package/templates/.claude/skills/nextjs-react-best-practices/AGENTS.md +95 -116
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +134 -152
- package/templates/.claude/skills/nextjs-react-best-practices/rules/advanced-event-handler-refs.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/advanced-use-latest.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-api-routes.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-defer-await.md +22 -22
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-dependencies.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-parallel.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/async-suspense-boundaries.md +21 -21
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-barrel-imports.md +18 -18
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-conditional.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-defer-third-party.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-dynamic-imports.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/bundle-preload.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/client-event-listeners.md +9 -9
- package/templates/.claude/skills/nextjs-react-best-practices/rules/client-swr-dedup.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-batch-dom-css.md +13 -13
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-function-results.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-property-access.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-cache-storage.md +10 -10
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-combine-iterations.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-early-exit.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-hoist-regexp.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-index-maps.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-length-check-first.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-min-max-loop.md +16 -16
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-set-map-lookups.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/js-tosorted-immutable.md +17 -17
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-activity.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-animate-svg-wrapper.md +11 -11
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-conditional-render.md +8 -8
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-content-visibility.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-hoist-jsx.md +6 -6
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-hydration-no-flicker.md +14 -14
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rendering-svg-precision.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-defer-reads.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-dependencies.md +7 -7
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-derived-state.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-functional-setstate.md +34 -34
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-lazy-state-init.md +15 -15
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-memo.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/rerender-transitions.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-after-nonblocking.md +24 -24
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-cache-lru.md +10 -10
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-cache-react.md +4 -4
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-parallel-fetching.md +5 -5
- package/templates/.claude/skills/nextjs-react-best-practices/rules/server-serialization.md +6 -6
- package/templates/.claude/skills/plan/SKILL.md +594 -0
- package/templates/.claude/skills/prd/SKILL.md +496 -0
- package/templates/.claude/skills/ralph/AGENTS.md +393 -0
- package/templates/.claude/skills/ralph/SKILL.md +1035 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +100 -121
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +139 -157
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-defer-await.md +22 -22
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-dependencies.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-loader.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-parallel.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-barrel-imports.md +18 -18
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-conditional.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-lazy-routes.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-preload.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-event-listeners.md +9 -9
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-tanstack-query.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-batch-dom-css.md +13 -13
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-function-results.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-property-access.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-storage.md +10 -10
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-combine-iterations.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-early-exit.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-hoist-regexp.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-index-maps.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-length-check-first.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-min-max-loop.md +16 -16
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-set-map-lookups.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-tosorted-immutable.md +17 -17
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-animate-svg-wrapper.md +11 -11
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-conditional-render.md +8 -8
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-content-visibility.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-hoist-jsx.md +6 -6
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-svg-precision.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-defer-reads.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-dependencies.md +7 -7
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-derived-state.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-functional-setstate.md +34 -34
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-lazy-state-init.md +15 -15
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-memo.md +5 -5
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-transitions.md +4 -4
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-cache-lru.md +12 -12
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +14 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-parallel-fetching.md +9 -9
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +6 -6
- package/templates/.claude/commands/agent-creator.md +0 -370
- package/templates/.claude/commands/command-creator.md +0 -524
- package/templates/.claude/commands/execute.md +0 -469
- package/templates/.claude/commands/git.md +0 -98
- package/templates/.claude/commands/plan.md +0 -526
- package/templates/.claude/commands/prd.md +0 -629
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-combine-iterations.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: reduces iterations
|
|
|
5
5
|
tags: javascript, arrays, loops, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 여러 배열 반복 결합
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
여러 개의 `.filter()` 또는 `.map()` 호출은 배열을 여러 번 반복합니다. 하나의 루프로 결합하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (3번 반복):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
const admins = users.filter(u => u.isAdmin)
|
|
@@ -17,7 +17,7 @@ const testers = users.filter(u => u.isTester)
|
|
|
17
17
|
const inactive = users.filter(u => !u.isActive)
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**✅ 올바른 예시 (1번 반복):**
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
const admins: User[] = []
|
|
@@ -5,17 +5,17 @@ impactDescription: avoids unnecessary computation
|
|
|
5
5
|
tags: javascript, functions, optimization, early-return
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 함수에서 조기 반환
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
결과가 결정되면 불필요한 처리를 건너뛰기 위해 조기 반환하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예 (답을 찾은 후에도 모든 항목 처리):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function validateUsers(users: User[]) {
|
|
16
16
|
let hasError = false
|
|
17
17
|
let errorMessage = ''
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
for (const user of users) {
|
|
20
20
|
if (!user.email) {
|
|
21
21
|
hasError = true
|
|
@@ -25,14 +25,14 @@ function validateUsers(users: User[]) {
|
|
|
25
25
|
hasError = true
|
|
26
26
|
errorMessage = 'Name required'
|
|
27
27
|
}
|
|
28
|
-
//
|
|
28
|
+
// 오류를 찾은 후에도 모든 사용자를 계속 확인함
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
return hasError ? { valid: false, error: errorMessage } : { valid: true }
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
**올바른 예 (첫 번째 오류에서 즉시 반환):**
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
38
|
function validateUsers(users: User[]) {
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-hoist-regexp.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: avoids recreation
|
|
|
5
5
|
tags: javascript, regexp, optimization, memoization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## RegExp 생성 호이스팅
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
렌더 내부에서 RegExp를 생성하지 마세요. 모듈 스코프로 호이스트하거나 `useMemo()`로 메모이제이션하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예 (매 렌더마다 새로운 RegExp):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function Highlighter({ text, query }: Props) {
|
|
@@ -19,7 +19,7 @@ function Highlighter({ text, query }: Props) {
|
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**올바른 예 (메모이제이션 또는 호이스팅):**
|
|
23
23
|
|
|
24
24
|
```tsx
|
|
25
25
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
@@ -34,9 +34,9 @@ function Highlighter({ text, query }: Props) {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
**주의 (전역 정규식은 가변 상태를 가짐):**
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
전역 정규식(`/g`)은 가변적인 `lastIndex` 상태를 가집니다:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
const regex = /foo/g
|
|
@@ -5,11 +5,11 @@ impactDescription: 1M ops to 2K ops
|
|
|
5
5
|
tags: javascript, map, indexing, optimization, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 반복 조회를 위한 인덱스 맵 구축
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
동일한 키로 여러 번 `.find()`를 호출하는 경우 Map을 사용하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (조회당 O(n)):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function processOrders(orders: Order[], users: User[]) {
|
|
@@ -20,7 +20,7 @@ function processOrders(orders: Order[], users: User[]) {
|
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
**✅ 올바른 예시 (조회당 O(1)):**
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
26
|
function processOrders(orders: Order[], users: User[]) {
|
|
@@ -33,5 +33,5 @@ function processOrders(orders: Order[], users: User[]) {
|
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
맵을 한 번 구축(O(n))하면 모든 조회가 O(1)입니다.
|
|
37
|
+
1000개의 주문 × 1000명의 사용자: 1M 연산 → 2K 연산.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-length-check-first.md
CHANGED
|
@@ -5,32 +5,32 @@ impactDescription: avoids expensive operations when lengths differ
|
|
|
5
5
|
tags: javascript, arrays, performance, optimization, comparison
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 배열 비교 시 길이를 먼저 확인
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
배열을 비교할 때 비용이 큰 연산(정렬, 깊은 동등성 비교, 직렬화)을 수행하기 전에 길이를 먼저 확인하세요. 길이가 다르면 배열이 같을 수 없습니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
실제 애플리케이션에서 이 최적화는 핫 패스(이벤트 핸들러, 렌더 루프)에서 비교가 실행될 때 특히 유용합니다.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
**잘못된 예 (항상 비용이 큰 비교 실행):**
|
|
15
15
|
|
|
16
16
|
```typescript
|
|
17
17
|
function hasChanges(current: string[], original: string[]) {
|
|
18
|
-
//
|
|
18
|
+
// 길이가 다를 때도 항상 정렬하고 조인함
|
|
19
19
|
return current.sort().join() !== original.sort().join()
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`current.length`가 5이고 `original.length`가 100일 때도 두 번의 O(n log n) 정렬이 실행됩니다. 배열을 조인하고 문자열을 비교하는 오버헤드도 있습니다.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
**올바른 예 (O(1) 길이 확인 먼저):**
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
function hasChanges(current: string[], original: string[]) {
|
|
29
|
-
//
|
|
29
|
+
// 길이가 다르면 조기 반환
|
|
30
30
|
if (current.length !== original.length) {
|
|
31
31
|
return true
|
|
32
32
|
}
|
|
33
|
-
//
|
|
33
|
+
// 길이가 같을 때만 정렬/조인
|
|
34
34
|
const currentSorted = current.toSorted()
|
|
35
35
|
const originalSorted = original.toSorted()
|
|
36
36
|
for (let i = 0; i < currentSorted.length; i++) {
|
|
@@ -42,8 +42,8 @@ function hasChanges(current: string[], original: string[]) {
|
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
45
|
+
이 새로운 접근 방식이 더 효율적인 이유:
|
|
46
|
+
- 길이가 다를 때 정렬과 조인의 오버헤드를 회피
|
|
47
|
+
- 조인된 문자열을 위한 메모리 소비를 회피 (특히 큰 배열에서 중요)
|
|
48
|
+
- 원본 배열을 변경하지 않음
|
|
49
|
+
- 차이를 발견하면 조기 반환
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-min-max-loop.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: O(n) instead of O(n log n)
|
|
|
5
5
|
tags: javascript, arrays, performance, sorting, algorithms
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 최소/최대값은 정렬 대신 루프 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
가장 작거나 큰 요소를 찾는 것은 배열을 한 번만 순회하면 됩니다. 정렬은 낭비적이고 느립니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예 (O(n log n) - 최신 항목을 찾기 위해 정렬):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
interface Project {
|
|
@@ -24,9 +24,9 @@ function getLatestProject(projects: Project[]) {
|
|
|
24
24
|
}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
최댓값을 찾기 위해 전체 배열을 정렬합니다.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**잘못된 예 (O(n log n) - 가장 오래된 것과 최신 것을 찾기 위해 정렬):**
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
32
|
function getOldestAndNewest(projects: Project[]) {
|
|
@@ -35,43 +35,43 @@ function getOldestAndNewest(projects: Project[]) {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
최소/최대값만 필요한데도 불필요하게 정렬합니다.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
**올바른 예 (O(n) - 단일 루프):**
|
|
41
41
|
|
|
42
42
|
```typescript
|
|
43
43
|
function getLatestProject(projects: Project[]) {
|
|
44
44
|
if (projects.length === 0) return null
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
let latest = projects[0]
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
for (let i = 1; i < projects.length; i++) {
|
|
49
49
|
if (projects[i].updatedAt > latest.updatedAt) {
|
|
50
50
|
latest = projects[i]
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
return latest
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function getOldestAndNewest(projects: Project[]) {
|
|
58
58
|
if (projects.length === 0) return { oldest: null, newest: null }
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
let oldest = projects[0]
|
|
61
61
|
let newest = projects[0]
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
for (let i = 1; i < projects.length; i++) {
|
|
64
64
|
if (projects[i].updatedAt < oldest.updatedAt) oldest = projects[i]
|
|
65
65
|
if (projects[i].updatedAt > newest.updatedAt) newest = projects[i]
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
return { oldest, newest }
|
|
69
69
|
}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
배열을 한 번만 순회하며, 복사도 정렬도 없습니다.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
**대안 (작은 배열에는 Math.min/Math.max):**
|
|
75
75
|
|
|
76
76
|
```typescript
|
|
77
77
|
const numbers = [5, 2, 8, 1, 9]
|
|
@@ -79,4 +79,4 @@ const min = Math.min(...numbers)
|
|
|
79
79
|
const max = Math.max(...numbers)
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
이는 작은 배열에서는 작동하지만 스프레드 연산자의 제한으로 인해 매우 큰 배열에서는 느릴 수 있습니다. 신뢰성을 위해 루프 방식을 사용하세요.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-set-map-lookups.md
CHANGED
|
@@ -5,18 +5,18 @@ impactDescription: O(n) to O(1)
|
|
|
5
5
|
tags: javascript, set, map, data-structures, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## O(1) 조회를 위해 Set/Map 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
반복적인 멤버십 확인을 위해 배열을 Set/Map으로 변환하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예 (확인당 O(n)):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
const allowedIds = ['a', 'b', 'c', ...]
|
|
16
16
|
items.filter(item => allowedIds.includes(item.id))
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**올바른 예 (확인당 O(1)):**
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
const allowedIds = new Set(['a', 'b', 'c', ...])
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-tosorted-immutable.md
CHANGED
|
@@ -5,15 +5,15 @@ impactDescription: prevents mutation bugs in React state
|
|
|
5
5
|
tags: javascript, arrays, immutability, react, state, mutation
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 불변성을 위해 sort() 대신 toSorted() 사용
|
|
9
9
|
|
|
10
|
-
`.sort()
|
|
10
|
+
`.sort()`는 배열을 제자리에서 변경하여 React 상태와 props에서 버그를 일으킬 수 있습니다. 변경 없이 새로운 정렬된 배열을 생성하려면 `.toSorted()`를 사용하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예 (원본 배열 변경):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function UserList({ users }: { users: User[] }) {
|
|
16
|
-
//
|
|
16
|
+
// users prop 배열을 변경함!
|
|
17
17
|
const sorted = useMemo(
|
|
18
18
|
() => users.sort((a, b) => a.name.localeCompare(b.name)),
|
|
19
19
|
[users]
|
|
@@ -22,11 +22,11 @@ function UserList({ users }: { users: User[] }) {
|
|
|
22
22
|
}
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
**올바른 예 (새 배열 생성):**
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
function UserList({ users }: { users: User[] }) {
|
|
29
|
-
//
|
|
29
|
+
// 새로운 정렬된 배열 생성, 원본은 변경 없음
|
|
30
30
|
const sorted = useMemo(
|
|
31
31
|
() => users.toSorted((a, b) => a.name.localeCompare(b.name)),
|
|
32
32
|
[users]
|
|
@@ -35,23 +35,23 @@ function UserList({ users }: { users: User[] }) {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
**
|
|
38
|
+
**React에서 이것이 중요한 이유:**
|
|
39
39
|
|
|
40
|
-
1. Props/state
|
|
41
|
-
2.
|
|
40
|
+
1. Props/state 변경은 React의 불변성 모델을 깨뜨림 - React는 props와 state가 읽기 전용으로 취급되길 기대함
|
|
41
|
+
2. 오래된 클로저 버그 발생 - 클로저(콜백, 이펙트) 내부에서 배열을 변경하면 예상치 못한 동작을 일으킬 수 있음
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
**브라우저 지원 (구형 브라우저를 위한 폴백):**
|
|
44
44
|
|
|
45
|
-
`.toSorted()
|
|
45
|
+
`.toSorted()`는 모든 최신 브라우저(Chrome 110+, Safari 16+, Firefox 115+, Node.js 20+)에서 사용할 수 있습니다. 구형 환경의 경우 스프레드 연산자를 사용하세요:
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
48
|
-
//
|
|
48
|
+
// 구형 브라우저를 위한 폴백
|
|
49
49
|
const sorted = [...items].sort((a, b) => a.value - b.value)
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
**다른 불변 배열 메서드:**
|
|
53
53
|
|
|
54
|
-
- `.toSorted()` -
|
|
55
|
-
- `.toReversed()` -
|
|
56
|
-
- `.toSpliced()` -
|
|
57
|
-
- `.with()` -
|
|
54
|
+
- `.toSorted()` - 불변 정렬
|
|
55
|
+
- `.toReversed()` - 불변 역순
|
|
56
|
+
- `.toSpliced()` - 불변 스플라이스
|
|
57
|
+
- `.with()` - 불변 요소 교체
|
|
@@ -5,19 +5,19 @@ impactDescription: enables hardware acceleration
|
|
|
5
5
|
tags: rendering, svg, css, animation, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## SVG 요소 대신 SVG 래퍼 애니메이션 적용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
많은 브라우저에서 SVG 요소에 대한 CSS3 애니메이션의 하드웨어 가속을 지원하지 않습니다. SVG를 `<div>`로 감싸고 래퍼에 애니메이션을 적용하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 방법 (SVG에 직접 애니메이션 - 하드웨어 가속 없음):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function LoadingSpinner() {
|
|
16
16
|
return (
|
|
17
|
-
<svg
|
|
17
|
+
<svg
|
|
18
18
|
className="animate-spin"
|
|
19
|
-
width="24"
|
|
20
|
-
height="24"
|
|
19
|
+
width="24"
|
|
20
|
+
height="24"
|
|
21
21
|
viewBox="0 0 24 24"
|
|
22
22
|
>
|
|
23
23
|
<circle cx="12" cy="12" r="10" stroke="currentColor" />
|
|
@@ -26,15 +26,15 @@ function LoadingSpinner() {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**올바른 방법 (래퍼 div에 애니메이션 - 하드웨어 가속 적용):**
|
|
30
30
|
|
|
31
31
|
```tsx
|
|
32
32
|
function LoadingSpinner() {
|
|
33
33
|
return (
|
|
34
34
|
<div className="animate-spin">
|
|
35
|
-
<svg
|
|
36
|
-
width="24"
|
|
37
|
-
height="24"
|
|
35
|
+
<svg
|
|
36
|
+
width="24"
|
|
37
|
+
height="24"
|
|
38
38
|
viewBox="0 0 24 24"
|
|
39
39
|
>
|
|
40
40
|
<circle cx="12" cy="12" r="10" stroke="currentColor" />
|
|
@@ -44,4 +44,4 @@ function LoadingSpinner() {
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
이는 모든 CSS 변형 및 전환(`transform`, `opacity`, `translate`, `scale`, `rotate`)에 적용됩니다. 래퍼 div를 사용하면 브라우저가 GPU 가속을 활용하여 더 부드러운 애니메이션을 제공할 수 있습니다.
|
|
@@ -5,11 +5,11 @@ impactDescription: prevents rendering 0 or NaN
|
|
|
5
5
|
tags: rendering, conditional, jsx, falsy-values
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 명시적 조건부 렌더링 사용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
조건이 `0`, `NaN` 또는 렌더링되는 다른 falsy 값일 수 있는 경우, `&&` 대신 명시적 삼항 연산자(`? :`)를 사용하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 방법 (count가 0일 때 "0"을 렌더링):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function Badge({ count }: { count: number }) {
|
|
@@ -20,11 +20,11 @@ function Badge({ count }: { count: number }) {
|
|
|
20
20
|
)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
//
|
|
23
|
+
// count = 0일 때, 렌더링 결과: <div>0</div>
|
|
24
|
+
// count = 5일 때, 렌더링 결과: <div><span class="badge">5</span></div>
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**올바른 방법 (count가 0일 때 아무것도 렌더링하지 않음):**
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
30
|
function Badge({ count }: { count: number }) {
|
|
@@ -35,6 +35,6 @@ function Badge({ count }: { count: number }) {
|
|
|
35
35
|
)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
//
|
|
38
|
+
// count = 0일 때, 렌더링 결과: <div></div>
|
|
39
|
+
// count = 5일 때, 렌더링 결과: <div><span class="badge">5</span></div>
|
|
40
40
|
```
|
|
@@ -5,9 +5,9 @@ impactDescription: faster initial render
|
|
|
5
5
|
tags: rendering, css, content-visibility, long-lists
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
## CSS content-visibility
|
|
8
|
+
## 긴 목록에 CSS content-visibility 적용
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`content-visibility: auto`를 적용하여 화면 밖 렌더링을 지연시킵니다.
|
|
11
11
|
|
|
12
12
|
**CSS:**
|
|
13
13
|
|
|
@@ -18,7 +18,7 @@ Apply `content-visibility: auto` to defer off-screen rendering.
|
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**예시:**
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
function MessageList({ messages }: { messages: Message[] }) {
|
|
@@ -35,4 +35,4 @@ function MessageList({ messages }: { messages: Message[] }) {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
1000개의 메시지가 있을 때, 브라우저는 화면 밖 약 990개 항목의 레이아웃/페인트를 건너뛰어 초기 렌더링 속도가 10배 빨라집니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-hoist-jsx.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: avoids re-creation
|
|
|
5
5
|
tags: rendering, jsx, static, optimization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 정적 JSX 요소 호이스팅
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
정적 JSX를 컴포넌트 외부로 추출하여 재생성을 방지합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 방법 (매 렌더링마다 요소 재생성):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function LoadingSkeleton() {
|
|
@@ -25,7 +25,7 @@ function Container() {
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**올바른 방법 (동일한 요소 재사용):**
|
|
29
29
|
|
|
30
30
|
```tsx
|
|
31
31
|
const loadingSkeleton = (
|
|
@@ -41,6 +41,6 @@ function Container() {
|
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
이는 매 렌더링마다 재생성하는 비용이 큰 대형 정적 SVG 노드에 특히 유용합니다.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
**참고:** 프로젝트에 [React Compiler](https://react.dev/learn/react-compiler)가 활성화되어 있다면, 컴파일러가 자동으로 정적 JSX 요소를 호이스팅하고 컴포넌트 재렌더링을 최적화하므로 수동 호이스팅이 불필요합니다.
|
|
@@ -5,23 +5,23 @@ impactDescription: reduces file size
|
|
|
5
5
|
tags: rendering, svg, optimization, svgo
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## SVG 정밀도 최적화
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
SVG 좌표 정밀도를 줄여 파일 크기를 감소시킵니다. 최적 정밀도는 viewBox 크기에 따라 다르지만, 일반적으로 정밀도 감소를 고려해야 합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 방법 (과도한 정밀도):**
|
|
13
13
|
|
|
14
14
|
```svg
|
|
15
15
|
<path d="M 10.293847 20.847362 L 30.938472 40.192837" />
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
**올바른 방법 (소수점 1자리):**
|
|
19
19
|
|
|
20
20
|
```svg
|
|
21
21
|
<path d="M 10.3 20.8 L 30.9 40.2" />
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
**
|
|
24
|
+
**SVGO로 자동화:**
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
npx svgo --precision=1 --multipass icon.svg
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-defer-reads.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: avoids unnecessary subscriptions
|
|
|
5
5
|
tags: rerender, searchParams, localStorage, optimization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 상태 읽기를 사용 시점으로 지연
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
콜백 내부에서만 읽는 동적 상태(searchParams, localStorage)는 구독하지 마세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (모든 searchParams 변경에 구독):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function ShareButton({ chatId }: { chatId: string }) {
|
|
@@ -24,7 +24,7 @@ function ShareButton({ chatId }: { chatId: string }) {
|
|
|
24
24
|
}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**올바른 예시 (필요 시점에 읽기, 구독 없음):**
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
30
|
function ShareButton({ chatId }: { chatId: string }) {
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-dependencies.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: minimizes effect re-runs
|
|
|
5
5
|
tags: rerender, useEffect, dependencies, optimization
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Effect 의존성 좁히기
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Effect 재실행을 최소화하기 위해 객체 대신 원시 값 의존성을 지정하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**잘못된 예시 (user의 모든 필드 변경 시 재실행):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
useEffect(() => {
|
|
@@ -17,7 +17,7 @@ useEffect(() => {
|
|
|
17
17
|
}, [user])
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**올바른 예시 (id 변경 시에만 재실행):**
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
23
|
useEffect(() => {
|
|
@@ -25,17 +25,17 @@ useEffect(() => {
|
|
|
25
25
|
}, [user.id])
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**파생 상태는 Effect 외부에서 계산:**
|
|
29
29
|
|
|
30
30
|
```tsx
|
|
31
|
-
//
|
|
31
|
+
// 잘못된 예시: width=767, 766, 765... 모든 변경 시 실행
|
|
32
32
|
useEffect(() => {
|
|
33
33
|
if (width < 768) {
|
|
34
34
|
enableMobileMode()
|
|
35
35
|
}
|
|
36
36
|
}, [width])
|
|
37
37
|
|
|
38
|
-
//
|
|
38
|
+
// 올바른 예시: boolean 전환 시에만 실행
|
|
39
39
|
const isMobile = width < 768
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
if (isMobile) {
|