@kood/claude-code 0.3.7 → 0.3.8
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 +1 -1
- package/package.json +1 -1
- package/templates/.claude/agents/code-reviewer.md +124 -124
- package/templates/.claude/agents/dependency-manager.md +85 -85
- package/templates/.claude/agents/deployment-validator.md +56 -56
- package/templates/.claude/agents/git-operator.md +64 -64
- package/templates/.claude/agents/implementation-executor.md +95 -95
- package/templates/.claude/agents/ko-to-en-translator.md +74 -0
- package/templates/.claude/agents/lint-fixer.md +78 -78
- package/templates/.claude/agents/refactor-advisor.md +122 -122
- package/templates/.claude/commands/agent-creator.md +185 -185
- package/templates/.claude/commands/bug-fix.md +193 -193
- package/templates/.claude/commands/command-creator.md +54 -54
- package/templates/.claude/commands/docs-creator.md +57 -57
- package/templates/.claude/commands/docs-refactor.md +26 -26
- package/templates/.claude/commands/execute.md +12 -12
- package/templates/.claude/commands/git-all.md +32 -32
- package/templates/.claude/commands/git-session.md +42 -42
- package/templates/.claude/commands/git.md +34 -34
- package/templates/.claude/commands/lint-fix.md +138 -138
- package/templates/.claude/commands/lint-init.md +61 -61
- package/templates/.claude/commands/plan.md +260 -260
- package/templates/.claude/commands/prd.md +24 -24
- package/templates/.claude/commands/pre-deploy.md +109 -109
- package/templates/.claude/commands/refactor.md +147 -147
- package/templates/.claude/commands/version-update.md +17 -17
- package/templates/hono/CLAUDE.md +27 -27
- package/templates/hono/docs/architecture.md +24 -24
- package/templates/hono/docs/deployment/cloudflare.md +18 -18
- package/templates/hono/docs/deployment/docker.md +13 -13
- package/templates/hono/docs/deployment/index.md +19 -19
- package/templates/hono/docs/deployment/railway.md +32 -32
- package/templates/hono/docs/deployment/vercel.md +29 -29
- package/templates/hono/docs/guides/conventions.md +57 -57
- package/templates/hono/docs/guides/env-setup.md +47 -47
- package/templates/hono/docs/guides/getting-started.md +27 -27
- package/templates/hono/docs/library/hono/error-handling.md +11 -11
- package/templates/hono/docs/library/hono/index.md +4 -4
- package/templates/hono/docs/library/hono/middleware.md +18 -18
- package/templates/hono/docs/library/hono/rpc.md +7 -7
- package/templates/hono/docs/library/hono/validation.md +6 -6
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +29 -29
- package/templates/hono/docs/library/prisma/config.md +16 -16
- package/templates/hono/docs/library/prisma/index.md +32 -32
- package/templates/hono/docs/library/t3-env/index.md +22 -22
- package/templates/hono/docs/library/zod/index.md +31 -31
- package/templates/nextjs/CLAUDE.md +51 -51
- package/templates/nextjs/docs/design.md +183 -183
- package/templates/nextjs/docs/guides/conventions.md +86 -86
- package/templates/nextjs/docs/guides/getting-started.md +28 -28
- package/templates/nextjs/docs/guides/routes.md +32 -32
- package/templates/nextjs/docs/library/better-auth/index.md +70 -70
- package/templates/nextjs/docs/library/nextjs/app-router.md +43 -43
- package/templates/nextjs/docs/library/nextjs/caching.md +73 -73
- package/templates/nextjs/docs/library/nextjs/index.md +51 -51
- package/templates/nextjs/docs/library/nextjs/middleware.md +41 -41
- package/templates/nextjs/docs/library/nextjs/route-handlers.md +31 -31
- package/templates/nextjs/docs/library/nextjs/server-actions.md +34 -34
- package/templates/nextjs/docs/library/prisma/cloudflare-d1.md +20 -20
- package/templates/nextjs/docs/library/prisma/config.md +18 -18
- package/templates/nextjs/docs/library/prisma/crud.md +17 -17
- package/templates/nextjs/docs/library/prisma/index.md +18 -18
- package/templates/nextjs/docs/library/prisma/relations.md +16 -16
- package/templates/nextjs/docs/library/prisma/schema.md +23 -23
- package/templates/nextjs/docs/library/prisma/setup.md +6 -6
- package/templates/nextjs/docs/library/prisma/transactions.md +10 -10
- package/templates/nextjs/docs/library/tanstack-query/index.md +6 -6
- package/templates/nextjs/docs/library/tanstack-query/invalidation.md +20 -20
- package/templates/nextjs/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/nextjs/docs/library/tanstack-query/use-mutation.md +15 -15
- package/templates/nextjs/docs/library/tanstack-query/use-query.md +22 -22
- package/templates/nextjs/docs/library/zod/complex-types.md +11 -11
- package/templates/nextjs/docs/library/zod/index.md +8 -8
- package/templates/nextjs/docs/library/zod/transforms.md +11 -11
- package/templates/nextjs/docs/library/zod/validation.md +9 -9
- package/templates/npx/CLAUDE.md +37 -37
- package/templates/npx/docs/library/commander/index.md +12 -12
- package/templates/npx/docs/library/fs-extra/index.md +9 -9
- package/templates/npx/docs/library/prompts/index.md +3 -3
- package/templates/npx/docs/references/patterns.md +12 -12
- package/templates/tanstack-start/CLAUDE.md +53 -53
- package/templates/tanstack-start/docs/architecture.md +128 -128
- package/templates/tanstack-start/docs/design.md +169 -169
- package/templates/tanstack-start/docs/guides/conventions.md +43 -43
- package/templates/tanstack-start/docs/guides/env-setup.md +35 -35
- package/templates/tanstack-start/docs/guides/getting-started.md +19 -19
- package/templates/tanstack-start/docs/guides/hooks.md +45 -45
- package/templates/tanstack-start/docs/guides/routes.md +54 -54
- package/templates/tanstack-start/docs/guides/services.md +45 -45
- package/templates/tanstack-start/docs/library/better-auth/index.md +68 -68
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +19 -19
- package/templates/tanstack-start/docs/library/prisma/config.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/crud.md +17 -17
- package/templates/tanstack-start/docs/library/prisma/index.md +17 -17
- package/templates/tanstack-start/docs/library/prisma/relations.md +16 -16
- package/templates/tanstack-start/docs/library/prisma/schema.md +23 -23
- package/templates/tanstack-start/docs/library/prisma/setup.md +6 -6
- package/templates/tanstack-start/docs/library/prisma/transactions.md +10 -10
- package/templates/tanstack-start/docs/library/t3-env/index.md +21 -160
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +6 -6
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +19 -19
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +4 -4
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +14 -14
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +21 -21
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +11 -11
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +18 -18
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +17 -17
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +5 -5
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +10 -10
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +8 -8
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +15 -15
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +9 -9
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +6 -6
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +18 -18
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +4 -4
- package/templates/tanstack-start/docs/library/zod/complex-types.md +11 -11
- package/templates/tanstack-start/docs/library/zod/index.md +8 -8
- package/templates/tanstack-start/docs/library/zod/transforms.md +11 -11
- package/templates/tanstack-start/docs/library/zod/validation.md +9 -9
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# App Router
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> File-based routing system
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## File Structure and Routing
|
|
8
8
|
|
|
9
|
-
###
|
|
9
|
+
### Basic Rules
|
|
10
10
|
|
|
11
|
-
|
|
|
12
|
-
|
|
13
|
-
| `app/page.tsx` | `/` |
|
|
14
|
-
| `app/about/page.tsx` | `/about` | About
|
|
15
|
-
| `app/blog/[slug]/page.tsx` | `/blog/:slug` |
|
|
11
|
+
| File | Route | Description |
|
|
12
|
+
|------|-------|-------------|
|
|
13
|
+
| `app/page.tsx` | `/` | Home page |
|
|
14
|
+
| `app/about/page.tsx` | `/about` | About page |
|
|
15
|
+
| `app/blog/[slug]/page.tsx` | `/blog/:slug` | Dynamic route |
|
|
16
16
|
| `app/shop/[...slug]/page.tsx` | `/shop/*` | Catch-all |
|
|
17
17
|
| `app/docs/[[...slug]]/page.tsx` | `/docs/*` | Optional catch-all |
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Example
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
// app/blog/[slug]/page.tsx
|
|
@@ -38,20 +38,20 @@ export default async function BlogPost({ params, searchParams }: PageProps) {
|
|
|
38
38
|
|
|
39
39
|
## Layouts
|
|
40
40
|
|
|
41
|
-
### Root Layout (
|
|
41
|
+
### Root Layout (required)
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
44
|
// app/layout.tsx
|
|
45
45
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
46
46
|
return (
|
|
47
|
-
<html lang="
|
|
47
|
+
<html lang="en">
|
|
48
48
|
<body>{children}</body>
|
|
49
49
|
</html>
|
|
50
50
|
)
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### Nested Layout
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
57
|
// app/dashboard/layout.tsx
|
|
@@ -65,10 +65,10 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
|
|
|
65
65
|
}
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
68
|
+
**Features:**
|
|
69
|
+
- Nestable (parent → child order)
|
|
70
|
+
- Persists without re-rendering
|
|
71
|
+
- Receives `children` as props
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
@@ -87,15 +87,15 @@ app/
|
|
|
87
87
|
└── page.tsx # /products
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
90
|
+
**Purpose:**
|
|
91
|
+
- Group folders without affecting URLs
|
|
92
|
+
- Apply different layouts
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
-
##
|
|
96
|
+
## Dynamic Routes
|
|
97
97
|
|
|
98
|
-
###
|
|
98
|
+
### Single Parameter
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
101
|
// app/posts/[id]/page.tsx
|
|
@@ -104,7 +104,7 @@ export default async function PostPage({ params }: { params: { id: string } }) {
|
|
|
104
104
|
return <article>{post.title}</article>
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
//
|
|
107
|
+
// Static generation (at build time)
|
|
108
108
|
export async function generateStaticParams() {
|
|
109
109
|
const posts = await prisma.post.findMany()
|
|
110
110
|
return posts.map(post => ({ id: post.id }))
|
|
@@ -123,7 +123,7 @@ export default function DocsPage({ params }: { params: { slug: string[] } }) {
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
##
|
|
126
|
+
## Parallel Routes
|
|
127
127
|
|
|
128
128
|
```
|
|
129
129
|
app/
|
|
@@ -157,7 +157,7 @@ export default function Layout({
|
|
|
157
157
|
|
|
158
158
|
---
|
|
159
159
|
|
|
160
|
-
##
|
|
160
|
+
## Intercepting Routes
|
|
161
161
|
|
|
162
162
|
```
|
|
163
163
|
app/
|
|
@@ -172,11 +172,11 @@ app/
|
|
|
172
172
|
└── page.tsx
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
- `(.)` -
|
|
177
|
-
- `(..)` -
|
|
178
|
-
- `(..)(..)` -
|
|
179
|
-
- `(...)` -
|
|
175
|
+
**Conventions:**
|
|
176
|
+
- `(.)` - same level
|
|
177
|
+
- `(..)` - one level up
|
|
178
|
+
- `(..)(..)` - two levels up
|
|
179
|
+
- `(...)` - from root
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
@@ -203,15 +203,15 @@ export async function generateMetadata({ params }: { params: { slug: string } })
|
|
|
203
203
|
|
|
204
204
|
---
|
|
205
205
|
|
|
206
|
-
##
|
|
206
|
+
## Special Files
|
|
207
207
|
|
|
208
|
-
|
|
|
209
|
-
|
|
210
|
-
| `loading.tsx` | Suspense
|
|
208
|
+
| File | Purpose |
|
|
209
|
+
|------|---------|
|
|
210
|
+
| `loading.tsx` | Suspense fallback |
|
|
211
211
|
| `error.tsx` | Error Boundary |
|
|
212
|
-
| `not-found.tsx` | 404
|
|
213
|
-
| `template.tsx` |
|
|
214
|
-
| `default.tsx` |
|
|
212
|
+
| `not-found.tsx` | 404 page |
|
|
213
|
+
| `template.tsx` | Re-rendering Layout |
|
|
214
|
+
| `default.tsx` | Parallel route fallback |
|
|
215
215
|
|
|
216
216
|
### Loading UI
|
|
217
217
|
|
|
@@ -231,8 +231,8 @@ export default function Loading() {
|
|
|
231
231
|
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
|
232
232
|
return (
|
|
233
233
|
<div>
|
|
234
|
-
<h2
|
|
235
|
-
<button onClick={reset}
|
|
234
|
+
<h2>An error occurred</h2>
|
|
235
|
+
<button onClick={reset}>Try again</button>
|
|
236
236
|
</div>
|
|
237
237
|
)
|
|
238
238
|
}
|
|
@@ -240,7 +240,7 @@ export default function Error({ error, reset }: { error: Error; reset: () => voi
|
|
|
240
240
|
|
|
241
241
|
---
|
|
242
242
|
|
|
243
|
-
##
|
|
243
|
+
## Navigation
|
|
244
244
|
|
|
245
245
|
```typescript
|
|
246
246
|
"use client"
|
|
@@ -250,8 +250,8 @@ import Link from "next/link"
|
|
|
250
250
|
|
|
251
251
|
export function Navigation() {
|
|
252
252
|
const router = useRouter()
|
|
253
|
-
const pathname = usePathname() //
|
|
254
|
-
const searchParams = useSearchParams() //
|
|
253
|
+
const pathname = usePathname() // current path
|
|
254
|
+
const searchParams = useSearchParams() // query parameters
|
|
255
255
|
|
|
256
256
|
return (
|
|
257
257
|
<>
|
|
@@ -264,6 +264,6 @@ export function Navigation() {
|
|
|
264
264
|
|
|
265
265
|
---
|
|
266
266
|
|
|
267
|
-
##
|
|
267
|
+
## References
|
|
268
268
|
|
|
269
|
-
- [Next.js App Router
|
|
269
|
+
- [Next.js App Router Official Docs](https://nextjs.org/docs/app)
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
# Caching
|
|
2
2
|
|
|
3
|
-
> Next.js
|
|
3
|
+
> Next.js caching strategies
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Cache Levels
|
|
8
8
|
|
|
9
|
-
|
|
|
10
|
-
|
|
11
|
-
| **Request Memoization** |
|
|
12
|
-
| **Data Cache** |
|
|
13
|
-
| **Full Route Cache** |
|
|
14
|
-
| **Router Cache** |
|
|
9
|
+
| Level | Description |
|
|
10
|
+
|-------|-------------|
|
|
11
|
+
| **Request Memoization** | Deduplicate same requests (React) |
|
|
12
|
+
| **Data Cache** | Server data cache (persistent) |
|
|
13
|
+
| **Full Route Cache** | Static rendering at build time |
|
|
14
|
+
| **Router Cache** | Client-side router cache |
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
## Request Memoization
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
|
-
//
|
|
21
|
+
// Same requests execute only once
|
|
22
22
|
async function getUser(id: string) {
|
|
23
23
|
const res = await fetch(`https://api.example.com/users/${id}`)
|
|
24
24
|
return res.json()
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export default async function Page() {
|
|
28
|
-
const user1 = await getUser("1") // fetch
|
|
29
|
-
const user2 = await getUser("1") //
|
|
28
|
+
const user1 = await getUser("1") // fetch executes
|
|
29
|
+
const user2 = await getUser("1") // cache used (deduplicated)
|
|
30
30
|
|
|
31
31
|
return <div>{user1.name}</div>
|
|
32
32
|
}
|
|
@@ -36,52 +36,52 @@ export default async function Page() {
|
|
|
36
36
|
|
|
37
37
|
## Data Cache (fetch)
|
|
38
38
|
|
|
39
|
-
###
|
|
39
|
+
### Default (cached)
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
|
-
//
|
|
42
|
+
// Cached by default
|
|
43
43
|
const res = await fetch("https://api.example.com/posts")
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
###
|
|
46
|
+
### Disable Cache
|
|
47
47
|
|
|
48
48
|
```typescript
|
|
49
|
-
//
|
|
49
|
+
// Fetch fresh data on every request
|
|
50
50
|
const res = await fetch("https://api.example.com/posts", {
|
|
51
51
|
cache: "no-store",
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
### Revalidate (
|
|
55
|
+
### Revalidate (time-based)
|
|
56
56
|
|
|
57
57
|
```typescript
|
|
58
|
-
// 60
|
|
58
|
+
// Revalidate every 60 seconds
|
|
59
59
|
const res = await fetch("https://api.example.com/posts", {
|
|
60
60
|
next: { revalidate: 60 },
|
|
61
61
|
})
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
### Tag
|
|
64
|
+
### Tag-based Cache
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
67
|
-
//
|
|
67
|
+
// Set tag
|
|
68
68
|
const res = await fetch("https://api.example.com/posts", {
|
|
69
69
|
next: { tags: ["posts"] },
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
// Server Action
|
|
72
|
+
// Invalidate tag in Server Action
|
|
73
73
|
"use server"
|
|
74
74
|
import { revalidateTag } from "next/cache"
|
|
75
75
|
|
|
76
76
|
export async function createPost(data: PostInput) {
|
|
77
77
|
await prisma.post.create({ data })
|
|
78
|
-
revalidateTag("posts") // "posts"
|
|
78
|
+
revalidateTag("posts") // Invalidate "posts" tag cache
|
|
79
79
|
}
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
84
|
-
## unstable_cache (
|
|
84
|
+
## unstable_cache (function caching)
|
|
85
85
|
|
|
86
86
|
```typescript
|
|
87
87
|
import { unstable_cache } from "next/cache"
|
|
@@ -90,10 +90,10 @@ const getCachedPosts = unstable_cache(
|
|
|
90
90
|
async () => {
|
|
91
91
|
return prisma.post.findMany()
|
|
92
92
|
},
|
|
93
|
-
["posts"], //
|
|
93
|
+
["posts"], // cache key
|
|
94
94
|
{
|
|
95
|
-
revalidate: 60, // 60
|
|
96
|
-
tags: ["posts"], //
|
|
95
|
+
revalidate: 60, // 60 seconds
|
|
96
|
+
tags: ["posts"], // tags
|
|
97
97
|
}
|
|
98
98
|
)
|
|
99
99
|
|
|
@@ -115,11 +115,11 @@ import { revalidatePath } from "next/cache"
|
|
|
115
115
|
export async function createPost(data: PostInput) {
|
|
116
116
|
const post = await prisma.post.create({ data })
|
|
117
117
|
|
|
118
|
-
//
|
|
118
|
+
// Invalidate specific path cache
|
|
119
119
|
revalidatePath("/posts")
|
|
120
120
|
revalidatePath(`/posts/${post.id}`)
|
|
121
121
|
|
|
122
|
-
//
|
|
122
|
+
// Invalidate all caches including layout
|
|
123
123
|
revalidatePath("/posts", "layout")
|
|
124
124
|
|
|
125
125
|
return post
|
|
@@ -138,7 +138,7 @@ import { revalidateTag } from "next/cache"
|
|
|
138
138
|
export async function createPost(data: PostInput) {
|
|
139
139
|
const post = await prisma.post.create({ data })
|
|
140
140
|
|
|
141
|
-
//
|
|
141
|
+
// Invalidate all caches with "posts" tag
|
|
142
142
|
revalidateTag("posts")
|
|
143
143
|
|
|
144
144
|
return post
|
|
@@ -147,22 +147,22 @@ export async function createPost(data: PostInput) {
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
-
## Full Route Cache (
|
|
150
|
+
## Full Route Cache (static rendering)
|
|
151
151
|
|
|
152
|
-
###
|
|
152
|
+
### Static Page
|
|
153
153
|
|
|
154
154
|
```typescript
|
|
155
|
-
//
|
|
155
|
+
// Generated at build time (default)
|
|
156
156
|
export default async function PostsPage() {
|
|
157
157
|
const posts = await prisma.post.findMany()
|
|
158
158
|
return <PostsList posts={posts} />
|
|
159
159
|
}
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
###
|
|
162
|
+
### Dynamic Page (disable cache)
|
|
163
163
|
|
|
164
164
|
```typescript
|
|
165
|
-
//
|
|
165
|
+
// Render on every request
|
|
166
166
|
export const dynamic = "force-dynamic"
|
|
167
167
|
|
|
168
168
|
export default async function PostsPage() {
|
|
@@ -171,10 +171,10 @@ export default async function PostsPage() {
|
|
|
171
171
|
}
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
### Revalidate (
|
|
174
|
+
### Revalidate (time-based)
|
|
175
175
|
|
|
176
176
|
```typescript
|
|
177
|
-
// 60
|
|
177
|
+
// Regenerate every 60 seconds
|
|
178
178
|
export const revalidate = 60
|
|
179
179
|
|
|
180
180
|
export default async function PostsPage() {
|
|
@@ -190,16 +190,16 @@ export default async function PostsPage() {
|
|
|
190
190
|
```typescript
|
|
191
191
|
// app/posts/page.tsx
|
|
192
192
|
|
|
193
|
-
//
|
|
193
|
+
// Force dynamic rendering
|
|
194
194
|
export const dynamic = "force-dynamic" // "auto" | "force-static" | "error"
|
|
195
195
|
|
|
196
|
-
// Revalidate
|
|
196
|
+
// Revalidate interval (seconds)
|
|
197
197
|
export const revalidate = 60 // false | 0 | number
|
|
198
198
|
|
|
199
|
-
//
|
|
199
|
+
// Runtime configuration
|
|
200
200
|
export const runtime = "nodejs" // "edge"
|
|
201
201
|
|
|
202
|
-
//
|
|
202
|
+
// Maximum execution time (seconds)
|
|
203
203
|
export const maxDuration = 60
|
|
204
204
|
|
|
205
205
|
export default async function PostsPage() {
|
|
@@ -209,7 +209,7 @@ export default async function PostsPage() {
|
|
|
209
209
|
|
|
210
210
|
---
|
|
211
211
|
|
|
212
|
-
## Router Cache (
|
|
212
|
+
## Router Cache (client-side)
|
|
213
213
|
|
|
214
214
|
```typescript
|
|
215
215
|
"use client"
|
|
@@ -222,8 +222,8 @@ export function Navigation() {
|
|
|
222
222
|
return (
|
|
223
223
|
<button
|
|
224
224
|
onClick={() => {
|
|
225
|
-
router.push("/posts") //
|
|
226
|
-
router.refresh() //
|
|
225
|
+
router.push("/posts") // Use cached page
|
|
226
|
+
router.refresh() // Force refresh
|
|
227
227
|
}}
|
|
228
228
|
>
|
|
229
229
|
Go to Posts
|
|
@@ -234,12 +234,12 @@ export function Navigation() {
|
|
|
234
234
|
|
|
235
235
|
---
|
|
236
236
|
|
|
237
|
-
## generateStaticParams (
|
|
237
|
+
## generateStaticParams (dynamic routes)
|
|
238
238
|
|
|
239
239
|
```typescript
|
|
240
240
|
// app/posts/[id]/page.tsx
|
|
241
241
|
|
|
242
|
-
//
|
|
242
|
+
// List of pages to generate at build time
|
|
243
243
|
export async function generateStaticParams() {
|
|
244
244
|
const posts = await prisma.post.findMany({ select: { id: true } })
|
|
245
245
|
return posts.map(post => ({ id: post.id }))
|
|
@@ -253,40 +253,40 @@ export default async function PostPage({ params }: { params: { id: string } }) {
|
|
|
253
253
|
|
|
254
254
|
---
|
|
255
255
|
|
|
256
|
-
##
|
|
256
|
+
## Caching Flow
|
|
257
257
|
|
|
258
|
-
###
|
|
258
|
+
### Static Page
|
|
259
259
|
|
|
260
260
|
```
|
|
261
|
-
1.
|
|
262
|
-
2. Full Route Cache
|
|
263
|
-
3.
|
|
264
|
-
4.
|
|
261
|
+
1. Render at build time
|
|
262
|
+
2. Save to Full Route Cache
|
|
263
|
+
3. Subsequent requests use cache
|
|
264
|
+
4. Regenerate after revalidate time
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
-
###
|
|
267
|
+
### Dynamic Page
|
|
268
268
|
|
|
269
269
|
```
|
|
270
|
-
1.
|
|
271
|
-
2.
|
|
272
|
-
3. Server Actions
|
|
273
|
-
4.
|
|
270
|
+
1. Render on every request
|
|
271
|
+
2. No cache
|
|
272
|
+
3. Update data with Server Actions
|
|
273
|
+
4. Invalidate only specific paths with revalidatePath
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
---
|
|
277
277
|
|
|
278
|
-
##
|
|
278
|
+
## Cache Invalidation Strategies
|
|
279
279
|
|
|
280
|
-
###
|
|
280
|
+
### Time-based
|
|
281
281
|
|
|
282
282
|
```typescript
|
|
283
|
-
// 60
|
|
283
|
+
// Regenerate every 60 seconds
|
|
284
284
|
export const revalidate = 60
|
|
285
285
|
|
|
286
286
|
const res = await fetch("...", { next: { revalidate: 60 } })
|
|
287
287
|
```
|
|
288
288
|
|
|
289
|
-
###
|
|
289
|
+
### On-demand (Server Actions)
|
|
290
290
|
|
|
291
291
|
```typescript
|
|
292
292
|
"use server"
|
|
@@ -296,34 +296,34 @@ import { revalidatePath, revalidateTag } from "next/cache"
|
|
|
296
296
|
export async function updatePost(id: string, data: PostInput) {
|
|
297
297
|
await prisma.post.update({ where: { id }, data })
|
|
298
298
|
|
|
299
|
-
//
|
|
299
|
+
// Path invalidation
|
|
300
300
|
revalidatePath(`/posts/${id}`)
|
|
301
301
|
|
|
302
|
-
//
|
|
302
|
+
// Tag invalidation
|
|
303
303
|
revalidateTag("posts")
|
|
304
304
|
}
|
|
305
305
|
```
|
|
306
306
|
|
|
307
307
|
---
|
|
308
308
|
|
|
309
|
-
##
|
|
309
|
+
## Best Practices
|
|
310
310
|
|
|
311
311
|
### ✅ DO
|
|
312
312
|
|
|
313
313
|
```typescript
|
|
314
|
-
// 1.
|
|
314
|
+
// 1. Use default cache for static data
|
|
315
315
|
const posts = await fetch("https://api.example.com/posts")
|
|
316
316
|
|
|
317
|
-
// 2.
|
|
317
|
+
// 2. Use no-store for dynamic data
|
|
318
318
|
const user = await fetch("https://api.example.com/user", {
|
|
319
319
|
cache: "no-store",
|
|
320
320
|
})
|
|
321
321
|
|
|
322
|
-
// 3.
|
|
322
|
+
// 3. Tag-based invalidation
|
|
323
323
|
const posts = await fetch("...", { next: { tags: ["posts"] } })
|
|
324
324
|
revalidateTag("posts")
|
|
325
325
|
|
|
326
|
-
// 4.
|
|
326
|
+
// 4. Function caching
|
|
327
327
|
const getCachedData = unstable_cache(
|
|
328
328
|
async () => prisma.post.findMany(),
|
|
329
329
|
["posts"],
|
|
@@ -334,18 +334,18 @@ const getCachedData = unstable_cache(
|
|
|
334
334
|
### ❌ DON'T
|
|
335
335
|
|
|
336
336
|
```typescript
|
|
337
|
-
// 1.
|
|
338
|
-
const user = await fetch("/api/user") // ❌
|
|
337
|
+
// 1. Caching sensitive data
|
|
338
|
+
const user = await fetch("/api/user") // ❌ Don't cache personal data
|
|
339
339
|
|
|
340
|
-
// 2.
|
|
341
|
-
revalidatePath("/") // ❌
|
|
340
|
+
// 2. Excessive revalidatePath
|
|
341
|
+
revalidatePath("/") // ❌ Invalidates entire site
|
|
342
342
|
|
|
343
|
-
// 3.
|
|
344
|
-
export const revalidate = 1 // ❌
|
|
343
|
+
// 3. Short revalidate interval
|
|
344
|
+
export const revalidate = 1 // ❌ Increases load
|
|
345
345
|
```
|
|
346
346
|
|
|
347
347
|
---
|
|
348
348
|
|
|
349
|
-
##
|
|
349
|
+
## References
|
|
350
350
|
|
|
351
351
|
- [Next.js Caching](https://nextjs.org/docs/app/building-your-application/caching)
|