Prompt Engineering for Nuxt

Rules 解决了"AI 知道项目规范"的问题,但每次具体的编码请求,你仍然需要写一个好的 Prompt。同样是"写一个视频上传组件",好的 Prompt 能让 AI 一次生成 90% 可用的代码,差的 Prompt 可能需要来回修改五六轮。本章总结面向 Nuxt4 开发的 Prompt 工程实践——不是通用的 Prompt 技巧,而是专门针对前端/全栈场景的实战方法论。

1. 高质量 Prompt 的五个要素

1.1 CRAFT 框架

要素英文说明示例
C Context上下文当前项目状态和技术栈"Nuxt4 项目,使用 Drizzle ORM"
R Role角色AI 应该扮演的角色"作为 Nuxt4 全栈开发者"
A Action行动具体要做什么"创建视频上传组件"
F Format格式输出格式要求"Vue SFC,使用 script setup"
T Target目标验收标准"支持分片上传、进度显示"

1.2 对比:差 Prompt vs 好 Prompt

差 Prompt

写一个上传组件

问题:不知道用什么框架、什么 UI 库、上传到哪里、要不要分片、需不需要进度条。AI 只能猜,大概率猜错。

好 Prompt

在 AI 视频平台(Nuxt4 + Nuxt UI)中,创建一个视频上传组件 `VideoUploader.vue`:

