@jgamaraalv/ts-dev-kit 1.0.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/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +24 -0
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/agents/accessibility-pro.md +139 -0
- package/agents/api-builder.md +110 -0
- package/agents/code-reviewer.md +190 -0
- package/agents/database-expert.md +138 -0
- package/agents/debugger.md +241 -0
- package/agents/docker-expert.md +51 -0
- package/agents/multi-agent-coordinator.md +378 -0
- package/agents/nextjs-expert.md +136 -0
- package/agents/performance-engineer.md +138 -0
- package/agents/playwright-expert.md +126 -0
- package/agents/react-specialist.md +97 -0
- package/agents/security-scanner.md +105 -0
- package/agents/test-generator.md +221 -0
- package/agents/typescript-pro.md +253 -0
- package/agents/ux-optimizer.md +93 -0
- package/docs/rules/orchestration.md.template +126 -0
- package/package.json +28 -0
- package/skills/bullmq/SKILL.md +225 -0
- package/skills/bullmq/references/flows-and-schedulers.md +186 -0
- package/skills/bullmq/references/job-types-and-options.md +163 -0
- package/skills/bullmq/references/patterns.md +273 -0
- package/skills/bullmq/references/production.md +308 -0
- package/skills/composition-patterns/SKILL.md +58 -0
- package/skills/composition-patterns/references/architecture-avoid-boolean-props.md +87 -0
- package/skills/composition-patterns/references/architecture-compound-components.md +107 -0
- package/skills/composition-patterns/references/patterns-children-over-render-props.md +77 -0
- package/skills/composition-patterns/references/patterns-explicit-variants.md +87 -0
- package/skills/composition-patterns/references/react19-no-forwardref.md +37 -0
- package/skills/composition-patterns/references/state-context-interface.md +194 -0
- package/skills/composition-patterns/references/state-decouple-implementation.md +96 -0
- package/skills/composition-patterns/references/state-lift-state.md +126 -0
- package/skills/conventional-commits/SKILL.md +148 -0
- package/skills/docker/SKILL.md +55 -0
- package/skills/docker/references/compose-configs.md +95 -0
- package/skills/docker/references/monorepo-dockerfile.md +111 -0
- package/skills/drizzle-pg/SKILL.md +202 -0
- package/skills/drizzle-pg/references/advanced.md +299 -0
- package/skills/drizzle-pg/references/migrations.md +214 -0
- package/skills/drizzle-pg/references/queries.md +321 -0
- package/skills/drizzle-pg/references/relations.md +272 -0
- package/skills/drizzle-pg/references/schema-pg.md +256 -0
- package/skills/drizzle-pg/references/sql-operator.md +215 -0
- package/skills/fastify-best-practices/SKILL.md +143 -0
- package/skills/fastify-best-practices/references/hooks-and-lifecycle.md +122 -0
- package/skills/fastify-best-practices/references/plugins-and-encapsulation.md +137 -0
- package/skills/fastify-best-practices/references/request-reply-errors.md +189 -0
- package/skills/fastify-best-practices/references/routes-and-handlers.md +134 -0
- package/skills/fastify-best-practices/references/server-and-options.md +127 -0
- package/skills/fastify-best-practices/references/typescript-and-logging.md +223 -0
- package/skills/fastify-best-practices/references/validation-and-serialization.md +190 -0
- package/skills/ioredis/SKILL.md +51 -0
- package/skills/ioredis/references/advanced-patterns.md +312 -0
- package/skills/ioredis/references/cluster-sentinel.md +280 -0
- package/skills/ioredis/references/connection-options.md +187 -0
- package/skills/ioredis/references/core-api.md +179 -0
- package/skills/nextjs-best-practices/SKILL.md +194 -0
- package/skills/nextjs-best-practices/references/async-patterns.md +84 -0
- package/skills/nextjs-best-practices/references/bundling.md +192 -0
- package/skills/nextjs-best-practices/references/data-patterns.md +310 -0
- package/skills/nextjs-best-practices/references/debug-tricks.md +127 -0
- package/skills/nextjs-best-practices/references/directives.md +74 -0
- package/skills/nextjs-best-practices/references/error-handling.md +237 -0
- package/skills/nextjs-best-practices/references/file-conventions.md +152 -0
- package/skills/nextjs-best-practices/references/font.md +175 -0
- package/skills/nextjs-best-practices/references/functions.md +116 -0
- package/skills/nextjs-best-practices/references/hydration-error.md +86 -0
- package/skills/nextjs-best-practices/references/image.md +184 -0
- package/skills/nextjs-best-practices/references/metadata.md +305 -0
- package/skills/nextjs-best-practices/references/parallel-routes.md +299 -0
- package/skills/nextjs-best-practices/references/route-handlers.md +154 -0
- package/skills/nextjs-best-practices/references/rsc-boundaries.md +168 -0
- package/skills/nextjs-best-practices/references/runtime-selection.md +40 -0
- package/skills/nextjs-best-practices/references/scripts.md +148 -0
- package/skills/nextjs-best-practices/references/self-hosting.md +210 -0
- package/skills/nextjs-best-practices/references/suspense-boundaries.md +67 -0
- package/skills/owasp-security-review/SKILL.md +98 -0
- package/skills/owasp-security-review/references/a01-broken-access-control.md +78 -0
- package/skills/owasp-security-review/references/a02-security-misconfiguration.md +81 -0
- package/skills/owasp-security-review/references/a03-supply-chain-failures.md +65 -0
- package/skills/owasp-security-review/references/a04-cryptographic-failures.md +82 -0
- package/skills/owasp-security-review/references/a05-injection.md +106 -0
- package/skills/owasp-security-review/references/a06-insecure-design.md +76 -0
- package/skills/owasp-security-review/references/a07-authentication-failures.md +83 -0
- package/skills/owasp-security-review/references/a08-integrity-failures.md +72 -0
- package/skills/owasp-security-review/references/a09-logging-alerting-failures.md +76 -0
- package/skills/owasp-security-review/references/a10-exceptional-conditions.md +131 -0
- package/skills/postgresql/SKILL.md +50 -0
- package/skills/postgresql/references/ddl-schema.md +300 -0
- package/skills/postgresql/references/indexes.md +257 -0
- package/skills/postgresql/references/jsonb.md +261 -0
- package/skills/postgresql/references/performance.md +291 -0
- package/skills/postgresql/references/psql-cli.md +153 -0
- package/skills/postgresql/references/queries.md +287 -0
- package/skills/postgresql/references/transactions.md +280 -0
- package/skills/react-best-practices/SKILL.md +110 -0
- package/skills/react-best-practices/references/advanced-patterns.md +91 -0
- package/skills/react-best-practices/references/async-patterns.md +233 -0
- package/skills/react-best-practices/references/bundle-optimization.md +201 -0
- package/skills/react-best-practices/references/client-patterns.md +178 -0
- package/skills/react-best-practices/references/js-performance.md +210 -0
- package/skills/react-best-practices/references/rendering-performance.md +209 -0
- package/skills/react-best-practices/references/rerender-optimization.md +316 -0
- package/skills/react-best-practices/references/server-performance.md +274 -0
- package/skills/service-worker/SKILL.md +195 -0
- package/skills/service-worker/references/api-reference.md +114 -0
- package/skills/service-worker/references/caching-strategies.md +202 -0
- package/skills/service-worker/references/push-and-sync.md +261 -0
- package/skills/typescript-conventions/SKILL.md +51 -0
- package/skills/ui-ux-guidelines/SKILL.md +105 -0
- package/skills/ui-ux-guidelines/references/accessibility-and-interaction.md +74 -0
- package/skills/ui-ux-guidelines/references/forms-content-checklist.md +126 -0
- package/skills/ui-ux-guidelines/references/layout-typography-animation.md +95 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Bundling
|
|
2
|
+
|
|
3
|
+
Fix common bundling issues with third-party packages.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Server-Incompatible Packages](#server-incompatible-packages)
|
|
8
|
+
- [CSS Imports](#css-imports)
|
|
9
|
+
- [Polyfills](#polyfills)
|
|
10
|
+
- [ESM/CommonJS Issues](#esmcommonjs-issues)
|
|
11
|
+
- [Common Problematic Packages](#common-problematic-packages)
|
|
12
|
+
- [Bundle Analysis](#bundle-analysis)
|
|
13
|
+
- [Migrating from Webpack to Turbopack](#migrating-from-webpack-to-turbopack)
|
|
14
|
+
|
|
15
|
+
## Server-Incompatible Packages
|
|
16
|
+
|
|
17
|
+
Some packages use browser APIs (`window`, `document`, `localStorage`) and fail in Server Components.
|
|
18
|
+
|
|
19
|
+
### Error Signs
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
ReferenceError: window is not defined
|
|
23
|
+
ReferenceError: document is not defined
|
|
24
|
+
ReferenceError: localStorage is not defined
|
|
25
|
+
Module not found: Can't resolve 'fs'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Solution 1: Mark as Client-Only
|
|
29
|
+
|
|
30
|
+
If the package is only needed on client:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// Bad: Fails - package uses window
|
|
34
|
+
import SomeChart from "some-chart-library";
|
|
35
|
+
|
|
36
|
+
export default function Page() {
|
|
37
|
+
return <SomeChart />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Good: Use dynamic import with ssr: false
|
|
41
|
+
import dynamic from "next/dynamic";
|
|
42
|
+
|
|
43
|
+
const SomeChart = dynamic(() => import("some-chart-library"), {
|
|
44
|
+
ssr: false,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export default function Page() {
|
|
48
|
+
return <SomeChart />;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Solution 2: Externalize from Server Bundle
|
|
53
|
+
|
|
54
|
+
For packages that should run on server but have bundling issues:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
// next.config.js
|
|
58
|
+
export default {
|
|
59
|
+
serverExternalPackages: ["problematic-package"],
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Use this for:
|
|
64
|
+
|
|
65
|
+
- Packages with native bindings (sharp, bcrypt)
|
|
66
|
+
- Packages that don't bundle well (some ORMs)
|
|
67
|
+
- Packages with circular dependencies
|
|
68
|
+
|
|
69
|
+
### Solution 3: Client Component Wrapper
|
|
70
|
+
|
|
71
|
+
Wrap the entire usage in a client component:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
// components/ChartWrapper.tsx
|
|
75
|
+
"use client";
|
|
76
|
+
|
|
77
|
+
import { Chart } from "chart-library";
|
|
78
|
+
|
|
79
|
+
export function ChartWrapper(props) {
|
|
80
|
+
return <Chart {...props} />;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// app/page.tsx (server component)
|
|
84
|
+
import { ChartWrapper } from "@/components/ChartWrapper";
|
|
85
|
+
|
|
86
|
+
export default function Page() {
|
|
87
|
+
return <ChartWrapper data={data} />;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## CSS Imports
|
|
92
|
+
|
|
93
|
+
Import CSS files instead of using `<link>` tags. Next.js handles bundling and optimization.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
// Bad: Manual link tag
|
|
97
|
+
<link rel="stylesheet" href="/styles.css" />;
|
|
98
|
+
|
|
99
|
+
// Good: Import CSS
|
|
100
|
+
import "./styles.css";
|
|
101
|
+
|
|
102
|
+
// Good: CSS Modules
|
|
103
|
+
import styles from "./Button.module.css";
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Polyfills
|
|
107
|
+
|
|
108
|
+
Next.js includes common polyfills automatically. Don't load redundant ones from polyfill.io or similar CDNs.
|
|
109
|
+
|
|
110
|
+
Already included: `Array.from`, `Object.assign`, `Promise`, `fetch`, `Map`, `Set`, `Symbol`, `URLSearchParams`, and 50+ others.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
// Bad: Redundant polyfills
|
|
114
|
+
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,Promise,Array.from" />
|
|
115
|
+
|
|
116
|
+
// Good: Next.js includes these automatically
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ESM/CommonJS Issues
|
|
120
|
+
|
|
121
|
+
### Error Signs
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
SyntaxError: Cannot use import statement outside a module
|
|
125
|
+
Error: require() of ES Module
|
|
126
|
+
Module not found: ESM packages need to be imported
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Solution: Transpile Package
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
// next.config.js
|
|
133
|
+
export default {
|
|
134
|
+
transpilePackages: ["some-esm-package", "another-package"],
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Common Problematic Packages
|
|
139
|
+
|
|
140
|
+
| Package | Issue | Solution |
|
|
141
|
+
| --------------- | --------------- | --------------------------------------------------------------- |
|
|
142
|
+
| `sharp` | Native bindings | `serverExternalPackages: ['sharp']` |
|
|
143
|
+
| `bcrypt` | Native bindings | `serverExternalPackages: ['bcrypt']` or use `bcryptjs` |
|
|
144
|
+
| `canvas` | Native bindings | `serverExternalPackages: ['canvas']` |
|
|
145
|
+
| `recharts` | Uses window | `dynamic(() => import('recharts'), { ssr: false })` |
|
|
146
|
+
| `react-quill` | Uses document | `dynamic(() => import('react-quill'), { ssr: false })` |
|
|
147
|
+
| `mapbox-gl` | Uses window | `dynamic(() => import('mapbox-gl'), { ssr: false })` |
|
|
148
|
+
| `monaco-editor` | Uses window | `dynamic(() => import('@monaco-editor/react'), { ssr: false })` |
|
|
149
|
+
| `lottie-web` | Uses document | `dynamic(() => import('lottie-react'), { ssr: false })` |
|
|
150
|
+
|
|
151
|
+
## Bundle Analysis
|
|
152
|
+
|
|
153
|
+
Analyze bundle size with the built-in analyzer (Next.js 16.1+):
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
next experimental-analyze
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
This opens an interactive UI to:
|
|
160
|
+
|
|
161
|
+
- Filter by route, environment (client/server), and type
|
|
162
|
+
- Inspect module sizes and import chains
|
|
163
|
+
- View treemap visualization
|
|
164
|
+
|
|
165
|
+
Save output for comparison:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
next experimental-analyze --output
|
|
169
|
+
# Output saved to .next/diagnostics/analyze
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Reference: https://nextjs.org/docs/app/guides/package-bundling
|
|
173
|
+
|
|
174
|
+
## Migrating from Webpack to Turbopack
|
|
175
|
+
|
|
176
|
+
Turbopack is the default bundler in Next.js 16.1.6+. If you have custom webpack config, migrate to Turbopack-compatible alternatives:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
// next.config.js
|
|
180
|
+
export default {
|
|
181
|
+
// Good: Works with Turbopack
|
|
182
|
+
serverExternalPackages: ["package"],
|
|
183
|
+
transpilePackages: ["package"],
|
|
184
|
+
|
|
185
|
+
// Bad: Webpack-only - migrate away from this
|
|
186
|
+
webpack: (config) => {
|
|
187
|
+
// custom webpack config
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Reference: https://nextjs.org/docs/app/building-your-application/upgrading/from-webpack-to-turbopack
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Data Patterns
|
|
2
|
+
|
|
3
|
+
Choose the right data fetching pattern for each use case.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Decision Tree](#decision-tree)
|
|
8
|
+
- [Pattern 1: Server Components (Preferred for Reads)](#pattern-1-server-components-preferred-for-reads)
|
|
9
|
+
- [Pattern 2: Server Actions (Preferred for Mutations)](#pattern-2-server-actions-preferred-for-mutations)
|
|
10
|
+
- [Pattern 3: Route Handlers (APIs)](#pattern-3-route-handlers-apis)
|
|
11
|
+
- [Avoiding Data Waterfalls](#avoiding-data-waterfalls)
|
|
12
|
+
- [Client Component Data Fetching](#client-component-data-fetching)
|
|
13
|
+
- [Quick Reference](#quick-reference)
|
|
14
|
+
|
|
15
|
+
## Decision Tree
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Need to fetch data?
|
|
19
|
+
├── From a Server Component?
|
|
20
|
+
│ └── Use: Fetch directly (no API needed)
|
|
21
|
+
│
|
|
22
|
+
├── From a Client Component?
|
|
23
|
+
│ ├── Is it a mutation (POST/PUT/DELETE)?
|
|
24
|
+
│ │ └── Use: Server Action
|
|
25
|
+
│ └── Is it a read (GET)?
|
|
26
|
+
│ └── Use: Route Handler OR pass from Server Component
|
|
27
|
+
│
|
|
28
|
+
├── Need external API access (webhooks, third parties)?
|
|
29
|
+
│ └── Use: Route Handler
|
|
30
|
+
│
|
|
31
|
+
└── Need REST API for mobile app / external clients?
|
|
32
|
+
└── Use: Route Handler
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Pattern 1: Server Components (Preferred for Reads)
|
|
36
|
+
|
|
37
|
+
Fetch data directly in Server Components - no API layer needed.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// app/users/page.tsx
|
|
41
|
+
async function UsersPage() {
|
|
42
|
+
// Direct database access - no API round-trip
|
|
43
|
+
const users = await db.user.findMany();
|
|
44
|
+
|
|
45
|
+
// Or fetch from external API
|
|
46
|
+
const posts = await fetch("https://api.example.com/posts").then((r) => r.json());
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<ul>
|
|
50
|
+
{users.map((user) => (
|
|
51
|
+
<li key={user.id}>{user.name}</li>
|
|
52
|
+
))}
|
|
53
|
+
</ul>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Benefits**:
|
|
59
|
+
|
|
60
|
+
- No API to maintain
|
|
61
|
+
- No client-server waterfall
|
|
62
|
+
- Secrets stay on server
|
|
63
|
+
- Direct database access
|
|
64
|
+
|
|
65
|
+
## Pattern 2: Server Actions (Preferred for Mutations)
|
|
66
|
+
|
|
67
|
+
Server Actions are the recommended way to handle mutations.
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// app/actions.ts
|
|
71
|
+
"use server";
|
|
72
|
+
|
|
73
|
+
import { revalidatePath } from "next/cache";
|
|
74
|
+
|
|
75
|
+
export async function createPost(formData: FormData) {
|
|
76
|
+
const title = formData.get("title") as string;
|
|
77
|
+
|
|
78
|
+
await db.post.create({ data: { title } });
|
|
79
|
+
|
|
80
|
+
revalidatePath("/posts");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function deletePost(id: string) {
|
|
84
|
+
await db.post.delete({ where: { id } });
|
|
85
|
+
|
|
86
|
+
revalidateTag("posts");
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// app/posts/new/page.tsx
|
|
92
|
+
import { createPost } from "@/app/actions";
|
|
93
|
+
|
|
94
|
+
export default function NewPost() {
|
|
95
|
+
return (
|
|
96
|
+
<form action={createPost}>
|
|
97
|
+
<input name="title" required />
|
|
98
|
+
<button type="submit">Create</button>
|
|
99
|
+
</form>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Benefits**:
|
|
105
|
+
|
|
106
|
+
- End-to-end type safety
|
|
107
|
+
- Progressive enhancement (works without JS)
|
|
108
|
+
- Automatic request handling
|
|
109
|
+
- Integrated with React transitions
|
|
110
|
+
|
|
111
|
+
**Constraints**:
|
|
112
|
+
|
|
113
|
+
- POST only (no GET caching semantics)
|
|
114
|
+
- Internal use only (no external access)
|
|
115
|
+
- Cannot return non-serializable data
|
|
116
|
+
|
|
117
|
+
## Pattern 3: Route Handlers (APIs)
|
|
118
|
+
|
|
119
|
+
Use Route Handlers when you need a REST API.
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// app/api/posts/route.ts
|
|
123
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
124
|
+
|
|
125
|
+
// GET is cacheable
|
|
126
|
+
export async function GET(request: NextRequest) {
|
|
127
|
+
const posts = await db.post.findMany();
|
|
128
|
+
return NextResponse.json(posts);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// POST for mutations
|
|
132
|
+
export async function POST(request: NextRequest) {
|
|
133
|
+
const body = await request.json();
|
|
134
|
+
const post = await db.post.create({ data: body });
|
|
135
|
+
return NextResponse.json(post, { status: 201 });
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**When to use**:
|
|
140
|
+
|
|
141
|
+
- External API access (mobile apps, third parties)
|
|
142
|
+
- Webhooks from external services
|
|
143
|
+
- GET endpoints that need HTTP caching
|
|
144
|
+
- OpenAPI/Swagger documentation needed
|
|
145
|
+
|
|
146
|
+
**When NOT to use**:
|
|
147
|
+
|
|
148
|
+
- Internal data fetching (use Server Components)
|
|
149
|
+
- Mutations from your UI (use Server Actions)
|
|
150
|
+
|
|
151
|
+
## Avoiding Data Waterfalls
|
|
152
|
+
|
|
153
|
+
### Problem: Sequential Fetches
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
// Bad: Sequential waterfalls
|
|
157
|
+
async function Dashboard() {
|
|
158
|
+
const user = await getUser(); // Wait...
|
|
159
|
+
const posts = await getPosts(); // Then wait...
|
|
160
|
+
const comments = await getComments(); // Then wait...
|
|
161
|
+
|
|
162
|
+
return <div>...</div>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Solution 1: Parallel Fetching with Promise.all
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
// Good: Parallel fetching
|
|
170
|
+
async function Dashboard() {
|
|
171
|
+
const [user, posts, comments] = await Promise.all([getUser(), getPosts(), getComments()]);
|
|
172
|
+
|
|
173
|
+
return <div>...</div>;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Solution 2: Streaming with Suspense
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// Good: Show content progressively
|
|
181
|
+
import { Suspense } from "react";
|
|
182
|
+
|
|
183
|
+
async function Dashboard() {
|
|
184
|
+
return (
|
|
185
|
+
<div>
|
|
186
|
+
<Suspense fallback={<UserSkeleton />}>
|
|
187
|
+
<UserSection />
|
|
188
|
+
</Suspense>
|
|
189
|
+
<Suspense fallback={<PostsSkeleton />}>
|
|
190
|
+
<PostsSection />
|
|
191
|
+
</Suspense>
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function UserSection() {
|
|
197
|
+
const user = await getUser(); // Fetches independently
|
|
198
|
+
return <div>{user.name}</div>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function PostsSection() {
|
|
202
|
+
const posts = await getPosts(); // Fetches independently
|
|
203
|
+
return <PostList posts={posts} />;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Solution 3: Preload Pattern
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
// lib/data.ts
|
|
211
|
+
import { cache } from "react";
|
|
212
|
+
|
|
213
|
+
export const getUser = cache(async (id: string) => {
|
|
214
|
+
return db.user.findUnique({ where: { id } });
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
export const preloadUser = (id: string) => {
|
|
218
|
+
void getUser(id); // Fire and forget
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
// app/user/[id]/page.tsx
|
|
224
|
+
import { getUser, preloadUser } from "@/lib/data";
|
|
225
|
+
|
|
226
|
+
export default async function UserPage({ params }) {
|
|
227
|
+
const { id } = await params;
|
|
228
|
+
|
|
229
|
+
// Start fetching early
|
|
230
|
+
preloadUser(id);
|
|
231
|
+
|
|
232
|
+
// Do other work...
|
|
233
|
+
|
|
234
|
+
// Data likely ready by now
|
|
235
|
+
const user = await getUser(id);
|
|
236
|
+
return <div>{user.name}</div>;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Client Component Data Fetching
|
|
241
|
+
|
|
242
|
+
When Client Components need data:
|
|
243
|
+
|
|
244
|
+
### Option 1: Pass from Server Component (Preferred)
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
// Server Component
|
|
248
|
+
async function Page() {
|
|
249
|
+
const data = await fetchData();
|
|
250
|
+
return <ClientComponent initialData={data} />;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Client Component
|
|
254
|
+
("use client");
|
|
255
|
+
function ClientComponent({ initialData }) {
|
|
256
|
+
const [data, setData] = useState(initialData);
|
|
257
|
+
// ...
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Option 2: Fetch on Mount (When Necessary)
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
"use client";
|
|
265
|
+
import { useEffect, useState } from "react";
|
|
266
|
+
|
|
267
|
+
function ClientComponent() {
|
|
268
|
+
const [data, setData] = useState(null);
|
|
269
|
+
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
fetch("/api/data")
|
|
272
|
+
.then((r) => r.json())
|
|
273
|
+
.then(setData);
|
|
274
|
+
}, []);
|
|
275
|
+
|
|
276
|
+
if (!data) return <Loading />;
|
|
277
|
+
return <div>{data.value}</div>;
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Option 3: Server Action for Reads (Works But Not Ideal)
|
|
282
|
+
|
|
283
|
+
Server Actions can be called from Client Components for reads, but this is not their intended purpose:
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
"use client";
|
|
287
|
+
import { getData } from "./actions";
|
|
288
|
+
import { useEffect, useState } from "react";
|
|
289
|
+
|
|
290
|
+
function ClientComponent() {
|
|
291
|
+
const [data, setData] = useState(null);
|
|
292
|
+
|
|
293
|
+
useEffect(() => {
|
|
294
|
+
getData().then(setData);
|
|
295
|
+
}, []);
|
|
296
|
+
|
|
297
|
+
return <div>{data?.value}</div>;
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Note**: Server Actions always use POST, so no HTTP caching. Prefer Route Handlers for cacheable reads.
|
|
302
|
+
|
|
303
|
+
## Quick Reference
|
|
304
|
+
|
|
305
|
+
| Pattern | Use Case | HTTP Method | Caching |
|
|
306
|
+
| ---------------------- | --------------------------- | ----------- | -------------------- |
|
|
307
|
+
| Server Component fetch | Internal reads | Any | Full Next.js caching |
|
|
308
|
+
| Server Action | Mutations, form submissions | POST only | No |
|
|
309
|
+
| Route Handler | External APIs, webhooks | Any | GET can be cached |
|
|
310
|
+
| Client fetch to API | Client-side reads | Any | HTTP cache headers |
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Debug Tricks
|
|
2
|
+
|
|
3
|
+
Tricks to speed up debugging Next.js applications.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [MCP Endpoint (Dev Server)](#mcp-endpoint-dev-server)
|
|
8
|
+
- [Rebuild Specific Routes (Next.js 16+)](#rebuild-specific-routes-nextjs-16)
|
|
9
|
+
|
|
10
|
+
## MCP Endpoint (Dev Server)
|
|
11
|
+
|
|
12
|
+
Next.js exposes a `/_next/mcp` endpoint in development for AI-assisted debugging via MCP (Model Context Protocol).
|
|
13
|
+
|
|
14
|
+
- **Next.js 16+**: Enabled by default, use `next-devtools-mcp`
|
|
15
|
+
- **Next.js < 16**: Requires `experimental.mcpServer: true` in next.config.js
|
|
16
|
+
|
|
17
|
+
Reference: https://nextjs.org/docs/app/guides/mcp
|
|
18
|
+
|
|
19
|
+
**Important**: Find the actual port of the running Next.js dev server (check terminal output or `package.json` scripts). Don't assume port 3000.
|
|
20
|
+
|
|
21
|
+
### Request Format
|
|
22
|
+
|
|
23
|
+
The endpoint uses JSON-RPC 2.0 over HTTP POST:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
curl -X POST http://localhost:<port>/_next/mcp \
|
|
27
|
+
-H "Content-Type: application/json" \
|
|
28
|
+
-H "Accept: application/json, text/event-stream" \
|
|
29
|
+
-d '{
|
|
30
|
+
"jsonrpc": "2.0",
|
|
31
|
+
"id": "1",
|
|
32
|
+
"method": "tools/call",
|
|
33
|
+
"params": {
|
|
34
|
+
"name": "<tool-name>",
|
|
35
|
+
"arguments": {}
|
|
36
|
+
}
|
|
37
|
+
}'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Available Tools
|
|
41
|
+
|
|
42
|
+
#### `get_errors`
|
|
43
|
+
|
|
44
|
+
Get current errors from dev server (build errors, runtime errors with source-mapped stacks):
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{ "name": "get_errors", "arguments": {} }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### `get_routes`
|
|
51
|
+
|
|
52
|
+
Discover all routes by scanning filesystem:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{ "name": "get_routes", "arguments": {} }
|
|
56
|
+
// Optional: { "name": "get_routes", "arguments": { "routerType": "app" } }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Returns: `{ "appRouter": ["/", "/api/users/[id]", ...], "pagesRouter": [...] }`
|
|
60
|
+
|
|
61
|
+
#### `get_project_metadata`
|
|
62
|
+
|
|
63
|
+
Get project path and dev server URL:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{ "name": "get_project_metadata", "arguments": {} }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Returns: `{ "projectPath": "/path/to/project", "devServerUrl": "http://localhost:3000" }`
|
|
70
|
+
|
|
71
|
+
#### `get_page_metadata`
|
|
72
|
+
|
|
73
|
+
Get runtime metadata about current page render (requires active browser session):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{ "name": "get_page_metadata", "arguments": {} }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Returns segment trie data showing layouts, boundaries, and page components.
|
|
80
|
+
|
|
81
|
+
#### `get_logs`
|
|
82
|
+
|
|
83
|
+
Get path to Next.js development log file:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{ "name": "get_logs", "arguments": {} }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Returns path to `<distDir>/logs/next-development.log`
|
|
90
|
+
|
|
91
|
+
#### `get_server_action_by_id`
|
|
92
|
+
|
|
93
|
+
Locate a Server Action by ID:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{ "name": "get_server_action_by_id", "arguments": { "actionId": "<action-id>" } }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Example: Get Errors
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
curl -X POST http://localhost:<port>/_next/mcp \
|
|
103
|
+
-H "Content-Type: application/json" \
|
|
104
|
+
-H "Accept: application/json, text/event-stream" \
|
|
105
|
+
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"get_errors","arguments":{}}}'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Rebuild Specific Routes (Next.js 16+)
|
|
109
|
+
|
|
110
|
+
Use `--debug-build-paths` to rebuild only specific routes instead of the entire app:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Rebuild a specific route
|
|
114
|
+
next build --debug-build-paths "/dashboard"
|
|
115
|
+
|
|
116
|
+
# Rebuild routes matching a glob
|
|
117
|
+
next build --debug-build-paths "/api/*"
|
|
118
|
+
|
|
119
|
+
# Dynamic routes
|
|
120
|
+
next build --debug-build-paths "/blog/[slug]"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use this to:
|
|
124
|
+
|
|
125
|
+
- Quickly verify a build fix without full rebuild
|
|
126
|
+
- Debug static generation issues for specific pages
|
|
127
|
+
- Iterate faster on build errors
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Directives
|
|
2
|
+
|
|
3
|
+
## React Directives
|
|
4
|
+
|
|
5
|
+
These are React directives, not Next.js specific.
|
|
6
|
+
|
|
7
|
+
### `'use client'`
|
|
8
|
+
|
|
9
|
+
Marks a component as a Client Component. Required for:
|
|
10
|
+
|
|
11
|
+
- React hooks (`useState`, `useEffect`, etc.)
|
|
12
|
+
- Event handlers (`onClick`, `onChange`)
|
|
13
|
+
- Browser APIs (`window`, `localStorage`)
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
"use client";
|
|
17
|
+
|
|
18
|
+
import { useState } from "react";
|
|
19
|
+
|
|
20
|
+
export function Counter() {
|
|
21
|
+
const [count, setCount] = useState(0);
|
|
22
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Reference: https://react.dev/reference/rsc/use-client
|
|
27
|
+
|
|
28
|
+
### `'use server'`
|
|
29
|
+
|
|
30
|
+
Marks a function as a Server Action. Can be passed to Client Components.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
"use server";
|
|
34
|
+
|
|
35
|
+
export async function submitForm(formData: FormData) {
|
|
36
|
+
// Runs on server
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or inline within a Server Component:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
export default function Page() {
|
|
44
|
+
async function submit() {
|
|
45
|
+
"use server";
|
|
46
|
+
// Runs on server
|
|
47
|
+
}
|
|
48
|
+
return <form action={submit}>...</form>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Reference: https://react.dev/reference/rsc/use-server
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Next.js Directive
|
|
57
|
+
|
|
58
|
+
### `'use cache'`
|
|
59
|
+
|
|
60
|
+
Marks a function or component for caching. Part of Next.js Cache Components.
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
"use cache";
|
|
64
|
+
|
|
65
|
+
export async function getCachedData() {
|
|
66
|
+
return await fetchData();
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Requires `cacheComponents: true` in `next.config.ts`.
|
|
71
|
+
|
|
72
|
+
For detailed usage including cache profiles, `cacheLife()`, `cacheTag()`, and `updateTag()`, see the `next-cache-components` skill.
|
|
73
|
+
|
|
74
|
+
Reference: https://nextjs.org/docs/app/api-reference/directives/use-cache
|