基于 WEB-UI-Development-Guide 标准的整体升级,并更名 LokiDeploy → opsx-loki。 前端(Gin+React+shadcn/ui): - 按 02/07 章重构:页面域化拆分(无超 400 行文件)、PageContainer/ListQuery、 反馈分级(成功静默/失败 toast/危险确认)、401 单飞刷新+队列重放 - 暗色模式(next-themes)+ 语义 Token(--primary 品牌色/success/warning/info) - 部署向导(状态推导四步:环境→存储→Loki→采集,内嵌表单闭环) - 日志查询页:LogQL 标签构建器/拖拽直方图/日志上下文/Live Tail/查询历史 - 按用户+标签策略的查询授权(服务端强制合并策略) 后端(Go+Gin+JSON DB): - 简单用户管理(仅 admin,无 RBAC)+ TokenVersion 会话吊销 + 登录 IP 限流 - LDAP 接入:配置(AES 加密存储/hasPassword 脱敏)/测试连接/批量导入/登录 - 存储配置测试连接(SigV4 零依赖)+ 桶不存在自动创建 - Loki 三模式部署修复:SSH 密钥认证、3.x 配置模板、ruler 对象存储嵌套块、 凭证解密、孤儿 deploying 状态恢复、Grafana 部署(可选默认关)+面板导入 - DaemonSet 采集纯 YAML(去 helm 依赖)+ DNS 自愈回退 ClusterIP + 集群名标签 - 日志查询代理:cluster-svc 经 kube-apiserver proxy/url 直连 + cursor 翻页 - 统一 log 命名空间;部署就绪探活;Grafana 访问地址自动记录 修复:run.sh 增量编译检测、Sanitized 脱敏补全、LokiDeployment Update 白名单、 健康检查 CreatedAt 零值等 10+ 存量 bug。 数据兼容:DB 沿用旧 lokideploy.json(新名优先);localStorage 一次性迁移; HKDF 加密前缀保留(已加密凭证不受影响)。
11 KiB
08 — 工程化与质量保障
参考:vue-vben-admin(Vite 配置工厂 + lefthook 流水线)、soybean-admin(eslint-config 工厂 + sa CLI)、vue-pure-admin(build/ 拆分 + env 开关能力)、ant-design-pro(Biome + 测试范式 + CI 矩阵)
一、构建配置组织
1.1 配置组织范式
vben:配置即内部包
internal/vite-config/ 提供 defineConfig({ application | library }) 工厂,
app 的 vite.config.ts 只剩 15 行(proxy 声明)
pure:根目录 build/ 拆分
build/{plugins,cdn,compress,optimize,utils,info}.ts,vite.config.ts 只做组装
(env 用 wrapperEnv 类型化读取)
soybean:build/plugins/ 按域拆文件
{router,unplugin,html,unocss,devtools}.ts 一文件一插件域
单工程标准:必须把 vite 配置按职责拆文件(plugins/env/proxy/compress),主配置只做组装;双栈工程的两个 vite 配置结构镜像(插件列表、alias、产物命名、proxy 规则逐项对齐)。
1.2 env 分层(三层结构)
| 层 | 形态 | 语义 | 说明 |
|---|---|---|---|
| 构建期烧录 | VITE_* |
打进产物,改了要重新构建 | API 前缀、功能开关 |
| 运行时可改 | VITE_GLOB_*(vben) |
构建时抽成 _app-config-{hash}.js 挂 window |
改 API 地址无需重构建 |
| 运行时 JSON | public/platform-config.json(pure) |
构建产物旁的配置文件,启动拉取注入 | 免重构建、免 window 挂载 |
| 纯 dev | proxy 端口等 | 只在 dev server 用 | — |
env 类型契约:每个 VITE_* 变量在 vite-env.d.ts 有类型与注释(soybean:联合类型直接收窄如 'static' | 'dynamic')。
1.3 dev server 要点(必须)
strictPort: true # 端口被占直接报错,不悄悄漂移
proxy '/api' → 后端端口
ws: true # 供 WebSocket(必须显式开)
changeOrigin: true
1.4 产物与指纹
- 构建注入版本:
define: { __APP_VERSION__, __COMMIT_HASH__ }(adp 用 git rev-parse 兜底)——设置页「关于」直接展示,排障救命 - 手工分包保留(radix/icons/charts/motion 等);新大依赖(图表/编辑器)必须评估独立 chunk + 懒加载
- 可选:构建压缩 env 开关(pure
VITE_COMPRESSION = none|gzip|brotli|both)、CDN 开关(VITE_CDN)、构建时间戳 banner
二、代码规范流水线
2.1 分层流水线(vben lefthook 范式)
pre-commit(仅 staged 文件):
快修复:oxlint --fix → oxfmt → eslint --fix → stylelint --fix
(stage_fixed 回填暂存区)
commit-msg:commitlint(conventional)
push/CI:慢检查全量 vue-tsc/tsc --noEmit + lint + madge 循环依赖
原则:快的在本地 pre-commit 自动修,慢的在 CI 卡。
soybean 的同构版本:@soybeanjs/eslint-config-vue 工厂(eslint.config.mjs 仅 14 行)+ vp lint(oxc 快扫)→ eslint(精修)双层;commit 由自研 sa CLI 交互生成并校验,scope 白名单单一数据源。pure 再补两块:stylelint(recess-order 属性排序)与 eslint-plugin-better-tailwindcss(校验 class 书写)。
2.2 必配清单(必须)
| 工具 | 要求 |
|---|---|
| ESLint(flat)+ Prettier | 双端同大版本、规则集可复制 |
| Stylelint | standard-scss + recommended-vue + 属性排序 |
| commitlint + husky + lint-staged | pre-commit 快修复、commit-msg 校验 |
preinstall: only-allow pnpm |
锁包管理器 |
Conventional Commits 类型集(commitlint type-enum,统一):feat / fix / docs / style / refactor / perf / test / chore / revert;scope 用功能域(user、rbac、cron、react……)。
any 管控:TS strict 端禁止裸 any——as any 需同行注释原因与消除计划;JS 端以 JSDoc @param/@returns 过渡,不允许出现「既无类型注释也无类型定义」的接口函数。
2.3 项目级 lint 增强(把各章规则自动化)
// eslint 配置片段(示意)
'no-console': ['warn', { allow: ['warn', 'error'] }] // 生产禁 console.log
'no-restricted-imports': // 示例层禁 import 系统层内聚单元
{ patterns: [{ group: ['@/views/system/*'], message: '示例层不得依赖系统层' }] }
vue/name: 'error' // 页面组件必须 defineOptions name(keep-alive 前置)
import/no-cycle: 'error' // 循环依赖
三、测试策略
3.1 管理端测试金字塔(务实版)
▲ E2E 冒烟(Playwright)
│ 登录→进列表→CRUD→登出 3-5 条主线,别贪多
├─ 组件/页面测试(Vitest + Testing Library)
│ 列表组件三态、表单弹窗校验与提交、菜单失败重试
├─ 组合函数测试(重点投入区,性价比最高)
│ usePagedQuery(取消/错序/分页边界)
│ permission 纯函数穷举
│ 请求层拦截器分支(401刷新/重放/静默)
└─ 纯函数单测
格式化、confirm、色阶算法
3.2 adp 测试范式(直接照抄)
// 重依赖 mock + 动态 import(vi.mock 提升到顶部,import 在 test 内)
vi.mock('@/services/user', () => ({ queryCurrentUser: vi.fn() }))
test('未登录访问受保护页重定向 login 并保留 redirect', async () => {
queryCurrentUser.mockRejectedValueOnce({ /* 401 */ })
const { getInitialState } = await import('@/app')
const redirect = await getInitialState()
expect(redirect).toContain('/user/login?redirect=')
})
关键点:纯函数穷举测试(permission/access 这类零成本高回报)、拦截器分支测试(请求层是事故高发区,mock adapter 驱动各分支)。
3.3 覆盖要求
- coverage 阈值必须配置(如 lines 70 / statements 70 / functions 60 / branches 70),排除生成代码
- E2E 至少覆盖:登录主线、一条 CRUD 主线、模块开关生效(若为底座)
- vben 是组件测试深度的标杆:连 Modal 的 keep-alive 场景都有单测
四、性能优化清单
| 手段 | 做法 | 出处 |
|---|---|---|
| 路由懒加载 | 全部页面 () => import();示例层可构建期 tree-shake |
通行 |
| 首屏占位 | index.html 注入 loading HTML(#root 空时先渲染骨架) | adp |
| 路由预取 | 菜单 hover prefetch / vite server.warmup 预热核心目录 |
adp/vben/pure |
| 图表懒加载 | Suspense/条件 import 包裹 ECharts 区块 | 通行 |
| chunk 失效恢复 | ChunkLoadError → 提示/自动 reload 一次(发版后旧 hash 404) | adp + 路由 onError |
| 请求防抖取消 | 列表页「取消 + 版本号」(见 03 章) | 本标准 |
| 大日期库治理 | moment→dayjs / 按需 locale | adp |
| WebSocket | 卸载断开 + 重连指数退避 + 心跳 | 监控类页面 |
| 长列表 | 虚拟滚动(日志类页面 >1000 行时) | 按需 |
度量先行:CI 加 rollup-plugin-visualizer 产物报告,chunk 超阈值(如 500KB)报警。
五、双端一致性规范(迁移期)
5.1 契约清单(迁移开始前统一,不等迁移完成)
| 项 | 统一值(推荐) | 说明 |
|---|---|---|
| token key | <app>.auth.token |
迁移期「读旧写新」一个版本 |
| 暗色 key | <app>.theme.mode |
同上 |
| 模块开关键 | <app>.modules.<name>.enabled |
常量两端同名,注释指向后端 API |
| 会话存储结构 | 字段名一致 | localStorage 布局对齐 |
| 响应契约 | 同一份 code/data/msg + 错误分级 | 见 03 章 |
| 权限语义 | 权限码清单同源(单一文档维护) | 见 04 章 |
| 路由路径 | 两端一致 | 互通书签 |
| ESLint / Prettier | 同大版本、同规则 | 配置可复制 |
执行方式:契约清单进 docs/(一页表),双端各引用;改任何一项 = 双端 PR 同步。副端纪律:不抢先实现主端没有的功能;mock 显式开关、生产禁用;每对齐一个域删除对应 mock(向真实收敛)。
六、CI/CD
6.1 标准流水线(adp 范式裁剪)
PR 触发:
job lint eslint + prettier --check + vue-tsc/tsc
job test vitest --coverage(阈值卡点)
job build vite build
job e2e 主分支 PR:playwright(webServer 自动拉起前后端)
main 合并:
构建产物部署(嵌入后端二进制 / 静态托管)
CI 增强项:madge 循环依赖检查、styles 入口引用检查、产物体积报告。CI 与本地命令同源(CI 里跑 make 目标,不另写一套脚本)。
七、文档与可观测性
7.1 文档治理(制度)
| 文档 | 责任 |
|---|---|
| 新模块指南 | 新模块五列表(菜单/路由/页面/API/权限码)同步 |
| 信息架构文档 | 分组/菜单行为描述与实现同步 |
| 删除性重构 | 过期段落归档,不留「描述已删除组件」的漂移文档 |
| CHANGELOG | 只描述现存功能 |
规则:实现与文档不一致 = 文档 bug,同一 PR 修复。
7.2 版本可观测
- 设置页「关于」展示
__APP_VERSION__/ commit hash / 构建时间(构建指纹注入) - 全局错误上报预留钩子(gva
core/error-handel.js式),先 console.error 收口,接 Sentry 留接口 - 可选:页面版本更新提示(pure 的 version-rocket:新版本发布后提醒用户刷新)
八、最佳实践清单
✅ 要做
- pre-commit 快修复 + CI 慢检查的分层流水线
- 请求层与权限纯函数优先补测试
- 双端 vite 配置结构镜像;契约清单一页表维护
- CI 与本地同源(make 目标)
- 每次构建带版本指纹,关于页可见
❌ 不要
- 不要双份 e2e/eslint 配置文件并存(配置漂移源头)
- 不要 CI 跑本地跑不通的命令(或反之)
- 不要 console.log 进生产(尤其 token 片段)
- 不要在 mock 数据里放真实用户名/密钥样式的假数据
- 不要为「以后可能用到」保留死配置、死样式、空目录
九、AI 检查清单(对比目标工程逐项核对)
P0(安全与一致性)
- 生产路径上是否有 console.log(尤其 token 片段打印)?
- 双端(若有)token/主题 key 是否同名?配置文件是否双份并存?
- mock 是否显式开关(是否存在网络错误静默回退假数据)?
P1(质量基建)
- lint 流水线是否分层(pre-commit 快修 + CI 慢查)?stylelint/commitlint 是否齐配?
- 请求层与权限纯函数是否有测试?coverage 阈值是否配置?
- CI 是否有循环依赖检查、产物体积报告?
- 构建指纹是否注入并在关于页展示?
P2(体验与治理)
- 文档漂移清单(描述已不存在实现的文档段落)列出并归档
- 运行时配置(VITE_GLOB / platform-config.json)是否值得引入
- 错误上报钩子是否预留
至此八章完毕。回到 00-目录与概览 复查十大黄金法则,或按各章「AI 检查清单」逐项对比目标工程输出优化任务。