Appearance
编码约定
文件命名
- 组件:
PascalCase.vue(如TextNode.vue、CanvasToolbar.vue) - Composables:
useCamelCase.ts(如useCanvas.ts、useNodeActions.ts) - Store:
camelCase.ts(如canvasStore.ts) - 工具函数:
camelCase.ts - 类型定义:与使用者同文件,或
types/目录下camelCase.ts - 测试文件:
[filename].test.ts(单元测试)、[filename].spec.ts(E2E 测试)
目录结构
- 页面组件 →
pages/(Nuxt 文件路由) - 跨页面共享组件 →
components/ - 仅单页面使用的组件 → 该页面目录内
- Vue Flow 自定义节点 →
components/nodes/ - 全局状态 →
stores/ - Composables →
composables/ - AI 服务 →
services/ai/ - HTTP 客户端 →
services/http/ - 类型定义 →
types/
组件规范
- 使用
<script setup lang="ts"> - Props 必须类型化:
defineProps<{ ... }>() - Emits 必须类型化:
defineEmits<{ ... }>() - 组件最大约 200 行,超出则拆分子组件
- 优先使用 Nuxt UI 组件
Vue Flow 自定义节点
- 每种节点类型一个组件文件(
TextNode.vue、ImageNode.vue等) - 节点组件统一放在
components/nodes/ - 节点内部配置(Prompt、模型选择、生成按钮)内嵌在节点组件中,不使用外部面板
- 连接点使用 Vue Flow 的
<Handle>组件
状态管理
- 本地状态:仅当前组件使用的数据,用
ref/reactive - 全局 Store:跨组件共享的数据(画布列表、当前画布),用 Pinia
- Vue Flow 状态:节点和连线数据,通过
useVueFlowcomposable 管理
样式
- 使用 Nuxt UI 内置样式体系
- 自定义样式优先用 Tailwind 工具类
- 使用 Nuxt UI canonical class(如
border-default、bg-muted、text-highlighted),禁止使用 CSS 变量引用形式(如border-(--ui-border)、bg-(--ui-bg-muted)) - 深色主题:使用 CSS 变量,所有颜色值走主题变量
- 避免内联
style,除非是动态计算值(如节点位置)
TypeScript
- 严格模式,禁止
any - 优先
interface(对象形状),type(联合类型/交叉类型) - 使用
as const替代 enum
Import 排序
由 ESLint 自动处理,规则如下:
- Vue / Nuxt 框架导入(
vue、nuxt/app、#imports) - 第三方库(
@vue-flow/core、pinia等) - 项目内模块(
~/composables、~/stores、~/types等)
各组之间保留一个空行。
测试
- 单元测试框架:Vitest
- 组件测试:
@vue/test-utils+happy-dom - E2E 测试:Playwright
- 单元测试放在
test/unit/,Nuxt 集成测试放在test/nuxt/,E2E 测试放在tests/ - 运行命令:
pnpm test(全部)、pnpm test:unit(单元)、pnpm test:e2e(E2E)
禁止模式(Anti-patterns)
以下是开发和 AI agent 生成代码时常犯的错误,必须避免:
状态管理
- 禁止在 action 外直接修改 store state — 所有状态变更必须通过 store action,不得在组件中直接赋值
store.someState = newValue - 禁止 store 间循环依赖 — store 依赖必须是单向的,不得 A store 调用 B store 且 B store 调用 A store
- 禁止在 computed 中执行副作用 — computed 只做纯计算,不得在其中调用 API、修改 state 或触发导航
异步与错误处理
- 禁止忽略 async 错误 — 所有异步操作(API 调用、文件操作)必须有 try/catch 或
.catch()处理 - 禁止在组件卸载后操作 DOM 或更新 state — 异步回调中必须检查组件是否仍然挂载,或使用 AbortController
- 禁止
await在<script setup>顶层使用而不包在 Suspense 中 — 会阻塞组件渲染
数据流
- 禁止双向数据绑定绕过单向数据流 — 子组件不得直接修改 props,必须通过 emit 通知父组件
- 禁止在 watcher 中触发被 watch 的值变更 — 会造成无限循环
- 禁止将 Vue Flow 内部状态当作 source of truth — 持久化数据以 canvasStore 为准,Vue Flow 仅用于渲染
Import 与依赖
- 禁止从
packages/shared引入运行时逻辑 — shared 包只包含类型和常量 - 禁止组件直接调用 HTTP 客户端 — 必须通过 services 层封装,组件 → composable → service → HTTP
- 禁止在
components/中放非组件文件 — 工具函数放utils/,composable 放composables/
Git
- 分支命名:
feat/xxx、fix/xxx、refactor/xxx - Commit 使用 conventional commits:
feat:、fix:、refactor:、docs:、chore: