@kood/claude-code 0.4.0 → 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 -531
- package/templates/.claude/commands/prd.md +0 -629
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: TanStack Router Loader에서 병렬 데이터 페칭
|
|
3
3
|
impact: CRITICAL
|
|
4
|
-
impactDescription: 2-10
|
|
4
|
+
impactDescription: 2-10배 성능 향상
|
|
5
5
|
tags: async, loader, tanstack-router, parallelization, waterfalls
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## TanStack Router Loader에서 병렬 데이터 페칭
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`loader`에서 독립적인 서버 함수 호출을 `Promise.all()`을 사용해 동시 실행. 요청 워터폴 (waterfalls)을 제거합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예 (순차 실행, 2번의 왕복):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import { createFileRoute } from '@tanstack/react-router'
|
|
@@ -24,7 +24,7 @@ export const Route = createFileRoute('/dashboard')({
|
|
|
24
24
|
})
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**✅ 올바른 예 (병렬 실행, 1번의 왕복):**
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
30
|
import { createFileRoute } from '@tanstack/react-router'
|
|
@@ -41,4 +41,4 @@ export const Route = createFileRoute('/dashboard')({
|
|
|
41
41
|
})
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
독립적인 `createServerFn()` 호출에 모두 적용 가능하며, 페이지 로드 시간을 50-80% 단축합니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-parallel.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: 2-10× improvement
|
|
|
5
5
|
tags: async, parallelization, promises, waterfalls
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
## Promise.all()
|
|
8
|
+
## 독립적인 작업에 Promise.all() 사용하기
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
비동기 작업들이 서로 의존성이 없을 때는 `Promise.all()`을 사용하여 동시에 실행합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (순차 실행, 3번의 라운드 트립):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
const user = await fetchUser()
|
|
@@ -17,7 +17,7 @@ const posts = await fetchPosts()
|
|
|
17
17
|
const comments = await fetchComments()
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**✅ 올바른 예시 (병렬 실행, 1번의 라운드 트립):**
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
const [user, posts, comments] = await Promise.all([
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-barrel-imports.md
CHANGED
|
@@ -5,55 +5,55 @@ impactDescription: 200-800ms import cost, slow builds
|
|
|
5
5
|
tags: bundle, imports, tree-shaking, barrel-files, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 배럴 파일 (Barrel File) 임포트 피하기
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
수천 개의 사용하지 않는 모듈을 로드하지 않도록 배럴 파일 대신 소스 파일에서 직접 임포트합니다. **배럴 파일**은 여러 모듈을 재내보내는 진입점입니다 (예: `export * from './module'`을 하는 `index.js`).
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
인기 있는 아이콘 및 컴포넌트 라이브러리는 진입 파일에서 **최대 10,000개의 재내보내기**를 가질 수 있습니다. 많은 React 패키지의 경우 **임포트하는 데만 200-800ms가 걸리며**, 개발 속도와 프로덕션 콜드 스타트 모두에 영향을 미칩니다.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
**트리 쉐이킹이 도움이 되지 않는 이유:** 라이브러리가 외부로 표시되면(번들링되지 않음) 번들러가 최적화할 수 없습니다. 트리 쉐이킹을 활성화하기 위해 번들링하면 전체 모듈 그래프를 분석하느라 빌드가 상당히 느려집니다.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**❌ 잘못된 예시 (전체 라이브러리 임포트):**
|
|
17
17
|
|
|
18
18
|
```tsx
|
|
19
19
|
import { Check, X, Menu } from 'lucide-react'
|
|
20
|
-
//
|
|
21
|
-
//
|
|
20
|
+
// 1,583개 모듈 로드, 개발 환경에서 약 2.8초 추가 소요
|
|
21
|
+
// 런타임 비용: 모든 콜드 스타트마다 200-800ms
|
|
22
22
|
|
|
23
23
|
import { Button, TextField } from '@mui/material'
|
|
24
|
-
//
|
|
24
|
+
// 2,225개 모듈 로드, 개발 환경에서 약 4.2초 추가 소요
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**✅ 올바른 예시 (필요한 것만 임포트):**
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
30
|
import Check from 'lucide-react/dist/esm/icons/check'
|
|
31
31
|
import X from 'lucide-react/dist/esm/icons/x'
|
|
32
32
|
import Menu from 'lucide-react/dist/esm/icons/menu'
|
|
33
|
-
//
|
|
33
|
+
// 3개 모듈만 로드 (~2KB vs ~1MB)
|
|
34
34
|
|
|
35
35
|
import Button from '@mui/material/Button'
|
|
36
36
|
import TextField from '@mui/material/TextField'
|
|
37
|
-
//
|
|
37
|
+
// 사용하는 것만 로드
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
**대안 (Next.js 13.5+):**
|
|
41
41
|
|
|
42
42
|
```js
|
|
43
|
-
// next.config.js -
|
|
43
|
+
// next.config.js - optimizePackageImports 사용
|
|
44
44
|
module.exports = {
|
|
45
45
|
experimental: {
|
|
46
46
|
optimizePackageImports: ['lucide-react', '@mui/material']
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
//
|
|
50
|
+
// 그러면 인체공학적인 배럴 임포트를 유지할 수 있습니다:
|
|
51
51
|
import { Check, X, Menu } from 'lucide-react'
|
|
52
|
-
//
|
|
52
|
+
// 빌드 시 자동으로 직접 임포트로 변환됨
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
직접 임포트는 개발 부팅이 15-70% 더 빠르고, 빌드가 28% 더 빠르고, 콜드 스타트가 40% 더 빠르고, HMR이 훨씬 더 빠릅니다.
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
일반적으로 영향을 받는 라이브러리: `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `ramda`, `date-fns`, `rxjs`, `react-use`.
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
참고: [How we optimized package imports in Next.js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-conditional.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: loads large data only when needed
|
|
|
5
5
|
tags: bundle, conditional-loading, lazy-loading
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 조건부 모듈 로딩
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
기능이 활성화될 때만 큰 데이터나 모듈을 로드합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**예시 (애니메이션 프레임 지연 로딩):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function AnimationPlayer({ enabled }: { enabled: boolean }) {
|
|
@@ -28,4 +28,4 @@ function AnimationPlayer({ enabled }: { enabled: boolean }) {
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
`typeof window !== 'undefined'` 체크는 SSR에서 이 모듈이 번들링되는 것을 방지하여 서버 번들 크기와 빌드 속도를 최적화합니다.
|
|
@@ -5,11 +5,11 @@ impactDescription: loads after hydration
|
|
|
5
5
|
tags: bundle, third-party, analytics, defer
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 중요하지 않은 서드파티 라이브러리 연기하기
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
분석, 로깅, 에러 추적은 사용자 상호작용을 차단하지 않습니다. 하이드레이션 후에 로드합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (초기 번들 차단):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
import { Analytics } from '@vercel/analytics/react'
|
|
@@ -26,7 +26,7 @@ export default function RootLayout({ children }) {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**✅ 올바른 예시 (하이드레이션 후 로드):**
|
|
30
30
|
|
|
31
31
|
```tsx
|
|
32
32
|
import dynamic from 'next/dynamic'
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-lazy-routes.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: 라우트 기반 코드 스플리팅
|
|
3
3
|
impact: CRITICAL
|
|
4
|
-
impactDescription: 30-50%
|
|
4
|
+
impactDescription: 초기 번들 30-50% 감소
|
|
5
5
|
tags: bundle, lazy-loading, code-splitting, routes
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 라우트 기반 코드 스플리팅
|
|
9
9
|
|
|
10
|
-
TanStack Router
|
|
10
|
+
TanStack Router는 라우트별로 자동 코드 스플리팅. 라우트 내 무거운 컴포넌트는 `lazy()`로 번들 크기를 추가 감소.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예 (무거운 컴포넌트 선행 로드):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
import { createFileRoute } from '@tanstack/react-router'
|
|
16
|
-
import HeavyEditor from '@/components/HeavyEditor' // 500KB
|
|
16
|
+
import HeavyEditor from '@/components/HeavyEditor' // 500KB 번들
|
|
17
17
|
|
|
18
18
|
export const Route = createFileRoute('/editor')({
|
|
19
19
|
component: () => <HeavyEditor />
|
|
20
20
|
})
|
|
21
|
-
//
|
|
21
|
+
// 사용자가 /editor를 방문하지 않아도 500KB 전체 로드
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**✅ 올바른 예 (무거운 컴포넌트 지연 로딩):**
|
|
25
25
|
|
|
26
26
|
```tsx
|
|
27
27
|
import { createFileRoute } from '@tanstack/react-router'
|
|
@@ -36,10 +36,10 @@ export const Route = createFileRoute('/editor')({
|
|
|
36
36
|
</Suspense>
|
|
37
37
|
)
|
|
38
38
|
})
|
|
39
|
-
//
|
|
39
|
+
// 사용자가 /editor로 이동할 때만 500KB 로드
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
**여러 무거운 의존성의 경우:**
|
|
43
43
|
|
|
44
44
|
```tsx
|
|
45
45
|
import { lazy, Suspense } from 'react'
|
|
@@ -62,6 +62,6 @@ export const Route = createFileRoute('/dashboard')({
|
|
|
62
62
|
})
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
지연 로딩을 고려할 무거운 라이브러리: 차트 라이브러리 (recharts, chart.js), 리치 텍스트 에디터 (tiptap, slate), PDF 뷰어, 비디오 플레이어, 3D 렌더러, 데이터 시각화.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
초기 번들을 30-50% 감소시키고 Time to Interactive를 개선합니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-preload.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: reduces perceived latency
|
|
|
5
5
|
tags: bundle, preload, user-intent, hover
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 사용자 의도에 따른 프리로드
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
무거운 번들을 필요하기 전에 프리로드하여 체감 지연 시간을 줄입니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**예시 (호버/포커스 시 프리로드):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function EditorButton({ onClick }: { onClick: () => void }) {
|
|
@@ -31,7 +31,7 @@ function EditorButton({ onClick }: { onClick: () => void }) {
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
**예시 (기능 플래그가 활성화될 때 프리로드):**
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
37
37
|
function FlagsProvider({ children, flags }: Props) {
|
|
@@ -47,4 +47,4 @@ function FlagsProvider({ children, flags }: Props) {
|
|
|
47
47
|
}
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
`typeof window !== 'undefined'` 체크는 프리로드된 모듈이 SSR에서 번들링되는 것을 방지하여 서버 번들 크기와 빌드 속도를 최적화합니다.
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-event-listeners.md
CHANGED
|
@@ -5,11 +5,11 @@ impactDescription: single listener for N components
|
|
|
5
5
|
tags: client, swr, event-listeners, subscription
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 전역 이벤트 리스너 중복 제거
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`useSWRSubscription()`을 사용하여 컴포넌트 인스턴스 간에 전역 이벤트 리스너를 공유합니다.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (N개 인스턴스 = N개 리스너):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
function useKeyboardShortcut(key: string, callback: () => void) {
|
|
@@ -25,18 +25,18 @@ function useKeyboardShortcut(key: string, callback: () => void) {
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
`useKeyboardShortcut` 훅을 여러 번 사용하면 각 인스턴스가 새로운 리스너를 등록합니다.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
**✅ 올바른 예시 (N개 인스턴스 = 1개 리스너):**
|
|
31
31
|
|
|
32
32
|
```tsx
|
|
33
33
|
import useSWRSubscription from 'swr/subscription'
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// 모듈 레벨 Map으로 키별 콜백 추적
|
|
36
36
|
const keyCallbacks = new Map<string, Set<() => void>>()
|
|
37
37
|
|
|
38
38
|
function useKeyboardShortcut(key: string, callback: () => void) {
|
|
39
|
-
//
|
|
39
|
+
// Map에 이 콜백 등록
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
if (!keyCallbacks.has(key)) {
|
|
42
42
|
keyCallbacks.set(key, new Set())
|
|
@@ -66,8 +66,8 @@ function useKeyboardShortcut(key: string, callback: () => void) {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function Profile() {
|
|
69
|
-
//
|
|
70
|
-
useKeyboardShortcut('p', () => { /* ... */ })
|
|
69
|
+
// 여러 단축키가 동일한 리스너를 공유함
|
|
70
|
+
useKeyboardShortcut('p', () => { /* ... */ })
|
|
71
71
|
useKeyboardShortcut('k', () => { /* ... */ })
|
|
72
72
|
// ...
|
|
73
73
|
}
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-tanstack-query.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: TanStack Query로 자동 캐싱 및 중복 제거
|
|
3
3
|
impact: MEDIUM-HIGH
|
|
4
|
-
impactDescription:
|
|
4
|
+
impactDescription: 중복 요청 제거
|
|
5
5
|
tags: client, cache, tanstack-query, deduplication
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## TanStack Query로 자동 캐싱 및 중복 제거
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
서버 함수 호출을 TanStack Query로 래핑하여 자동 요청 중복 제거 (deduplication), 캐싱, 백그라운드 재페칭 활성화.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예 (중복 제거 없음, 각 컴포넌트가 페칭):**
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
15
|
import { useState, useEffect } from 'react'
|
|
@@ -25,10 +25,10 @@ function UserList() {
|
|
|
25
25
|
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// UserList를 페이지에 3번 사용하면 getUsers()가 3번 호출됨
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
**✅ 올바른 예 (자동 중복 제거, 단일 요청):**
|
|
32
32
|
|
|
33
33
|
```tsx
|
|
34
34
|
import { useQuery } from '@tanstack/react-query'
|
|
@@ -43,10 +43,10 @@ function UserList() {
|
|
|
43
43
|
return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
//
|
|
46
|
+
// 여러 인스턴스가 하나의 요청 공유, 자동 캐시 무효화 포함
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
**
|
|
49
|
+
**Mutation과 함께:**
|
|
50
50
|
|
|
51
51
|
```tsx
|
|
52
52
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
@@ -63,7 +63,7 @@ function UserManager() {
|
|
|
63
63
|
const mutation = useMutation({
|
|
64
64
|
mutationFn: createUser,
|
|
65
65
|
onSuccess: () => {
|
|
66
|
-
//
|
|
66
|
+
// 자동으로 users 재페칭
|
|
67
67
|
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
68
68
|
}
|
|
69
69
|
})
|
|
@@ -72,6 +72,6 @@ function UserManager() {
|
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
TanStack Query
|
|
75
|
+
TanStack Query가 제공하는 것: 요청 중복 제거, 백그라운드 재페칭, 캐시 무효화, 낙관적 업데이트 (optimistic updates), 재시도 로직, 로딩/에러 상태.
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
참고: [TanStack Query](https://tanstack.com/query)
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-batch-dom-css.md
CHANGED
|
@@ -5,15 +5,15 @@ impactDescription: reduces reflows/repaints
|
|
|
5
5
|
tags: javascript, dom, css, performance, reflow
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## DOM CSS 변경 일괄 처리
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
스타일을 한 번에 하나씩 변경하지 마세요. 여러 CSS 변경 사항을 클래스 또는 `cssText`를 통해 그룹화하여 브라우저 리플로우를 최소화하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (여러 번의 리플로우):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function updateElementStyles(element: HTMLElement) {
|
|
16
|
-
//
|
|
16
|
+
// 각 줄이 리플로우를 트리거함
|
|
17
17
|
element.style.width = '100px'
|
|
18
18
|
element.style.height = '200px'
|
|
19
19
|
element.style.backgroundColor = 'blue'
|
|
@@ -21,10 +21,10 @@ function updateElementStyles(element: HTMLElement) {
|
|
|
21
21
|
}
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**✅ 올바른 예시 (클래스 추가 - 단일 리플로우):**
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
// CSS
|
|
27
|
+
// CSS 파일
|
|
28
28
|
.highlighted-box {
|
|
29
29
|
width: 100px;
|
|
30
30
|
height: 200px;
|
|
@@ -38,7 +38,7 @@ function updateElementStyles(element: HTMLElement) {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
**✅ 올바른 예시 (cssText 변경 - 단일 리플로우):**
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
44
|
function updateElementStyles(element: HTMLElement) {
|
|
@@ -51,13 +51,13 @@ function updateElementStyles(element: HTMLElement) {
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
**React
|
|
54
|
+
**React 예시:**
|
|
55
55
|
|
|
56
56
|
```tsx
|
|
57
|
-
//
|
|
57
|
+
// ❌ 잘못된 예시: 스타일을 하나씩 변경
|
|
58
58
|
function Box({ isHighlighted }: { isHighlighted: boolean }) {
|
|
59
59
|
const ref = useRef<HTMLDivElement>(null)
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
useEffect(() => {
|
|
62
62
|
if (ref.current && isHighlighted) {
|
|
63
63
|
ref.current.style.width = '100px'
|
|
@@ -65,11 +65,11 @@ function Box({ isHighlighted }: { isHighlighted: boolean }) {
|
|
|
65
65
|
ref.current.style.backgroundColor = 'blue'
|
|
66
66
|
}
|
|
67
67
|
}, [isHighlighted])
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
return <div ref={ref}>Content</div>
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
//
|
|
72
|
+
// ✅ 올바른 예시: 클래스 토글
|
|
73
73
|
function Box({ isHighlighted }: { isHighlighted: boolean }) {
|
|
74
74
|
return (
|
|
75
75
|
<div className={isHighlighted ? 'highlighted-box' : ''}>
|
|
@@ -79,4 +79,4 @@ function Box({ isHighlighted }: { isHighlighted: boolean }) {
|
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
가능하면 인라인 스타일보다 CSS 클래스를 선호하세요. 클래스는 브라우저에 캐시되며 관심사의 분리를 더 잘 제공합니다.
|
|
@@ -5,20 +5,20 @@ impactDescription: avoid redundant computation
|
|
|
5
5
|
tags: javascript, cache, memoization, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 반복되는 함수 호출 캐싱
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
렌더링 중 동일한 입력으로 동일한 함수가 반복적으로 호출될 때 모듈 레벨 Map을 사용하여 함수 결과를 캐시하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (중복 계산):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function ProjectList({ projects }: { projects: Project[] }) {
|
|
16
16
|
return (
|
|
17
17
|
<div>
|
|
18
18
|
{projects.map(project => {
|
|
19
|
-
// slugify()
|
|
19
|
+
// slugify()가 동일한 프로젝트 이름에 대해 100번 이상 호출됨
|
|
20
20
|
const slug = slugify(project.name)
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
return <ProjectCard key={project.id} slug={slug} />
|
|
23
23
|
})}
|
|
24
24
|
</div>
|
|
@@ -26,10 +26,10 @@ function ProjectList({ projects }: { projects: Project[] }) {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**✅ 올바른 예시 (캐시된 결과):**
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
|
-
//
|
|
32
|
+
// 모듈 레벨 캐시
|
|
33
33
|
const slugifyCache = new Map<string, string>()
|
|
34
34
|
|
|
35
35
|
function cachedSlugify(text: string): string {
|
|
@@ -45,9 +45,9 @@ function ProjectList({ projects }: { projects: Project[] }) {
|
|
|
45
45
|
return (
|
|
46
46
|
<div>
|
|
47
47
|
{projects.map(project => {
|
|
48
|
-
//
|
|
48
|
+
// 고유한 프로젝트 이름당 한 번만 계산됨
|
|
49
49
|
const slug = cachedSlugify(project.name)
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
return <ProjectCard key={project.id} slug={slug} />
|
|
52
52
|
})}
|
|
53
53
|
</div>
|
|
@@ -55,7 +55,7 @@ function ProjectList({ projects }: { projects: Project[] }) {
|
|
|
55
55
|
}
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
**단일 값 함수를 위한 간단한 패턴:**
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
61
|
let isLoggedInCache: boolean | null = null
|
|
@@ -64,17 +64,17 @@ function isLoggedIn(): boolean {
|
|
|
64
64
|
if (isLoggedInCache !== null) {
|
|
65
65
|
return isLoggedInCache
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
isLoggedInCache = document.cookie.includes('auth=')
|
|
69
69
|
return isLoggedInCache
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
//
|
|
72
|
+
// 인증이 변경될 때 캐시 초기화
|
|
73
73
|
function onAuthChange() {
|
|
74
74
|
isLoggedInCache = null
|
|
75
75
|
}
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Map을 사용하세요 (훅이 아님). 그래야 유틸리티, 이벤트 핸들러 등 어디서든 작동합니다 (React 컴포넌트뿐만 아니라).
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
참고: [How we made the Vercel Dashboard twice as fast](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)
|
|
@@ -5,11 +5,11 @@ impactDescription: reduces lookups
|
|
|
5
5
|
tags: javascript, loops, optimization, caching
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 루프에서 속성 접근 캐싱
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
핫 패스에서 객체 속성 조회를 캐시하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (3개의 조회 × N번 반복):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -17,7 +17,7 @@ for (let i = 0; i < arr.length; i++) {
|
|
|
17
17
|
}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**✅ 올바른 예시 (총 1번의 조회):**
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
const value = obj.config.settings.value
|
package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-storage.md
CHANGED
|
@@ -5,20 +5,20 @@ impactDescription: reduces expensive I/O
|
|
|
5
5
|
tags: javascript, localStorage, storage, caching, performance
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Storage API 호출 캐싱
|
|
9
9
|
|
|
10
|
-
`localStorage`, `sessionStorage`,
|
|
10
|
+
`localStorage`, `sessionStorage`, `document.cookie`는 동기적이고 비용이 많이 듭니다. 읽기를 메모리에 캐시하세요.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**❌ 잘못된 예시 (호출할 때마다 스토리지 읽기):**
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
function getTheme() {
|
|
16
16
|
return localStorage.getItem('theme') ?? 'light'
|
|
17
17
|
}
|
|
18
|
-
//
|
|
18
|
+
// 10번 호출 = 10번 스토리지 읽기
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**✅ 올바른 예시 (Map 캐시):**
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
const storageCache = new Map<string, string | null>()
|
|
@@ -32,13 +32,13 @@ function getLocalStorage(key: string) {
|
|
|
32
32
|
|
|
33
33
|
function setLocalStorage(key: string, value: string) {
|
|
34
34
|
localStorage.setItem(key, value)
|
|
35
|
-
storageCache.set(key, value) //
|
|
35
|
+
storageCache.set(key, value) // 캐시를 동기화된 상태로 유지
|
|
36
36
|
}
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Map을 사용하세요 (훅이 아님). 그래야 유틸리티, 이벤트 핸들러 등 어디서든 작동합니다 (React 컴포넌트뿐만 아니라).
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
**쿠키 캐싱:**
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
44
|
let cookieCache: Record<string, string> | null = null
|
|
@@ -53,9 +53,9 @@ function getCookie(name: string) {
|
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
**중요 (외부 변경 시 무효화):**
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
스토리지가 외부에서 변경될 수 있는 경우 (다른 탭, 서버 설정 쿠키), 캐시를 무효화하세요:
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
61
|
window.addEventListener('storage', (e) => {
|