@su-record/vibe 2.4.72 → 2.4.76
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.md +216 -215
- package/README.md +4 -4
- package/agents/research/best-practices-agent.md +13 -13
- package/agents/research/codebase-patterns-agent.md +33 -33
- package/agents/research/framework-docs-agent.md +23 -23
- package/agents/research/security-advisory-agent.md +29 -29
- package/agents/review/architecture-reviewer.md +31 -31
- package/agents/review/complexity-reviewer.md +21 -21
- package/agents/review/data-integrity-reviewer.md +29 -29
- package/agents/review/git-history-reviewer.md +24 -24
- package/agents/review/performance-reviewer.md +29 -29
- package/agents/review/python-reviewer.md +53 -53
- package/agents/review/rails-reviewer.md +40 -40
- package/agents/review/react-reviewer.md +40 -40
- package/agents/review/security-reviewer.md +29 -29
- package/agents/review/simplicity-reviewer.md +24 -24
- package/agents/review/test-coverage-reviewer.md +31 -31
- package/agents/review/typescript-reviewer.md +41 -41
- package/commands/vibe.analyze.md +103 -7
- package/commands/vibe.reason.md +106 -0
- package/commands/vibe.review.md +123 -38
- package/commands/vibe.run.md +286 -223
- package/commands/vibe.spec.md +425 -186
- package/commands/vibe.utils.md +104 -3
- package/commands/vibe.verify.md +179 -86
- package/dist/cli/detect.js +40 -40
- package/dist/cli/detect.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/llm.js +5 -5
- package/dist/cli/llm.js.map +1 -1
- package/dist/cli/setup.js +3 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/lib/ContextCompressor.js +1 -1
- package/dist/lib/ContextCompressor.js.map +1 -1
- package/dist/lib/MemoryManager.d.ts +13 -155
- package/dist/lib/MemoryManager.d.ts.map +1 -1
- package/dist/lib/MemoryManager.js +52 -617
- package/dist/lib/MemoryManager.js.map +1 -1
- package/dist/lib/gemini-api.js +12 -12
- package/dist/lib/gemini-api.js.map +1 -1
- package/dist/lib/gemini-oauth.js +22 -22
- package/dist/lib/gemini-oauth.js.map +1 -1
- package/dist/lib/gemini-storage.js +3 -3
- package/dist/lib/gemini-storage.js.map +1 -1
- package/dist/lib/gpt-api.js +11 -11
- package/dist/lib/gpt-api.js.map +1 -1
- package/dist/lib/gpt-oauth.js +28 -28
- package/dist/lib/gpt-oauth.js.map +1 -1
- package/dist/lib/gpt-storage.js +3 -3
- package/dist/lib/gpt-storage.js.map +1 -1
- package/dist/lib/memory/KnowledgeGraph.d.ts +34 -0
- package/dist/lib/memory/KnowledgeGraph.d.ts.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.js +216 -0
- package/dist/lib/memory/KnowledgeGraph.js.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.test.d.ts +2 -0
- package/dist/lib/memory/KnowledgeGraph.test.d.ts.map +1 -0
- package/dist/lib/memory/KnowledgeGraph.test.js +189 -0
- package/dist/lib/memory/KnowledgeGraph.test.js.map +1 -0
- package/dist/lib/memory/MemorySearch.d.ts +25 -0
- package/dist/lib/memory/MemorySearch.d.ts.map +1 -0
- package/dist/lib/memory/MemorySearch.js +85 -0
- package/dist/lib/memory/MemorySearch.js.map +1 -0
- package/dist/lib/memory/MemorySearch.test.d.ts +2 -0
- package/dist/lib/memory/MemorySearch.test.d.ts.map +1 -0
- package/dist/lib/memory/MemorySearch.test.js +149 -0
- package/dist/lib/memory/MemorySearch.test.js.map +1 -0
- package/dist/lib/memory/MemoryStorage.d.ts +77 -0
- package/dist/lib/memory/MemoryStorage.d.ts.map +1 -0
- package/dist/lib/memory/MemoryStorage.js +278 -0
- package/dist/lib/memory/MemoryStorage.js.map +1 -0
- package/dist/lib/memory/MemoryStorage.test.d.ts +2 -0
- package/dist/lib/memory/MemoryStorage.test.d.ts.map +1 -0
- package/dist/lib/memory/MemoryStorage.test.js +198 -0
- package/dist/lib/memory/MemoryStorage.test.js.map +1 -0
- package/dist/lib/memory/index.d.ts +4 -0
- package/dist/lib/memory/index.d.ts.map +1 -0
- package/dist/lib/memory/index.js +8 -0
- package/dist/lib/memory/index.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +4 -6
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/tools/convention/analyzeComplexity.d.ts +3 -1
- package/dist/tools/convention/analyzeComplexity.d.ts.map +1 -1
- package/dist/tools/convention/analyzeComplexity.js +102 -4
- package/dist/tools/convention/analyzeComplexity.js.map +1 -1
- package/dist/tools/convention/analyzeComplexity.test.d.ts +2 -0
- package/dist/tools/convention/analyzeComplexity.test.d.ts.map +1 -0
- package/dist/tools/convention/analyzeComplexity.test.js +207 -0
- package/dist/tools/convention/analyzeComplexity.test.js.map +1 -0
- package/dist/tools/convention/applyQualityRules.js +1 -1
- package/dist/tools/convention/applyQualityRules.js.map +1 -1
- package/dist/tools/convention/checkCouplingCohesion.js +2 -2
- package/dist/tools/convention/checkCouplingCohesion.js.map +1 -1
- package/dist/tools/convention/suggestImprovements.js +1 -1
- package/dist/tools/convention/suggestImprovements.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.d.ts +3 -1
- package/dist/tools/convention/validateCodeQuality.d.ts.map +1 -1
- package/dist/tools/convention/validateCodeQuality.js +145 -2
- package/dist/tools/convention/validateCodeQuality.js.map +1 -1
- package/dist/tools/convention/validateCodeQuality.test.d.ts +2 -0
- package/dist/tools/convention/validateCodeQuality.test.d.ts.map +1 -0
- package/dist/tools/convention/validateCodeQuality.test.js +230 -0
- package/dist/tools/convention/validateCodeQuality.test.js.map +1 -0
- package/dist/tools/memory/autoSaveContext.js +1 -1
- package/dist/tools/memory/autoSaveContext.js.map +1 -1
- package/dist/tools/memory/createMemoryTimeline.js +27 -27
- package/dist/tools/memory/createMemoryTimeline.js.map +1 -1
- package/dist/tools/memory/deleteMemory.js +1 -1
- package/dist/tools/memory/deleteMemory.js.map +1 -1
- package/dist/tools/memory/getMemoryGraph.js +24 -24
- package/dist/tools/memory/getMemoryGraph.js.map +1 -1
- package/dist/tools/memory/getSessionContext.js +36 -36
- package/dist/tools/memory/getSessionContext.js.map +1 -1
- package/dist/tools/memory/linkMemories.js +21 -21
- package/dist/tools/memory/linkMemories.js.map +1 -1
- package/dist/tools/memory/prioritizeMemory.js +1 -1
- package/dist/tools/memory/prioritizeMemory.js.map +1 -1
- package/dist/tools/memory/restoreSessionContext.js +1 -1
- package/dist/tools/memory/restoreSessionContext.js.map +1 -1
- package/dist/tools/memory/searchMemories.js +1 -1
- package/dist/tools/memory/searchMemories.js.map +1 -1
- package/dist/tools/memory/searchMemoriesAdvanced.js +42 -42
- package/dist/tools/memory/searchMemoriesAdvanced.js.map +1 -1
- package/dist/tools/memory/startSession.js +2 -2
- package/dist/tools/memory/startSession.js.map +1 -1
- package/dist/tools/memory/updateMemory.js +1 -1
- package/dist/tools/memory/updateMemory.js.map +1 -1
- package/dist/tools/semantic/analyzeDependencyGraph.js +38 -38
- package/dist/tools/semantic/analyzeDependencyGraph.js.map +1 -1
- package/dist/tools/semantic/findReferences.js +1 -1
- package/dist/tools/semantic/findReferences.js.map +1 -1
- package/dist/tools/semantic/findSymbol.js +1 -1
- package/dist/tools/semantic/findSymbol.js.map +1 -1
- package/dist/tools/time/getCurrentTime.js +1 -1
- package/dist/tools/time/getCurrentTime.js.map +1 -1
- package/dist/tools/ui/previewUiAscii.js +2 -2
- package/dist/tools/ui/previewUiAscii.js.map +1 -1
- package/hooks/hooks.json +11 -2
- package/hooks/scripts/llm-orchestrate.js +1 -1
- package/hooks/scripts/utils.js +31 -6
- package/languages/csharp-unity.md +82 -83
- package/languages/dart-flutter.md +89 -88
- package/languages/go.md +76 -75
- package/languages/java-spring.md +85 -84
- package/languages/kotlin-android.md +64 -63
- package/languages/python-django.md +83 -82
- package/languages/python-fastapi.md +82 -81
- package/languages/rust.md +75 -74
- package/languages/swift-ios.md +73 -72
- package/languages/typescript-electron.md +70 -71
- package/languages/typescript-nextjs.md +93 -92
- package/languages/typescript-node.md +64 -63
- package/languages/typescript-nuxt.md +113 -112
- package/languages/typescript-react-native.md +82 -81
- package/languages/typescript-react.md +76 -75
- package/languages/typescript-tauri.md +74 -75
- package/languages/typescript-vue.md +73 -72
- package/package.json +1 -1
- package/skills/git-worktree.md +25 -25
- package/skills/multi-llm-orchestration.md +4 -6
- package/skills/priority-todos.md +39 -39
- package/skills/vibe-capabilities.md +2 -2
- package/vibe/config.json +2 -2
|
@@ -1,36 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TypeScript + Nuxt 3 Quality Rules
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Core Principles (inherited from Vue)
|
|
4
4
|
|
|
5
5
|
```markdown
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
# Core Principles (inherited from Vue)
|
|
7
|
+
Single Responsibility (SRP)
|
|
8
|
+
No Duplication (DRY)
|
|
9
|
+
Reusability
|
|
10
|
+
Low Complexity
|
|
11
|
+
Function <= 30 lines, Template <= 100 lines
|
|
12
|
+
Nesting <= 3 levels
|
|
13
|
+
Composition API + script setup
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
## Nuxt 3
|
|
16
|
+
## Nuxt 3 Specific Rules
|
|
16
17
|
|
|
17
|
-
### 1. Auto-imports
|
|
18
|
+
### 1. Auto-imports Usage
|
|
18
19
|
|
|
19
20
|
```typescript
|
|
20
|
-
//
|
|
21
|
+
// Good: Nuxt 3 auto-imports (no explicit import needed)
|
|
21
22
|
<script setup lang="ts">
|
|
22
|
-
// ref, computed, watch
|
|
23
|
+
// ref, computed, watch etc Vue API auto-imported
|
|
23
24
|
const count = ref(0);
|
|
24
25
|
const doubled = computed(() => count.value * 2);
|
|
25
26
|
|
|
26
|
-
// useFetch, useAsyncData
|
|
27
|
+
// useFetch, useAsyncData etc Nuxt composables auto-imported
|
|
27
28
|
const { data } = await useFetch('/api/users');
|
|
28
29
|
|
|
29
|
-
// components/
|
|
30
|
-
// <UserCard />
|
|
30
|
+
// Components from components/ folder auto-imported
|
|
31
|
+
// <UserCard /> can be used directly
|
|
31
32
|
</script>
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
+
// Bad: Unnecessary imports
|
|
34
35
|
import { ref, computed } from 'vue';
|
|
35
36
|
import { useFetch } from '#app';
|
|
36
37
|
```
|
|
@@ -38,21 +39,21 @@ import { useFetch } from '#app';
|
|
|
38
39
|
### 2. Server API Routes
|
|
39
40
|
|
|
40
41
|
```typescript
|
|
41
|
-
//
|
|
42
|
+
// Good: server/api/users/index.get.ts (GET /api/users)
|
|
42
43
|
export default defineEventHandler(async (event) => {
|
|
43
44
|
const users = await prisma.user.findMany();
|
|
44
45
|
return users;
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
//
|
|
48
|
+
// Good: server/api/users/index.post.ts (POST /api/users)
|
|
48
49
|
export default defineEventHandler(async (event) => {
|
|
49
50
|
const body = await readBody(event);
|
|
50
51
|
|
|
51
|
-
//
|
|
52
|
+
// Validation
|
|
52
53
|
if (!body.email || !body.name) {
|
|
53
54
|
throw createError({
|
|
54
55
|
statusCode: 400,
|
|
55
|
-
message: '
|
|
56
|
+
message: 'Email and name are required',
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -60,7 +61,7 @@ export default defineEventHandler(async (event) => {
|
|
|
60
61
|
return user;
|
|
61
62
|
});
|
|
62
63
|
|
|
63
|
-
//
|
|
64
|
+
// Good: server/api/users/[id].get.ts (GET /api/users/:id)
|
|
64
65
|
export default defineEventHandler(async (event) => {
|
|
65
66
|
const id = getRouterParam(event, 'id');
|
|
66
67
|
|
|
@@ -69,14 +70,14 @@ export default defineEventHandler(async (event) => {
|
|
|
69
70
|
if (!user) {
|
|
70
71
|
throw createError({
|
|
71
72
|
statusCode: 404,
|
|
72
|
-
message: '
|
|
73
|
+
message: 'User not found',
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
return user;
|
|
77
78
|
});
|
|
78
79
|
|
|
79
|
-
//
|
|
80
|
+
// Good: server/api/users/[id].put.ts (PUT /api/users/:id)
|
|
80
81
|
export default defineEventHandler(async (event) => {
|
|
81
82
|
const id = getRouterParam(event, 'id');
|
|
82
83
|
const body = await readBody(event);
|
|
@@ -89,7 +90,7 @@ export default defineEventHandler(async (event) => {
|
|
|
89
90
|
return user;
|
|
90
91
|
});
|
|
91
92
|
|
|
92
|
-
//
|
|
93
|
+
// Good: server/api/users/[id].delete.ts (DELETE /api/users/:id)
|
|
93
94
|
export default defineEventHandler(async (event) => {
|
|
94
95
|
const id = getRouterParam(event, 'id');
|
|
95
96
|
await prisma.user.delete({ where: { id } });
|
|
@@ -97,45 +98,45 @@ export default defineEventHandler(async (event) => {
|
|
|
97
98
|
});
|
|
98
99
|
```
|
|
99
100
|
|
|
100
|
-
### 3. Data Fetching (SSR
|
|
101
|
+
### 3. Data Fetching (SSR Supported)
|
|
101
102
|
|
|
102
103
|
```typescript
|
|
103
|
-
//
|
|
104
|
+
// Good: useFetch - basic data fetching
|
|
104
105
|
<script setup lang="ts">
|
|
105
106
|
const { data: user, pending, error, refresh } = await useFetch<User>(
|
|
106
107
|
`/api/users/${props.userId}`
|
|
107
108
|
);
|
|
108
109
|
|
|
109
|
-
//
|
|
110
|
+
// With options
|
|
110
111
|
const { data: posts } = await useFetch('/api/posts', {
|
|
111
112
|
query: { limit: 10, offset: 0 },
|
|
112
113
|
headers: { 'X-Custom': 'value' },
|
|
113
|
-
pick: ['id', 'title'], //
|
|
114
|
-
transform: (data) => data.items, //
|
|
114
|
+
pick: ['id', 'title'], // Select only needed fields
|
|
115
|
+
transform: (data) => data.items, // Transform response
|
|
115
116
|
});
|
|
116
117
|
</script>
|
|
117
118
|
|
|
118
|
-
//
|
|
119
|
+
// Good: useAsyncData - custom fetching logic
|
|
119
120
|
<script setup lang="ts">
|
|
120
121
|
const { data, pending } = await useAsyncData(
|
|
121
|
-
'user-posts', //
|
|
122
|
+
'user-posts', // Cache key
|
|
122
123
|
() => $fetch(`/api/users/${props.userId}/posts`),
|
|
123
124
|
{
|
|
124
|
-
default: () => [], //
|
|
125
|
-
lazy: true, //
|
|
126
|
-
server: false, // SSR
|
|
125
|
+
default: () => [], // Default value
|
|
126
|
+
lazy: true, // Execute only on client
|
|
127
|
+
server: false, // Disable SSR
|
|
127
128
|
}
|
|
128
129
|
);
|
|
129
130
|
</script>
|
|
130
131
|
|
|
131
|
-
//
|
|
132
|
+
// Good: useLazyFetch - lazy loading (without Suspense)
|
|
132
133
|
<script setup lang="ts">
|
|
133
134
|
const { data, pending } = useLazyFetch('/api/heavy-data');
|
|
134
135
|
|
|
135
|
-
// pending
|
|
136
|
+
// Handle pending state
|
|
136
137
|
</script>
|
|
137
138
|
<template>
|
|
138
|
-
<div v-if="pending"
|
|
139
|
+
<div v-if="pending">Loading...</div>
|
|
139
140
|
<div v-else>{{ data }}</div>
|
|
140
141
|
</template>
|
|
141
142
|
```
|
|
@@ -143,9 +144,9 @@ const { data, pending } = useLazyFetch('/api/heavy-data');
|
|
|
143
144
|
### 4. State Management
|
|
144
145
|
|
|
145
146
|
```typescript
|
|
146
|
-
//
|
|
147
|
+
// Good: useState - server/client shared state
|
|
147
148
|
<script setup lang="ts">
|
|
148
|
-
//
|
|
149
|
+
// State shared across all components
|
|
149
150
|
const counter = useState('counter', () => 0);
|
|
150
151
|
|
|
151
152
|
function increment() {
|
|
@@ -153,7 +154,7 @@ function increment() {
|
|
|
153
154
|
}
|
|
154
155
|
</script>
|
|
155
156
|
|
|
156
|
-
//
|
|
157
|
+
// Good: Pinia Store (complex state)
|
|
157
158
|
// stores/user.ts
|
|
158
159
|
export const useUserStore = defineStore('user', () => {
|
|
159
160
|
const user = ref<User | null>(null);
|
|
@@ -179,17 +180,17 @@ export const useUserStore = defineStore('user', () => {
|
|
|
179
180
|
### 5. Middleware
|
|
180
181
|
|
|
181
182
|
```typescript
|
|
182
|
-
//
|
|
183
|
+
// Good: middleware/auth.ts (Named middleware)
|
|
183
184
|
export default defineNuxtRouteMiddleware((to, from) => {
|
|
184
185
|
const { isLoggedIn } = useUserStore();
|
|
185
186
|
|
|
186
|
-
//
|
|
187
|
+
// Protect pages requiring login
|
|
187
188
|
if (!isLoggedIn && to.meta.requiresAuth) {
|
|
188
189
|
return navigateTo('/login');
|
|
189
190
|
}
|
|
190
191
|
});
|
|
191
192
|
|
|
192
|
-
//
|
|
193
|
+
// Usage in page
|
|
193
194
|
<script setup lang="ts">
|
|
194
195
|
definePageMeta({
|
|
195
196
|
middleware: 'auth',
|
|
@@ -197,12 +198,12 @@ definePageMeta({
|
|
|
197
198
|
});
|
|
198
199
|
</script>
|
|
199
200
|
|
|
200
|
-
//
|
|
201
|
+
// Good: middleware/auth.global.ts (Global middleware)
|
|
201
202
|
export default defineNuxtRouteMiddleware((to, from) => {
|
|
202
|
-
//
|
|
203
|
+
// Applies to all routes
|
|
203
204
|
});
|
|
204
205
|
|
|
205
|
-
//
|
|
206
|
+
// Good: Server middleware
|
|
206
207
|
// server/middleware/auth.ts
|
|
207
208
|
export default defineEventHandler((event) => {
|
|
208
209
|
const token = getCookie(event, 'auth-token');
|
|
@@ -210,7 +211,7 @@ export default defineEventHandler((event) => {
|
|
|
210
211
|
if (!token && event.path.startsWith('/api/protected')) {
|
|
211
212
|
throw createError({
|
|
212
213
|
statusCode: 401,
|
|
213
|
-
message: '
|
|
214
|
+
message: 'Authentication required',
|
|
214
215
|
});
|
|
215
216
|
}
|
|
216
217
|
});
|
|
@@ -219,7 +220,7 @@ export default defineEventHandler((event) => {
|
|
|
219
220
|
### 6. Layouts & Pages
|
|
220
221
|
|
|
221
222
|
```typescript
|
|
222
|
-
//
|
|
223
|
+
// Good: layouts/default.vue
|
|
223
224
|
<template>
|
|
224
225
|
<div class="layout">
|
|
225
226
|
<AppHeader />
|
|
@@ -230,7 +231,7 @@ export default defineEventHandler((event) => {
|
|
|
230
231
|
</div>
|
|
231
232
|
</template>
|
|
232
233
|
|
|
233
|
-
//
|
|
234
|
+
// Good: layouts/admin.vue
|
|
234
235
|
<template>
|
|
235
236
|
<div class="admin-layout">
|
|
236
237
|
<AdminSidebar />
|
|
@@ -240,7 +241,7 @@ export default defineEventHandler((event) => {
|
|
|
240
241
|
</div>
|
|
241
242
|
</template>
|
|
242
243
|
|
|
243
|
-
//
|
|
244
|
+
// Good: pages/admin/index.vue
|
|
244
245
|
<script setup lang="ts">
|
|
245
246
|
definePageMeta({
|
|
246
247
|
layout: 'admin',
|
|
@@ -248,7 +249,7 @@ definePageMeta({
|
|
|
248
249
|
});
|
|
249
250
|
</script>
|
|
250
251
|
|
|
251
|
-
//
|
|
252
|
+
// Good: pages/users/[id].vue (dynamic route)
|
|
252
253
|
<script setup lang="ts">
|
|
253
254
|
const route = useRoute();
|
|
254
255
|
const userId = route.params.id;
|
|
@@ -256,7 +257,7 @@ const userId = route.params.id;
|
|
|
256
257
|
const { data: user } = await useFetch(`/api/users/${userId}`);
|
|
257
258
|
</script>
|
|
258
259
|
|
|
259
|
-
//
|
|
260
|
+
// Good: pages/posts/[...slug].vue (Catch-all route)
|
|
260
261
|
<script setup lang="ts">
|
|
261
262
|
const route = useRoute();
|
|
262
263
|
const slugParts = route.params.slug; // ['a', 'b', 'c']
|
|
@@ -266,7 +267,7 @@ const slugParts = route.params.slug; // ['a', 'b', 'c']
|
|
|
266
267
|
### 7. SEO & Meta
|
|
267
268
|
|
|
268
269
|
```typescript
|
|
269
|
-
//
|
|
270
|
+
// Good: Per-page meta configuration
|
|
270
271
|
<script setup lang="ts">
|
|
271
272
|
const { data: post } = await useFetch(`/api/posts/${route.params.id}`);
|
|
272
273
|
|
|
@@ -279,7 +280,7 @@ useHead({
|
|
|
279
280
|
],
|
|
280
281
|
});
|
|
281
282
|
|
|
282
|
-
//
|
|
283
|
+
// Or useSeoMeta
|
|
283
284
|
useSeoMeta({
|
|
284
285
|
title: post.value?.title,
|
|
285
286
|
ogTitle: post.value?.title,
|
|
@@ -289,7 +290,7 @@ useSeoMeta({
|
|
|
289
290
|
});
|
|
290
291
|
</script>
|
|
291
292
|
|
|
292
|
-
//
|
|
293
|
+
// Good: nuxt.config.ts global configuration
|
|
293
294
|
export default defineNuxtConfig({
|
|
294
295
|
app: {
|
|
295
296
|
head: {
|
|
@@ -308,7 +309,7 @@ export default defineNuxtConfig({
|
|
|
308
309
|
### 8. Plugins & Modules
|
|
309
310
|
|
|
310
311
|
```typescript
|
|
311
|
-
//
|
|
312
|
+
// Good: plugins/api.ts
|
|
312
313
|
export default defineNuxtPlugin(() => {
|
|
313
314
|
const api = $fetch.create({
|
|
314
315
|
baseURL: '/api',
|
|
@@ -333,11 +334,11 @@ export default defineNuxtPlugin(() => {
|
|
|
333
334
|
};
|
|
334
335
|
});
|
|
335
336
|
|
|
336
|
-
//
|
|
337
|
+
// Usage
|
|
337
338
|
const { $api } = useNuxtApp();
|
|
338
339
|
const users = await $api('/users');
|
|
339
340
|
|
|
340
|
-
//
|
|
341
|
+
// Good: plugins/dayjs.client.ts (client only)
|
|
341
342
|
import dayjs from 'dayjs';
|
|
342
343
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
343
344
|
|
|
@@ -350,7 +351,7 @@ export default defineNuxtPlugin(() => {
|
|
|
350
351
|
### 9. Composables
|
|
351
352
|
|
|
352
353
|
```typescript
|
|
353
|
-
//
|
|
354
|
+
// Good: composables/useAuth.ts
|
|
354
355
|
export function useAuth() {
|
|
355
356
|
const user = useState<User | null>('auth-user', () => null);
|
|
356
357
|
const isLoggedIn = computed(() => !!user.value);
|
|
@@ -372,7 +373,7 @@ export function useAuth() {
|
|
|
372
373
|
return { user, isLoggedIn, login, logout };
|
|
373
374
|
}
|
|
374
375
|
|
|
375
|
-
//
|
|
376
|
+
// Good: composables/usePagination.ts
|
|
376
377
|
export function usePagination<T>(
|
|
377
378
|
fetchFn: (page: number) => Promise<{ items: T[]; total: number }>
|
|
378
379
|
) {
|
|
@@ -401,7 +402,7 @@ export function usePagination<T>(
|
|
|
401
402
|
### 10. Error Handling
|
|
402
403
|
|
|
403
404
|
```typescript
|
|
404
|
-
//
|
|
405
|
+
// Good: error.vue (global error page)
|
|
405
406
|
<script setup lang="ts">
|
|
406
407
|
const props = defineProps<{
|
|
407
408
|
error: {
|
|
@@ -417,11 +418,11 @@ const handleError = () => clearError({ redirect: '/' });
|
|
|
417
418
|
<div class="error-page">
|
|
418
419
|
<h1>{{ error.statusCode }}</h1>
|
|
419
420
|
<p>{{ error.message }}</p>
|
|
420
|
-
<button @click="handleError"
|
|
421
|
+
<button @click="handleError">Go Home</button>
|
|
421
422
|
</div>
|
|
422
423
|
</template>
|
|
423
424
|
|
|
424
|
-
//
|
|
425
|
+
// Good: Component level error handling
|
|
425
426
|
<script setup lang="ts">
|
|
426
427
|
const { data, error } = await useFetch('/api/data');
|
|
427
428
|
|
|
@@ -433,89 +434,89 @@ if (error.value) {
|
|
|
433
434
|
}
|
|
434
435
|
</script>
|
|
435
436
|
|
|
436
|
-
//
|
|
437
|
+
// Good: NuxtErrorBoundary usage
|
|
437
438
|
<template>
|
|
438
439
|
<NuxtErrorBoundary @error="logError">
|
|
439
440
|
<SomeComponent />
|
|
440
441
|
<template #error="{ error, clearError }">
|
|
441
|
-
<p
|
|
442
|
-
<button @click="clearError"
|
|
442
|
+
<p>Error occurred: {{ error.message }}</p>
|
|
443
|
+
<button @click="clearError">Retry</button>
|
|
443
444
|
</template>
|
|
444
445
|
</NuxtErrorBoundary>
|
|
445
446
|
</template>
|
|
446
447
|
```
|
|
447
448
|
|
|
448
|
-
##
|
|
449
|
+
## File Structure (Nuxt 3)
|
|
449
450
|
|
|
450
|
-
```
|
|
451
|
+
```text
|
|
451
452
|
project/
|
|
452
|
-
├── .nuxt/ #
|
|
453
|
-
├── assets/ #
|
|
454
|
-
├── components/ #
|
|
455
|
-
│ ├── ui/ #
|
|
456
|
-
│ ├── features/ #
|
|
457
|
-
│ └── App*.vue #
|
|
458
|
-
├── composables/ #
|
|
459
|
-
├── layouts/ #
|
|
460
|
-
├── middleware/ #
|
|
461
|
-
├── pages/ #
|
|
462
|
-
├── plugins/ # Nuxt
|
|
463
|
-
├── public/ #
|
|
453
|
+
├── .nuxt/ # Build output (git ignored)
|
|
454
|
+
├── assets/ # Assets included in build
|
|
455
|
+
├── components/ # Auto-imported components
|
|
456
|
+
│ ├── ui/ # Base UI components
|
|
457
|
+
│ ├── features/ # Feature-specific components
|
|
458
|
+
│ └── App*.vue # App common components
|
|
459
|
+
├── composables/ # Auto-imported composables
|
|
460
|
+
├── layouts/ # Layouts
|
|
461
|
+
├── middleware/ # Route middleware
|
|
462
|
+
├── pages/ # File-based routing
|
|
463
|
+
├── plugins/ # Nuxt plugins
|
|
464
|
+
├── public/ # Static files
|
|
464
465
|
├── server/
|
|
465
|
-
│ ├── api/ # API
|
|
466
|
-
│ ├── middleware/ #
|
|
467
|
-
│ └── utils/ #
|
|
468
|
-
├── stores/ # Pinia
|
|
469
|
-
├── types/ # TypeScript
|
|
470
|
-
├── utils/ #
|
|
471
|
-
├── app.vue #
|
|
472
|
-
├── nuxt.config.ts # Nuxt
|
|
473
|
-
└── tsconfig.json # TypeScript
|
|
466
|
+
│ ├── api/ # API routes
|
|
467
|
+
│ ├── middleware/ # Server middleware
|
|
468
|
+
│ └── utils/ # Server utilities
|
|
469
|
+
├── stores/ # Pinia stores
|
|
470
|
+
├── types/ # TypeScript types
|
|
471
|
+
├── utils/ # Utility functions
|
|
472
|
+
├── app.vue # App root
|
|
473
|
+
├── nuxt.config.ts # Nuxt configuration
|
|
474
|
+
└── tsconfig.json # TypeScript configuration
|
|
474
475
|
```
|
|
475
476
|
|
|
476
|
-
##
|
|
477
|
+
## Anti-patterns
|
|
477
478
|
|
|
478
479
|
```typescript
|
|
479
|
-
//
|
|
480
|
+
// Bad: Direct DB access from client
|
|
480
481
|
<script setup>
|
|
481
482
|
import { PrismaClient } from '@prisma/client';
|
|
482
|
-
const prisma = new PrismaClient(); //
|
|
483
|
+
const prisma = new PrismaClient(); // Cannot run on client
|
|
483
484
|
</script>
|
|
484
485
|
|
|
485
|
-
//
|
|
486
|
+
// Good: Access through Server API
|
|
486
487
|
const { data } = await useFetch('/api/users');
|
|
487
488
|
|
|
488
|
-
//
|
|
489
|
+
// Bad: Conditional useFetch
|
|
489
490
|
if (someCondition) {
|
|
490
|
-
const { data } = await useFetch('/api/data'); //
|
|
491
|
+
const { data } = await useFetch('/api/data'); // Error
|
|
491
492
|
}
|
|
492
493
|
|
|
493
|
-
//
|
|
494
|
+
// Good: Use enabled option
|
|
494
495
|
const { data } = await useFetch('/api/data', {
|
|
495
496
|
immediate: someCondition,
|
|
496
497
|
});
|
|
497
498
|
|
|
498
|
-
//
|
|
499
|
+
// Bad: Using navigateTo outside setup
|
|
499
500
|
function handleClick() {
|
|
500
|
-
navigateTo('/page'); //
|
|
501
|
+
navigateTo('/page'); // Possible but not recommended
|
|
501
502
|
}
|
|
502
503
|
|
|
503
|
-
//
|
|
504
|
+
// Good: Use useRouter
|
|
504
505
|
const router = useRouter();
|
|
505
506
|
function handleClick() {
|
|
506
507
|
router.push('/page');
|
|
507
508
|
}
|
|
508
509
|
```
|
|
509
510
|
|
|
510
|
-
##
|
|
511
|
-
|
|
512
|
-
- [ ]
|
|
513
|
-
- [ ] Server API
|
|
514
|
-
- [ ]
|
|
515
|
-
- [ ]
|
|
516
|
-
- [ ]
|
|
517
|
-
- [ ]
|
|
518
|
-
- [ ]
|
|
519
|
-
- [ ] useHead/useSeoMeta
|
|
520
|
-
- [ ]
|
|
521
|
-
- [ ] TypeScript
|
|
511
|
+
## Checklist
|
|
512
|
+
|
|
513
|
+
- [ ] Use auto-imports (remove unnecessary imports)
|
|
514
|
+
- [ ] Follow Server API file naming convention (*.get.ts, *.post.ts)
|
|
515
|
+
- [ ] SSR-supported data fetching with useFetch/useAsyncData
|
|
516
|
+
- [ ] Server/client state sharing with useState
|
|
517
|
+
- [ ] Per-page meta with definePageMeta
|
|
518
|
+
- [ ] Route protection with middleware
|
|
519
|
+
- [ ] Error handling with NuxtErrorBoundary
|
|
520
|
+
- [ ] SEO optimization with useHead/useSeoMeta
|
|
521
|
+
- [ ] Logic reuse with Composables
|
|
522
|
+
- [ ] Use TypeScript strict mode
|