- migrate frontend to TypeScript (vue-tsc strict in build), upgrade all deps to latest (Vite 8, Tailwind 4, daisyUI 5, Pinia 4, vue-router 5) - restructure frontend dirs (api/components/common/layouts/styles/types/views) - drop Element Plus, add daisyUI TagInput; main CSS 490KB->163KB, entry JS 618KB->1.3KB - rewrite Dockerfile(.cn): frontend/backend stages pinned to $BUILDPLATFORM, CGO_ENABLED=0 cross-compile, no QEMU in multi-arch builds; add .dockerignore - local dev: Vite /api proxy + make dev targets; go:embed all:dist with .gitkeep so backend runs without prior frontend build - fix latent bugs: Keys.vue users ref, Settings.vue undefined userStore, Login.vue Ref-as-error display, res.error misuse - add REFACTOR_PLAN.md (phased refactor log)
18 KiB
18 KiB
opencatd-open 重构计划
本文档是重构过程的唯一进度记录,每完成一个阶段立即更新「阶段状态」与「执行记录」。 前后端同仓库,本期(第一期)只重构前端 + 前端相关的构建脚本;后端代码不在本期范围。
- 计划创建时间:2026-08-29
- 当前分支:
team(按约定不提交,所有改动留在工作区,由维护者回来后审查) - 项目根目录:
/Users/cjun/Code/Go/src/opencatd-open - 前端目录:
frontend/(构建产物dist/由 Go 通过//go:embed dist/*嵌入cmd/openteam)
一、背景与现状
| 项 | 现状 | 问题 |
|---|---|---|
| 技术栈 | Vue 3.5 + Vite 6 + JavaScript,无 TS | 依赖偏旧;无类型约束 |
| UI 库 | Element Plus 与 daisyUI/Tailwind 3 两套并存 | 9 个视图使用 el-* 组件,风格割裂、包体冗余 |
| 目录结构 | components/views 仅按 dashboard 简单分层 | 组件分类不规范,无 api/layouts/types 分层 |
| 构建脚本 | Dockerfile 三阶段,node 阶段未指定 $BUILDPLATFORM |
多架构构建时前端被 QEMU 模拟重复编译,极慢 |
| 依赖声明 | pinia、@iconify/vue 误放 devDependencies | 分类错误 |
| Dockerfile 杂项 | 存在无效的 CMD ["go mod tidy","go mod download"];node:20 基础镜像 |
需清理/升级 |
| 杂项 | 根目录 web/(仅 dist + node_modules,未跟踪) |
疑似误构建产物,暂不动,仅记录 |
二、已确认的决策(2026-08-29,维护者离开前确认)
- 迁移到 TypeScript(全量,含 vue-tsc 类型检查)。
- UI 统一到 Tailwind/daisyUI,移除 Element Plus,
el-*组件全部重写;接受外观变化。 - 不提交:所有改动留在工作区,按阶段推进,不做 git commit。
其余由执行者自行决定的默认约定:
- 依赖一律升到当前最新稳定版(含 Tailwind 4 / daisyUI 5 / Vite 7+ / Pinia 3 等大版本跨越)。
- Element Plus 在被移除前不再投入升级成本(Phase 4 直接删除)。
- 每阶段验收标准:
pnpm build(后期含vue-tsc)通过 + 页面路由/交互逻辑与重构前等价。 - 计划文档放项目根目录
REFACTOR_PLAN.md。
三、阶段计划
| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 0 | 创建本计划文档 | ✅ 完成 |
| Phase 1 | 依赖全部升级到最新版(Tailwind 4 / daisyUI 5 迁移、pinia 归位 dependencies) | ✅ 完成 |
| Phase 2 | TypeScript 迁移(tsconfig、vue-tsc、全量 .ts/.vue 改写) | ✅ 完成 |
| Phase 3 | 目录结构规范化(api / components / composables / layouts / types / views 分层) | ✅ 完成 |
| Phase 4 | 移除 Element Plus,统一 Tailwind/daisyUI 重写全部组件 | ✅ 完成 |
| Phase 5 | Docker / makefile 构建脚本更新(前端 $BUILDPLATFORM 单次编译) |
✅ 完成 |
| Phase 6 | 最终验证(前端 build + Go embed 编译),收尾文档 | ✅ 完成 |
四、各阶段详细方案
Phase 1 — 依赖升级
vite、@vitejs/plugin-vue、@vitejs/plugin-basic-ssl、vue、vue-router、axios、lucide-vue-next、qrcode.vue、@simplewebauthn/browser、@iconify/vue、@iconify-json/*→ 最新。pinia→ v3 并移入 dependencies;@iconify/vue移入 dependencies。- Tailwind 3 → 4:改用
@tailwindcss/vite插件,删除postcss.config.js/autoprefixer/tailwind.config.js,style.css改为@import "tailwindcss"+@plugin "daisyui"+@theme定义原有 daisyUI 主题集合(light/dark/cupcake/emerald/pastel)。 daisyui→ v5。- element-plus 保持现状(Phase 4 删除)。
- 验收:
pnpm build通过。
Phase 2 — TypeScript 迁移
- 新增
tsconfig.json(bundler 解析策略 +@别名路径映射)、src/vite-env.d.ts、env.d.ts(import.meta.env类型)。 vite.config.js→vite.config.ts;src/**/*.js(router/stores/utils/main)→.ts。- 全部
.vue改<script setup lang="ts">,props/emits/响应式数据补类型。 build脚本加vue-tsc --noEmit类型检查。- 验收:
pnpm build(含 vue-tsc)通过。
Phase 3 — 目录结构规范化
src/
├── api/ # axios 实例 + 各业务接口封装(由 utils/request.js 演进)
├── assets/ # 图片/图标(不变)
├── components/
│ ├── common/ # 通用组件(Toast、Pagination、QRCodeCard、LineSegmentFlow)
│ └── dashboard/ # 仪表盘布局组件(Sidebar、BreadcrumbHeader)
├── composables/ # 组合式函数(useToast 等从 provide/inject 演进)
├── layouts/ # 布局(DashboardLayout 等,如适用)
├── router/ # 路由
├── stores/ # pinia stores
├── styles/ # 全局样式
├── types/ # 共享 TS 类型(API 响应、业务实体)
├── utils/ # 纯工具函数(格式化日期等)
└── views/
├── auth/ # Login、Signup
├── error/ # 404
└── dashboard/ # Overview、Keys、Tokens、Users、Settings、Profile 等
- vite.config 的 manualChunks 别名同步更新。
- 验收:
pnpm build通过,无悬空 import。
Phase 4 — UI 统一到 Tailwind/daisyUI
- 移除
element-plus依赖与main.ts全局注册。 - 重写以下 9 个视图中的
el-*组件(table/dialog/form/select/input/switch/message 等用 daisyUI 组件类 + 自实现交互): Login、Signup、dashboard/{UserView、Settings、KeyView、Profile、TokenNew、KeyNew、UserNew}。 - 顺带规范既有自研组件(Toast、Pagination 等)使用 daisyUI 类。
- 保留既有业务逻辑、字段、接口调用不变。
- 验收:
pnpm build通过;grep el-/element-plus无残留。
Phase 5 — Docker / makefile 构建脚本
deploy/docker/Dockerfile:- 前端阶段
FROM --platform=$BUILDPLATFORM node:22-alpine AS frontend(多架构下只原生编译一次)。 - 后端阶段同样
$BUILDPLATFORM+CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH交叉编译(go.mod 使用纯 Go 的 glebarez/sqlite,可关闭 CGO);如遇阻塞则后端阶段回退为按目标平台编译,仅保留前端优化。 - 删除无效
CMD行;runner 阶段瘦身。
- 前端阶段
makefile:web 目标改用 pnpm(不强制全局安装 pnpm),构建产物位置与 embed 路径核对。- 同步更新
Dockerfile.cn(国内镜像版)保持一致。 - 验收:
docker build本地单架构通过(多架构如环境不允许则用--platform模拟检查语法与目标参数)。
Phase 6 — 最终验证与收尾
frontend: pnpm build(含 vue-tsc)。- 把
frontend/dist放入cmd/openteam/dist后执行go build ./cmd/openteam,确认 embed 成功。 - 更新本文档所有阶段状态与执行记录,列出遗留问题(如
web/目录处置、外观回归点)。
五、执行记录(每阶段完成后追加)
Phase 0 — 计划文档创建(2026-08-29)
- 已确认三项决策:TS 迁移 / 统一 Tailwind-daisyUI / 不提交。
- 摸底结论:前端约 4700 行 Vue;Element Plus 用于 9 个视图;pinia、@iconify/vue 在 devDependencies;
glebarez/sqlite为纯 Go 驱动(Docker 交叉编译可行);本地 Node v25.2.1 / pnpm 10.25.0。 - 发现根目录未跟踪的
web/目录仅含 dist 与 node_modules,疑似误产物,本期不动。
Phase 1 — 依赖升级(2026-08-29)✅
- 升级结果(均为当前最新稳定版):
- dependencies:vue 3.5.42、vue-router 5.3.0(大版本 4→5)、pinia 4.0.3(大版本 2→4,并移入 dependencies)、axios 1.20.0、qrcode.vue 3.10.0、@simplewebauthn/browser 13.3.0、@iconify/vue 5.0.1(移入 dependencies)、@lucide/vue 1.37.0(替代已废弃的 lucide-vue-next)。
- devDependencies:vite 8.2.2(大版本 6→8,构建器为 rolldown)、@vitejs/plugin-vue 6.0.8、@vitejs/plugin-basic-ssl 2.3.0、tailwindcss 4.3.3(大版本 3→4)、@tailwindcss/vite 4.3.3、daisyui 5.7.22(大版本 4→5)、@iconify-json/* 升级。
- 移除:autoprefixer、postcss、tailwind.config.js、postcss.config.js(Tailwind 4 改为 CSS-first 配置)。
- 迁移要点:
style.css改为@import "tailwindcss"+@plugin "daisyui",主题集合保持 light(默认)/dark/cupcake/emerald/pastel。vite.config.js加入@tailwindcss/vite插件;__dirname改为import.meta.dirname(消除 Vite 8 警告)。- package.json 改名为
opencatd-open-frontend;新增pnpm.onlyBuiltDependencies: [esbuild, vue-demi]放行构建脚本。
- 代码适配:新版 Lucide 移除品牌图标,
Profile.vue的<Github>图标改为项目内已有的<img src="/assets/github.svg">(与 Keys/KeyNew/KeyView 用法一致)。 - 验收:
pnpm build通过(4.8s,rolldown 构建)。 - 备注:element-plus 2.9.7 保持旧版未升级(Phase 4 将整体移除);当前 components chunk 406KB 主要来自 Element Plus,Phase 4 后预计大幅缩小。
Phase 2 — TypeScript 迁移(2026-08-29)✅
- 工具链:typescript 6.0.3 + vue-tsc 3.3.11 + @types/node 26.4.0。
- 注:最初装了 typescript 7.0.2(tsgo 原生版),但 vue-tsc 依赖
typescript/lib/tsc导出而 TS7 已移除,故回落到 6.x(当前最新 JS 版)。 - tsconfig:strict 模式、bundler 解析、
@别名(TS6 弃用 baseUrl,改用相对 paths)、types 含 vite/client + node。
- 注:最初装了 typescript 7.0.2(tsgo 原生版),但 vue-tsc 依赖
- 全量转换:
vite.config.ts、src/main.ts、router/stores/utils 共 9 个 JS→TS;19 个.vue全部<script setup lang="ts">。 - 类型设计:
src/types/index.ts:UserInfo / TokenInfo / ApiKey / PasskeyInfo 及各请求 Payload 类型(宽松可选字段 + 索引签名兼容后端松散返回)。src/composables/toast.ts:类型安全的 provide/inject(InjectionKey),替代各视图裸inject('toast')。vue-routerRouteMeta 模块扩展(title/icon/showInSidebar/requiresAuth 等);MenuItem 为可辨识联合。
- package.json:新增
typecheck脚本;build改为vue-tsc --noEmit && vite build。 - 顺带修复的存量 bug(均记录在案):
Keys.vuetoggleSelectAll 引用了不存在的users(应为keys)——运行时全选会抛错。Settings.vueupdateUser 引用了未定义的userStore/userId(复制粘贴残留),提交表单必抛错——改为经authStore.updateProfile更新当前用户。- store 的 catch 中
throw error抛出的是 Ref 对象,Login.vue会把 Ref 显示为[object Object]——加了errMsg()取值辅助。 KeyNew.vue模板绑定了不存在的togglePasswordVisibility(点击报 TypeError)——移除死绑定。User/Keys/UserNew/KeyNew里res.error恒为 undefined(AxiosResponse 无此字段)——改为res.data?.error。TokenNew.vue初始user_id: user.user_id(ComputedRef 上取值恒 undefined)——改为user.value?.user_id。Login.vuerember 记住密码存入布尔被 localStorage 转字符串('true'),统一String()存储。
- 验收:
pnpm build(含 vue-tsc 严格检查)通过。
Phase 3 — 目录结构规范化(2026-08-29)✅
- 最终结构:
src/api/client.ts← utils/request.ts(axios 实例与拦截器;业务接口调用仍保留在 stores 中,作为轻量 API 层,避免无谓 churn,后续可按需下沉到 api/ 各模块)src/components/common/← Toast / Pagination / QRCodeCard / LineSegmentFlowsrc/components/dashboard/保持(Sidebar / BreadcrumbHeader)src/layouts/DashboardLayout.vue← views/DashBoard.vue(本质是布局组件,归位 layouts 层)src/styles/main.css← src/style.csssrc/views/auth/← Login / Signup;src/views/error/NotFound.vue← views/404.vuesrc/views/Home.vue、src/views/dashboard/*保持
- 全部相对路径 import 统一为
@/别名;模板内相对资源路径(../assets/...)统一为@/assets/...。 - vite.config.ts 的 manualChunks 分包规则按新目录核对(components / views-dashboard / stores 三组仍有效)。
- 验收:
pnpm build通过,无悬空 import。
Phase 4 — UI 统一到 Tailwind/daisyUI(2026-08-29)✅
- 摸底修正:Element Plus 实际仅在 3 处使用(main.ts 全局注册 + KeyNew/KeyView 的
el-input-tag),其余视图本就以 daisyUI 为主。 - 变更:
main.ts移除 Element Plus 注册与样式;pnpm remove element-plus。- 新增
src/components/common/TagInput.vue(daisyUI 风格,Enter 添加/逐个删除/Backspace 删末尾/可清空),替换 KeyNew/KeyView 中的el-input-tag。 - 全库 grep 确认无
element-plus/el-*组件残留。
- 收益(构建产物对比):
- 主 CSS:489.6KB → 163.4KB(-67%,主要为 Element Plus 全量样式)
- components JS:405.7KB → 194.7KB(-52%)
- 入口 index JS:617.8KB → 1.3KB(Element Plus 运行时原本在入口包)
- 验收:
pnpm build(含类型检查)通过。
Phase 5 — Docker / makefile 构建脚本(2026-08-29)✅
deploy/docker/Dockerfile重写:- 前端阶段
FROM --platform=$BUILDPLATFORM node:22-alpine:多架构构建时前端只在构建机原生平台编译一次(原先会被 QEMU 模拟在每个目标平台各跑一遍)。 - 后端阶段同样
$BUILDPLATFORM+CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH交叉编译(glebarez/sqlite 纯 Go 驱动,已验证可行),全程零 QEMU。 - 删除了无效且写法错误的
CMD ["go mod tidy","go mod download"];pnpm 固定@10.25.0;pnpm install --frozen-lockfile;runner 阶段补充ca-certificates;修正LABEL anther→author;移除不再需要的cmake。 Dockerfile.cn(国内源版)同步更新。
- 前端阶段
- 新增根目录
.dockerignore(原先缺失:node_modules、dist、.git、web/ 等全部会被拷进构建上下文)。 makefile:web目标:pnpm 按需安装 +--frozen-lockfile,产物干净替换到cmd/openteam/dist(原mv dist ../cmd/openteam/在目标已存在时会错误嵌套一层)。build目标:加CGO_ENABLED=0;upx改为可选(本机未装时跳过,不再中断)。
- package.json 增加
"packageManager": "pnpm@10.25.0":新版 pnpm 默认启用供应链策略(拒装 24h 内发布的包)并不再读取 package.json 的pnpm字段,钉住版本保证容器内外行为一致、可重现。 - 验证:
docker build --target frontend通过,dist 产物完整。docker buildx build --platform linux/amd64,linux/arm64(xbuilder)通过;日志确认 frontend 仅在原生平台执行一次,arm64 后端为交叉编译,无 QEMU。- 本机
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build产出静态 ELF(含嵌入前端)。 make web、make build通过。
Phase 6 — 最终验证与收尾(2026-08-29)✅
pnpm build(vue-tsc 严格类型检查 + vite 构建)通过。.gitignore补充cmd/openteam/dist/(构建产物)与web/(误生成目录,未跟踪)。- 遗留事项(供维护者决策,均不影响本期交付):
frontend/src/utils/format-date.ts、Overview.vue内部仍各自实现了一份formatDateTime,可合并到 utils 统一导入(行为无差异,纯清理)。- CI workflow(
.github/workflows/)引用的./docker/Dockerfile路径早已失效(现为deploy/docker/Dockerfile),且 checkout 的还是 @v3 旧 action——后端/CI 不在本期范围,未改动。 - 依赖升级中未逐项验证运行时 UI 细节(如 daisyUI 4→5 的个别类名行为差异、vue-router 4→5),建议维护者回来后
make web && make build或pnpm dev过一遍登录/令牌/密钥/用户管理页面。 web/目录(仅 dist + node_modules)疑似误构建产物,已加入 .gitignore,确认无用后可删除。
六、后续增量(2026-08-29,维护者返程前追加)
增量 1 — 本地开发体验优化(前后端分离联调)✅
背景:前端构建产物经 //go:embed 嵌入 Go 二进制,本地每改一次前端都要 make web + make build,且没有热更新。
frontend/vite.config.ts:dev server 增加server.proxy,/api代理到本地 Go 后端(默认http://localhost:8080,VITE_DEV_API_TARGET可覆盖)。开发时前端跑在 Vite 上(HMR),接口走代理到后端,无跨域问题。- dev server 默认改为 HTTP(localhost 属浏览器安全上下文,clipboard/Passkey 均可用);需要自签名 HTTPS 时设
VITE_DEV_HTTPS=true恢复 basicSsl。
- dev server 默认改为 HTTP(localhost 属浏览器安全上下文,clipboard/Passkey 均可用);需要自签名 HTTPS 时设
cmd/openteam/main.go://go:embed dist/*→//go:embed all:dist,配合cmd/openteam/dist/.gitkeep占位(已跟踪),dist 没有真实产物时go run ./cmd/openteam也能编译启动——克隆后可直接起后端联调,不必先构建前端。make web移入产物后会补回.gitkeep。makefile新增:make dev-backend:PORT=8080 go run ./cmd/openteam(数据库./db/openteam.db)make dev-frontend:cd frontend && pnpm dev(5173)make dev:$(MAKE) -j2并行启动两者,Ctrl+C 一起退出
frontend/README.md补充开发文档(启动方式、环境变量表)。- 验证:后端 8080 + Vite 5173 同时运行,
curl http://localhost:5173/返回 SPA 页面;经 5173 代理的POST /api/auth/login返回后端真实校验 JSON、GET /api/auth/passkey/begin返回 200,代理链路完整。 - 说明:这是构建基础设施改动,触及
cmd/openteam/main.go一行 embed 指令;后端业务逻辑零改动。生产构建流程不受影响(Docker 内 dist 由前端阶段提供)。