Files
global-coding-governance/vue-coding-style/references/architecture.md
2026-07-25 23:45:09 +08:00

6.6 KiB
Raw Permalink Blame History

Vue 架构与职责边界

目录

  • 结构原则
  • 组件边界
  • Composable
  • Pinia
  • Vue Router
  • API 与数据边界
  • 表单
  • SSR 与 Hydration
  • 依赖和公共 API
  • 官方依据

结构原则

  • 先遵循现有目录结构;不要在单个需求中引入第二套架构。
  • 新建中大型项目或独立业务域时,优先按 feature/domain 聚合页面、组件、composable、store、服务和类型;将真正跨域的稳定能力放入 shared
  • 避免把 components/utils/types/ 变成无边界仓库。目录名需表达所属业务或技术职责。
  • 只允许单向依赖:应用层可依赖共享层,共享层不得反向依赖具体页面或业务域。
  • 在浏览器、服务端、存储、网络和第三方 SDK 边界建立适配层,避免组件直接承载协议细节。

组件边界

  • 让页面组件负责路由级编排,让业务组件负责明确用例,让基础组件负责可复用交互和展示。
  • 组件同时承担数据请求、复杂业务计算、多块无关 UI 和跨域副作用时,按职责拆分。
  • 不按行数机械拆分;仅在职责、复用、测试隔离或性能边界更清晰时提取。
  • 保持公共组件 API 小而稳定。避免大量布尔 props 组合出互斥模式;使用判别联合、variant 或具名 slots。
  • 不让父组件通过 DOM 查询或 template ref 修改子组件内部状态。
  • 向下传递少量明确数据;深层跨树依赖使用 provide/inject 时定义 typed injection key,并提供缺失依赖处理。
  • 设计组件时覆盖默认、loading、empty、error、disabled 和只读等适用状态。

Composable

  • composable 封装可复用的有状态逻辑、生命周期或外部系统连接,不把纯函数包装成 composable。
  • 接收明确参数或响应式输入;不要隐式读取任意全局单例,除非该依赖就是契约的一部分。
  • 返回稳定、最小的公开 API。将 state 与操作区分清楚,必要时返回 readonly state。
  • 由创建资源的一方负责释放资源;在内部注册 cleanup,或向调用方暴露明确 stop/dispose
  • 避免一个 composable 同时处理请求、表单、路由、通知和持久化;按用例编排更小能力。
  • 对有宿主组件依赖的 composable 标明生命周期约束;纯响应式 composable 应可直接单测。

Pinia

  • 仅将跨组件、跨页面、需持久化或需 DevTools 跟踪的状态放入 store。
  • 每个 store 表达一个稳定业务域,使用唯一 id,并在独立文件定义。
  • state 保持最小;派生值使用 getters/computed;状态改变和业务动作通过 actions 或明确方法完成。
  • 不在组件外随意解构 store;在组件中用 storeToRefs 解构响应式 state/gettersactions 可直接解构。
  • setup store 必须返回所有应被 Pinia 管理的 state;不要依赖“私有 state”技巧破坏 SSR、DevTools 或插件行为。
  • 不在 store 中保存 Router/Route、DOM 元素或不可序列化第三方实例;这些依赖留在调用层或适配层。
  • 持久化仅保存必要字段,并处理版本迁移、过期、隐私与反序列化失败。
  • 测试 store 的公开 action、getter 和状态转移,不依赖内部实现顺序。

Vue Router

  • 页面级组件使用动态 import 做路由懒加载;不要把异步组件与路由懒加载混为一谈。
  • 优先命名路由,集中定义 path、name 和 meta 类型。
  • 将认证、权限和通用重定向放在合适的全局或路由级 guard;不要把所有页面业务塞入全局 guard。
  • guard 返回导航结果或抛出可处理错误;避免多次调用导航、隐式 fall-through 和未处理竞态。
  • 客户端路由权限只控制体验,不构成安全边界;后端必须独立授权。
  • 路由参数和 query 都是不可信字符串输入,使用前解析、校验并处理缺失或重复值。
  • 编程式导航需要时等待结果并处理 navigation failure。

API 与数据边界

  • 将 HTTP 客户端配置、认证头、错误归一化和序列化放入 API 基础层。
  • 按业务域定义 service/repository 函数,组件不直接拼接重复 URL 或处理底层响应结构。
  • 为请求参数和响应 DTO 提供类型;对不可信响应在运行时校验关键字段。
  • 在边界将 DTO 映射为前端领域模型,避免蛇形命名、nullable 约定和后端枚举扩散到整个 UI。
  • 支持请求取消或过期响应丢弃;切页、快速搜索和重复提交必须处理竞态。
  • 对 mutation 提供重复提交保护、幂等策略或清晰恢复方式。
  • 不在客户端持有服务端密钥。VITE_* 内容会进入客户端 bundle,只能存放公开配置。
  • 将用户可见错误转换为可行动信息,同时保留脱敏的诊断上下文。

表单

  • 分离原始 DTO、可编辑表单值、验证结果和提交 payload。
  • 明确字段 touched、dirty、validating、disabled 和 submitting 状态。
  • 客户端验证用于即时反馈,服务端仍是最终业务校验来源。
  • 服务端字段错误映射回对应控件,并提供表单级错误摘要或焦点移动。
  • 避免 watcher 组成不可追踪的双向同步链;建立单一数据源和显式 reset/submit 流程。
  • 离开页面可能丢失编辑内容时,按需求提供确认或草稿策略。

SSR 与 Hydration

  • 先识别项目是否为 Nuxt、SSR、SSG 或纯 SPA,再选择数据获取和生命周期位置。
  • 不在服务端共享请求级可变单例,避免用户间状态泄漏。
  • 将浏览器 API 放在客户端生命周期或带环境判断的适配层。
  • 保证服务端与首次客户端渲染结构一致;时间、随机数、locale 和设备判断需避免 hydration mismatch。
  • setup store、持久化插件和请求缓存必须符合项目 SSR 约定。

依赖和公共 API

  • 新增依赖前证明现有能力不足,并评估体积、维护状态、类型、许可证、SSR 和 tree-shaking。
  • 不因单个小功能引入大型工具库。
  • 公共组件、composable、store 和类型一旦被多个模块使用,即视为契约;修改时检查全部调用方并补充回归测试。
  • 删除或重命名公共导出前,先迁移调用方并确认兼容策略。

官方依据