@kood/claude-code 0.1.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.d.ts +2 -0
- package/dist/index.js +297 -0
- package/package.json +47 -0
- package/templates/hono/CLAUDE.md +376 -0
- package/templates/hono/docs/deployment/cloudflare.md +328 -0
- package/templates/hono/docs/deployment/index.md +291 -0
- package/templates/hono/docs/git/index.md +180 -0
- package/templates/hono/docs/library/hono/error-handling.md +400 -0
- package/templates/hono/docs/library/hono/index.md +241 -0
- package/templates/hono/docs/library/hono/middleware.md +334 -0
- package/templates/hono/docs/library/hono/rpc.md +454 -0
- package/templates/hono/docs/library/hono/validation.md +328 -0
- package/templates/hono/docs/library/prisma/index.md +427 -0
- package/templates/hono/docs/library/zod/index.md +413 -0
- package/templates/hono/docs/mcp/context7.md +106 -0
- package/templates/hono/docs/mcp/index.md +94 -0
- package/templates/hono/docs/mcp/sequential-thinking.md +101 -0
- package/templates/hono/docs/mcp/sgrep.md +105 -0
- package/templates/hono/docs/skills/gemini-review/SKILL.md +220 -0
- package/templates/hono/docs/skills/gemini-review/references/checklists.md +136 -0
- package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +303 -0
- package/templates/tanstack-start/CLAUDE.md +279 -0
- package/templates/tanstack-start/docs/architecture/architecture.md +547 -0
- package/templates/tanstack-start/docs/deployment/cloudflare.md +346 -0
- package/templates/tanstack-start/docs/deployment/index.md +102 -0
- package/templates/tanstack-start/docs/deployment/nitro.md +211 -0
- package/templates/tanstack-start/docs/deployment/railway.md +364 -0
- package/templates/tanstack-start/docs/deployment/vercel.md +287 -0
- package/templates/tanstack-start/docs/design/accessibility.md +433 -0
- package/templates/tanstack-start/docs/design/color.md +235 -0
- package/templates/tanstack-start/docs/design/components.md +409 -0
- package/templates/tanstack-start/docs/design/index.md +107 -0
- package/templates/tanstack-start/docs/design/safe-area.md +317 -0
- package/templates/tanstack-start/docs/design/spacing.md +341 -0
- package/templates/tanstack-start/docs/design/tailwind-setup.md +470 -0
- package/templates/tanstack-start/docs/design/typography.md +324 -0
- package/templates/tanstack-start/docs/git/index.md +203 -0
- package/templates/tanstack-start/docs/guides/best-practices.md +753 -0
- package/templates/tanstack-start/docs/guides/getting-started.md +304 -0
- package/templates/tanstack-start/docs/guides/husky-lint-staged.md +303 -0
- package/templates/tanstack-start/docs/guides/prettier.md +189 -0
- package/templates/tanstack-start/docs/guides/project-templates.md +710 -0
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +136 -0
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +138 -0
- package/templates/tanstack-start/docs/library/better-auth/index.md +83 -0
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +111 -0
- package/templates/tanstack-start/docs/library/better-auth/session.md +127 -0
- package/templates/tanstack-start/docs/library/better-auth/setup.md +123 -0
- package/templates/tanstack-start/docs/library/prisma/crud.md +218 -0
- package/templates/tanstack-start/docs/library/prisma/index.md +165 -0
- package/templates/tanstack-start/docs/library/prisma/relations.md +191 -0
- package/templates/tanstack-start/docs/library/prisma/schema.md +177 -0
- package/templates/tanstack-start/docs/library/prisma/setup.md +156 -0
- package/templates/tanstack-start/docs/library/prisma/transactions.md +140 -0
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +146 -0
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +146 -0
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +196 -0
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +110 -0
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +170 -0
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +173 -0
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +171 -0
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +114 -0
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +142 -0
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +163 -0
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +128 -0
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +85 -0
- package/templates/tanstack-start/docs/library/zod/basic-types.md +186 -0
- package/templates/tanstack-start/docs/library/zod/complex-types.md +204 -0
- package/templates/tanstack-start/docs/library/zod/index.md +186 -0
- package/templates/tanstack-start/docs/library/zod/transforms.md +174 -0
- package/templates/tanstack-start/docs/library/zod/validation.md +208 -0
- package/templates/tanstack-start/docs/mcp/context7.md +204 -0
- package/templates/tanstack-start/docs/mcp/index.md +116 -0
- package/templates/tanstack-start/docs/mcp/sequential-thinking.md +180 -0
- package/templates/tanstack-start/docs/mcp/sgrep.md +174 -0
- package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +220 -0
- package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +150 -0
- package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +293 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
TanStack Start 프로젝트 시작 가이드입니다.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 18+
|
|
8
|
+
- Yarn
|
|
9
|
+
- Claude Code CLI
|
|
10
|
+
|
|
11
|
+
## Project Setup
|
|
12
|
+
|
|
13
|
+
### 1. Create TanStack Start Project
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx create-tsrouter-app@latest my-app --template start
|
|
17
|
+
cd my-app
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Install Dependencies
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 3. Add Essential Packages
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Database (Prisma 7.x)
|
|
30
|
+
yarn add @prisma/client@7
|
|
31
|
+
yarn add -D prisma@7
|
|
32
|
+
|
|
33
|
+
# Validation (Zod 4.x)
|
|
34
|
+
yarn add zod
|
|
35
|
+
|
|
36
|
+
# TanStack Query
|
|
37
|
+
yarn add @tanstack/react-query
|
|
38
|
+
|
|
39
|
+
# UI (optional)
|
|
40
|
+
yarn add tailwindcss postcss autoprefixer
|
|
41
|
+
npx tailwindcss init -p
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 4. Initialize Prisma
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx prisma init
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Project Structure
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
my-app/
|
|
54
|
+
├── src/
|
|
55
|
+
│ ├── routes/
|
|
56
|
+
│ │ ├── __root.tsx
|
|
57
|
+
│ │ ├── index.tsx
|
|
58
|
+
│ │ └── users/
|
|
59
|
+
│ │ ├── index.tsx
|
|
60
|
+
│ │ ├── route.tsx # 필요시 route 설정
|
|
61
|
+
│ │ ├── -components/ # 페이지 전용 컴포넌트
|
|
62
|
+
│ │ │ └── user-card.tsx
|
|
63
|
+
│ │ ├── -sections/ # 섹션 분리 (복잡한 경우)
|
|
64
|
+
│ │ │ ├── user-list-section.tsx
|
|
65
|
+
│ │ │ └── user-filter-section.tsx
|
|
66
|
+
│ │ └── -hooks/ # 페이지 전용 훅
|
|
67
|
+
│ │ ├── use-users.ts
|
|
68
|
+
│ │ └── use-user-filter.ts
|
|
69
|
+
│ ├── components/ # 공통 컴포넌트
|
|
70
|
+
│ │ └── ui/
|
|
71
|
+
│ │ ├── button.tsx
|
|
72
|
+
│ │ └── input.tsx
|
|
73
|
+
│ ├── database/ # 데이터베이스 관련
|
|
74
|
+
│ │ └── prisma.ts # Prisma Client 인스턴스
|
|
75
|
+
│ ├── services/ # 도메인별 SDK/서비스 레이어
|
|
76
|
+
│ │ ├── user/
|
|
77
|
+
│ │ │ ├── index.ts # 진입점 (re-export)
|
|
78
|
+
│ │ │ ├── schemas.ts # Zod 스키마
|
|
79
|
+
│ │ │ ├── queries.ts # GET 요청
|
|
80
|
+
│ │ │ └── mutations.ts # POST 요청
|
|
81
|
+
│ │ └── auth/
|
|
82
|
+
│ │ ├── index.ts
|
|
83
|
+
│ │ ├── schemas.ts
|
|
84
|
+
│ │ ├── queries.ts
|
|
85
|
+
│ │ └── mutations.ts
|
|
86
|
+
│ ├── lib/ # 공통 유틸리티
|
|
87
|
+
│ │ ├── query-client.ts
|
|
88
|
+
│ │ └── utils.ts
|
|
89
|
+
│ └── styles/
|
|
90
|
+
│ └── app.css
|
|
91
|
+
├── generated/
|
|
92
|
+
│ └── prisma/ # Prisma Client 출력
|
|
93
|
+
├── prisma/
|
|
94
|
+
│ └── schema.prisma
|
|
95
|
+
├── app.config.ts
|
|
96
|
+
├── package.json
|
|
97
|
+
└── tsconfig.json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Route Folder Convention
|
|
101
|
+
|
|
102
|
+
TanStack Start에서 `-` 접두사는 라우트에서 제외됩니다:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
routes/users/
|
|
106
|
+
├── index.tsx # /users 페이지
|
|
107
|
+
├── route.tsx # route 설정 (loader, beforeLoad 등)
|
|
108
|
+
├── -components/ # ❌ 라우트 아님, 컴포넌트 폴더
|
|
109
|
+
│ └── user-card.tsx
|
|
110
|
+
├── -sections/ # ❌ 라우트 아님, 섹션 폴더
|
|
111
|
+
│ └── user-list-section.tsx
|
|
112
|
+
└── -hooks/ # ❌ 라우트 아님, 훅 폴더
|
|
113
|
+
└── use-users.ts
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Core Configuration
|
|
117
|
+
|
|
118
|
+
### app.config.ts
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { defineConfig } from '@tanstack/react-start/config'
|
|
122
|
+
|
|
123
|
+
export default defineConfig({
|
|
124
|
+
server: {
|
|
125
|
+
preset: 'node-server',
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Root Route
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
// src/routes/__root.tsx
|
|
134
|
+
import { createRootRoute, Outlet } from '@tanstack/react-router'
|
|
135
|
+
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
|
|
136
|
+
|
|
137
|
+
export const Route = createRootRoute({
|
|
138
|
+
component: RootComponent,
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const RootComponent = (): JSX.Element => {
|
|
142
|
+
return (
|
|
143
|
+
<>
|
|
144
|
+
<div className="min-h-screen">
|
|
145
|
+
<nav className="border-b p-4">
|
|
146
|
+
<a href="/" className="font-bold">My App</a>
|
|
147
|
+
</nav>
|
|
148
|
+
<main className="container mx-auto p-4">
|
|
149
|
+
<Outlet />
|
|
150
|
+
</main>
|
|
151
|
+
</div>
|
|
152
|
+
<TanStackRouterDevtools />
|
|
153
|
+
</>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Home Route
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
// src/routes/index.tsx
|
|
162
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
163
|
+
|
|
164
|
+
export const Route = createFileRoute('/')({
|
|
165
|
+
component: HomePage,
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const HomePage = (): JSX.Element => {
|
|
169
|
+
return (
|
|
170
|
+
<div>
|
|
171
|
+
<h1 className="text-2xl font-bold">Welcome</h1>
|
|
172
|
+
</div>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Services Setup
|
|
178
|
+
|
|
179
|
+
### Database Setup
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// src/database/prisma.ts
|
|
183
|
+
import { PrismaClient } from '../../generated/prisma'
|
|
184
|
+
|
|
185
|
+
const globalForPrisma = globalThis as unknown as {
|
|
186
|
+
prisma: PrismaClient | undefined
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const prisma =
|
|
190
|
+
globalForPrisma.prisma ??
|
|
191
|
+
new PrismaClient({
|
|
192
|
+
log: process.env.NODE_ENV === 'development' ? ['query'] : [],
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
196
|
+
globalForPrisma.prisma = prisma
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Query Client
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// src/lib/query-client.ts
|
|
204
|
+
import { QueryClient } from '@tanstack/react-query'
|
|
205
|
+
|
|
206
|
+
export const createQueryClient = (): QueryClient => {
|
|
207
|
+
return new QueryClient({
|
|
208
|
+
defaultOptions: {
|
|
209
|
+
queries: {
|
|
210
|
+
staleTime: 60 * 1000,
|
|
211
|
+
retry: 1,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### User Service (도메인 폴더 구조)
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// src/services/user/schemas.ts
|
|
222
|
+
import { z } from 'zod'
|
|
223
|
+
|
|
224
|
+
export const createUserSchema = z.object({
|
|
225
|
+
email: z.email(),
|
|
226
|
+
name: z.string().min(1).max(100).trim(),
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
export const updateUserSchema = z.object({
|
|
230
|
+
id: z.string(),
|
|
231
|
+
email: z.email().optional(),
|
|
232
|
+
name: z.string().min(1).max(100).trim().optional(),
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
export type CreateUserInput = z.infer<typeof createUserSchema>
|
|
236
|
+
export type UpdateUserInput = z.infer<typeof updateUserSchema>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// src/services/user/queries.ts
|
|
241
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
242
|
+
import { prisma } from '@/database/prisma'
|
|
243
|
+
|
|
244
|
+
export const getUsers = createServerFn({ method: 'GET' })
|
|
245
|
+
.handler(async () => {
|
|
246
|
+
return prisma.user.findMany({
|
|
247
|
+
orderBy: { createdAt: 'desc' },
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
export const getUserById = createServerFn({ method: 'GET' })
|
|
252
|
+
.handler(async ({ data: id }: { data: string }) => {
|
|
253
|
+
const user = await prisma.user.findUnique({ where: { id } })
|
|
254
|
+
if (!user) throw new Error('User not found')
|
|
255
|
+
return user
|
|
256
|
+
})
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// src/services/user/mutations.ts
|
|
261
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
262
|
+
import { prisma } from '@/database/prisma'
|
|
263
|
+
import { createUserSchema, updateUserSchema } from './schemas'
|
|
264
|
+
|
|
265
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
266
|
+
.inputValidator(createUserSchema)
|
|
267
|
+
.handler(async ({ data }) => {
|
|
268
|
+
return prisma.user.create({ data })
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
export const updateUser = createServerFn({ method: 'POST' })
|
|
272
|
+
.inputValidator(updateUserSchema)
|
|
273
|
+
.handler(async ({ data }) => {
|
|
274
|
+
const { id, ...updateData } = data
|
|
275
|
+
return prisma.user.update({ where: { id }, data: updateData })
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
export const deleteUser = createServerFn({ method: 'POST' })
|
|
279
|
+
.handler(async ({ data: id }: { data: string }) => {
|
|
280
|
+
return prisma.user.delete({ where: { id } })
|
|
281
|
+
})
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// src/services/user/index.ts
|
|
286
|
+
export * from './schemas'
|
|
287
|
+
export * from './queries'
|
|
288
|
+
export * from './mutations'
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Development Commands
|
|
292
|
+
|
|
293
|
+
| Command | Description |
|
|
294
|
+
|---------|-------------|
|
|
295
|
+
| `yarn dev` | Start development server |
|
|
296
|
+
| `yarn build` | Build for production |
|
|
297
|
+
| `yarn start` | Start production server |
|
|
298
|
+
| `yarn test` | Run tests |
|
|
299
|
+
| `yarn lint` | Check code quality |
|
|
300
|
+
|
|
301
|
+
## Next Steps
|
|
302
|
+
|
|
303
|
+
- [Best Practices](./best-practices.md) - 개발 모범 사례
|
|
304
|
+
- [Project Templates](./project-templates.md) - 프로젝트 템플릿
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Husky + lint-staged
|
|
2
|
+
|
|
3
|
+
> Git 커밋 시 자동 코드 검사 및 포맷팅
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Quick Reference
|
|
8
|
+
|
|
9
|
+
### 설치 (복사용)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# 패키지 설치
|
|
13
|
+
yarn add -D husky lint-staged
|
|
14
|
+
|
|
15
|
+
# Husky 초기화
|
|
16
|
+
npx husky init
|
|
17
|
+
|
|
18
|
+
# pre-commit 훅 설정
|
|
19
|
+
echo "npx lint-staged" > .husky/pre-commit
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 설치 단계별 가이드
|
|
25
|
+
|
|
26
|
+
### 1. 패키지 설치
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
yarn add -D husky lint-staged
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Husky 초기화
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx husky init
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
이 명령어는:
|
|
39
|
+
- `.husky/` 디렉토리 생성
|
|
40
|
+
- `package.json`에 `prepare` 스크립트 추가
|
|
41
|
+
- 기본 `pre-commit` 훅 생성
|
|
42
|
+
|
|
43
|
+
### 3. pre-commit 훅 설정
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
echo "npx lint-staged" > .husky/pre-commit
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 설정 파일
|
|
52
|
+
|
|
53
|
+
### package.json
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"scripts": {
|
|
58
|
+
"prepare": "husky"
|
|
59
|
+
},
|
|
60
|
+
"lint-staged": {
|
|
61
|
+
"*.{js,jsx,ts,tsx}": [
|
|
62
|
+
"prettier --write"
|
|
63
|
+
],
|
|
64
|
+
"*.{json,yml,yaml}": [
|
|
65
|
+
"prettier --write"
|
|
66
|
+
],
|
|
67
|
+
"*.{css,scss}": [
|
|
68
|
+
"prettier --write"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 또는 .lintstagedrc.json (별도 파일)
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"*.{js,jsx,ts,tsx}": [
|
|
79
|
+
"prettier --write"
|
|
80
|
+
],
|
|
81
|
+
"*.{json,yml,yaml}": [
|
|
82
|
+
"prettier --write"
|
|
83
|
+
],
|
|
84
|
+
"*.{css,scss}": [
|
|
85
|
+
"prettier --write"
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**주의**: `*.md` 파일은 lint-staged에서 제외 (Prettier가 테이블 등을 이상하게 변형함)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 고급 설정
|
|
95
|
+
|
|
96
|
+
### TypeScript 타입 체크 포함
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"lint-staged": {
|
|
101
|
+
"*.{ts,tsx}": [
|
|
102
|
+
"prettier --write",
|
|
103
|
+
"bash -c 'tsc --noEmit'"
|
|
104
|
+
],
|
|
105
|
+
"*.{js,jsx}": [
|
|
106
|
+
"prettier --write"
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### ESLint 포함 (선택)
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"lint-staged": {
|
|
117
|
+
"*.{js,jsx,ts,tsx}": [
|
|
118
|
+
"eslint --fix",
|
|
119
|
+
"prettier --write"
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 테스트 포함 (선택)
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"lint-staged": {
|
|
130
|
+
"*.{ts,tsx}": [
|
|
131
|
+
"prettier --write",
|
|
132
|
+
"vitest related --run"
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 디렉토리 구조
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
project/
|
|
144
|
+
├── .husky/
|
|
145
|
+
│ ├── _/
|
|
146
|
+
│ │ └── husky.sh
|
|
147
|
+
│ └── pre-commit # 커밋 전 실행
|
|
148
|
+
├── package.json # lint-staged 설정
|
|
149
|
+
└── .prettierrc # Prettier 설정
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## .husky/pre-commit 예시
|
|
155
|
+
|
|
156
|
+
### 기본 (lint-staged만)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npx lint-staged
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 추가 검사 포함
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
#!/bin/sh
|
|
166
|
+
|
|
167
|
+
# lint-staged 실행
|
|
168
|
+
npx lint-staged
|
|
169
|
+
|
|
170
|
+
# 타입 체크 (전체)
|
|
171
|
+
echo "Running type check..."
|
|
172
|
+
npx tsc --noEmit
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 작동 흐름
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
git commit -m "feat: 새 기능"
|
|
181
|
+
↓
|
|
182
|
+
.husky/pre-commit 실행
|
|
183
|
+
↓
|
|
184
|
+
lint-staged 실행
|
|
185
|
+
↓
|
|
186
|
+
스테이징된 파일만 처리:
|
|
187
|
+
- *.ts, *.tsx → prettier --write
|
|
188
|
+
- *.json, *.md → prettier --write
|
|
189
|
+
↓
|
|
190
|
+
변경된 파일 자동 스테이징
|
|
191
|
+
↓
|
|
192
|
+
커밋 완료
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 문제 해결
|
|
198
|
+
|
|
199
|
+
### 훅이 실행되지 않을 때
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Husky 재설치
|
|
203
|
+
rm -rf .husky
|
|
204
|
+
npx husky init
|
|
205
|
+
echo "npx lint-staged" > .husky/pre-commit
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 권한 문제
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
chmod +x .husky/pre-commit
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### lint-staged 캐시 문제
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# 캐시 삭제
|
|
218
|
+
rm -rf node_modules/.cache/lint-staged
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 훅 우회 (긴급 시에만)
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
git commit -m "fix: 긴급 수정" --no-verify
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**주의**: `--no-verify`는 정말 긴급한 상황에서만 사용
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 팀 설정
|
|
232
|
+
|
|
233
|
+
### 새 팀원 온보딩
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# 클론 후 실행
|
|
237
|
+
yarn install # prepare 스크립트가 자동으로 husky 설정
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### CI/CD에서 Husky 비활성화
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# CI 환경에서
|
|
244
|
+
HUSKY=0 yarn install
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
또는 package.json:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"scripts": {
|
|
252
|
+
"prepare": "husky || true"
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 권장 설정 조합
|
|
260
|
+
|
|
261
|
+
### 최소 설정
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"lint-staged": {
|
|
266
|
+
"*": ["prettier --write --ignore-unknown"]
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 표준 설정 (권장)
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"lint-staged": {
|
|
276
|
+
"*.{js,jsx,ts,tsx}": ["prettier --write"],
|
|
277
|
+
"*.{json,yml,yaml,css,scss}": ["prettier --write"]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 엄격한 설정
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"lint-staged": {
|
|
287
|
+
"*.{ts,tsx}": [
|
|
288
|
+
"prettier --write",
|
|
289
|
+
"bash -c 'tsc --noEmit'"
|
|
290
|
+
],
|
|
291
|
+
"*.{js,jsx}": ["prettier --write"],
|
|
292
|
+
"*.{json,yml,yaml,css,scss}": ["prettier --write"]
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 참고
|
|
300
|
+
|
|
301
|
+
- [Husky 공식 문서](https://typicode.github.io/husky/)
|
|
302
|
+
- [lint-staged 공식 문서](https://github.com/lint-staged/lint-staged)
|
|
303
|
+
- [Prettier 설정](./prettier.md)
|