技术要求:
- 使用 `useChunkUpload` composable(已有,见 composables/useChunkUpload.ts)
- UI 使用 Nuxt UI 的 UButton、UProgress 组件
- 拖拽上传区域,支持点击选择文件
- 文件类型限制:video/*,最大 2GB

功能:
- 选择文件后显示文件名和大小
- 上传过程中显示进度条(百分比)
- 上传完成后跳转到 /video/[id]/edit
- 上传失败显示错误提示

不要:
- 不要创建新的 composable,使用现有的 useChunkUpload
- 不要用原生 fetch,useChunkUpload 内部已处理

好 Prompt 的特点:明确依赖(指出已有的 composable)、明确 UI 库(Nuxt UI)、明确行为(进度、跳转、错误处理)、明确边界(不要做什么)。

2. Nuxt 特定 Prompt 模式

2.1 创建 API 路由

创建 Nuxt Nitro API 路由 `server/api/videos/[id]/like.post.ts`:

功能:切换视频点赞状态(已赞则取消,未赞则添加)

要求:
- 使用 requireAuth(event) 做认证
- 使用 Zod 做空 body 校验(不需要参数)
- 操作 likes 表(schema 已在 packages/database/schema/likes.ts)
- 同时更新 videos 表的 likeCount(sql 原子操作)
- 返回 { liked: boolean }

参考现有路由:server/api/videos/[id]/danmaku.post.ts

关键技巧:指定参考文件。让 AI 看一个已有的类似实现,它会模仿风格和模式,比你用文字描述准确得多。

2.2 创建页面组件

创建 Nuxt 页面 `pages/video/[id].vue`:

数据获取:
- 使用 useFetch 获取 /api/videos/:id(SSR)
- 使用 useSeoMeta 设置标题、描述、OG 图片
- 404 时使用 showError({ statusCode: 404 })

组件组合:
- VideoPlayer(已有,props: src, poster)
- LikeButton(已有,props: videoId, initialLiked, initialCount)
- 视频标题、描述、标签、播放量、创建时间
- 相关视频推荐(调用 /api/videos/related?id=xxx)

布局:
- 使用 default layout
- 左侧 2/3 视频 + 信息,右侧 1/3 相关视频
- 响应式:移动端单列

2.3 创建 Composable

创建 composable `composables/useVideoFilter.ts`:

功能:视频列表的筛选和排序状态管理

输入:
- 初始查询参数从 route.query 读取

状态:
- category: string | null(分类筛选)
- sortBy: 'latest' | 'popular' | 'trending'
- duration: 'short' | 'medium' | 'long' | null

输出:
- query: computed 的查询参数对象(用于传给 useFetch)
- reset(): 重置所有筛选
- 每次状态变化自动同步到 URL query(使用 router.replace)

注意:
- SSR 安全(初始值从 route.query 读取)
- 不要在 composable 内调用 useFetch(由调用者负责)

3. 任务拆分策略

3.1 为什么要拆分

AI 模型有上下文窗口限制和注意力衰减——任务越大,出错概率越高。一个"创建完整的用户系统"的请求,AI 很可能遗漏边界情况;但拆成"创建用户注册 API"、"创建登录页面"、"创建个人资料页"等小任务,每个都能做得很好。

3.2 拆分原则

按层拆分(推荐用于新功能):

功能:视频收藏
├── 任务 1:数据库 schema(favorites 表 + migration)
├── 任务 2:API 路由(收藏/取消/列表)
├── 任务 3:Composable(useFavorite)
├── 任务 4:UI 组件(FavoriteButton + 收藏列表页)
└── 任务 5:测试

按功能拆分(推荐用于重构):

重构:视频状态管理
├── 任务 1:抽取 useVideoPlayer composable
├── 任务 2:抽取 useVideoProgress composable  
├── 任务 3:抽取 useVideoQuality composable
├── 任务 4:重构 VideoPlayer.vue 使用新 composables
└── 任务 5:验证所有功能正常

3.3 任务之间的上下文传递

拆分后的关键问题:后续任务需要知道前面的产出。两种方式:

方式 1:引用文件(Cursor / Windsurf)

上一步我们创建了 packages/database/schema/favorites.ts。
现在基于这个 schema,创建 API 路由:
- @packages/database/schema/favorites.ts
- 参考 @server/api/videos/[id]/like.post.ts 的风格

方式 2:总结传递(Claude Code / 新会话)

项目已有:
- favorites schema:id, userId, videoId, createdAt(唯一约束 userId+videoId)
- 用户系统:requireAuth(event) 返回 session.user.id

创建 server/api/favorites/ 下的 CRUD 路由

4. 多轮对话策略

4.1 渐进式细化

不要试图一次把所有需求说完。先给出核心需求,然后逐步细化:

第 1 轮:创建一个视频搜索页面,使用 /api/search 接口
         → AI 生成基础版本

第 2 轮:添加搜索防抖(300ms)和加载骨架屏
         → AI 在现有代码上增强

第 3 轮:搜索结果为空时显示推荐视频,从 /api/videos/popular 获取
         → AI 添加空状态处理

第 4 轮:添加搜索历史(localStorage),最多保存 10 条
         → AI 添加历史功能

这比一次写一个巨大的需求文档效果好得多——每一轮 AI 都能集中注意力在一个小的改进上。

4.2 修正与引导

AI 犯错时,不要重写整个 Prompt,而是精确指出问题:

差:重新生成,上次的不对
好:上面的代码有两个问题:
    1. useFetch 不应该在 onMounted 里调用,直接在 setup 顶层调用
    2. computed 里不要用 .value,直接引用 ref 变量名
    请修正这两处

5. Nuxt 开发 Prompt 模板库

5.1 创建 CRUD 模块

为 [实体名] 创建完整的 CRUD 模块:

数据库:
- Schema 文件:packages/database/schema/[实体].ts
- 字段:[列出字段和类型]
- 关系:[外键关系]

API 路由(server/api/[实体]/):
- index.get.ts:分页列表(支持 page, limit, search 参数)
- [id].get.ts:详情
- index.post.ts:创建(需要认证)
- [id].put.ts:更新(需要认证 + 权限检查)
- [id].delete.ts:删除(需要认证 + 权限检查)

所有路由使用 Zod 校验,返回 typed 响应。
参考现有的 videos 模块实现风格。

5.2 添加新功能

在现有 [页面/组件] 上添加 [功能名]:

当前代码:@[文件路径]

需要添加:
- [具体功能描述]
- [交互行为]
- [边界情况]

约束:
- 不要修改现有的 [xxx] 逻辑
- 使用现有的 [yyy] composable
- 保持与现有代码相同的风格

5.3 Bug 修复

Bug:[描述现象]
预期行为:[描述正确行为]
实际行为:[描述错误行为]
复现步骤:[1, 2, 3]

相关文件:
- @[文件 1]
- @[文件 2]

请分析根本原因并修复。如果需要看更多代码请告诉我。

5.4 代码重构

重构 @[文件路径]:

目标:[重构目标,如"拆分过长的组件"、"提取重复逻辑"]

当前问题:
- [问题 1]
- [问题 2]

约束:
- 保持所有现有功能不变
- 保持组件的 public API(props, emits)不变
- 新文件放在 [目录]

请先给出重构方案,我确认后再实施。

6. 常见陷阱与应对

6.1 AI 的常见错误

错误原因Prompt 中的防范
手动 import ref不知道 Nuxt 自动导入Rules 中声明 + Prompt 提醒
onMounted 中用 useFetch不理解 Nuxt 的 SSR 数据获取给出正确示例
生成 .js 文件默认行为明确指定 TypeScript
fetch 替代 $fetch通用习惯Rules 中 NEVER 声明
不处理加载/错误状态只关注 happy pathPrompt 中列出边界情况

6.2 提升 Prompt 效果的技巧

  • @引用文件:让 AI 看到真实代码,比文字描述准确 10 倍
  • 指定参考:"参考 xxx 的风格"比"遵循最佳实践"有效
  • 列出不要做的事:反约束比正约束更能减少错误
  • 先方案后实施:"先给方案,我确认再写代码"避免做无用功
  • 小步迭代:一次一个小功能,比一次做整个模块可靠

本章小结

  • CRAFT 框架:Context + Role + Action + Format + Target,好 Prompt 的五个要素
  • Nuxt 特定模式:API 路由、页面组件、Composable 各有对应的 Prompt 模板
  • 任务拆分:按层拆分(新功能)或按功能拆分(重构),每个子任务保持聚焦
  • 多轮策略:渐进式细化优于一次写完,精确修正优于重新生成
  • 模板库:CRUD 模块、添加功能、Bug 修复、代码重构四大模板覆盖 90% 场景
  • 防范陷阱:Rules 声明反模式 + Prompt 中指定参考文件 + 列出不要做的事