refactor(frontend): 前端架构重构与工程化升级(TypeScript + Pinia + Router + i18n)#1
refactor(frontend): 前端架构重构与工程化升级(TypeScript + Pinia + Router + i18n)#1
Conversation
There was a problem hiding this comment.
Pull request overview
This PR performs a major frontend refactor and engineering upgrade for MineDock: migrating the app to TypeScript, introducing Pinia + Vue Router + vue-i18n, and wiring in lint/format tooling with CI/Task integration.
Changes:
- Migrate frontend entry + API layer to TypeScript and add Pinia store + Router-based view structure.
- Add i18n initialization with zh-CN/en-US locale packs and a top-bar language switcher.
- Introduce ESLint (flat config) + Prettier scripts, add Taskfile tasks, and extend CI/Release workflows to run format/lint checks.
Reviewed changes
Copilot reviewed 31 out of 34 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/vite.config.js | Adds dev server proxy for /api. |
| frontend/tsconfig.node.json | Adds node/TS build config (currently mismatched with existing Vite config filename). |
| frontend/tsconfig.json | Adds main TS config with project references. |
| frontend/src/views/ContainerList.vue | New container list view with create/toggle/delete flows + modal UI. |
| frontend/src/stores/containers.ts | New Pinia store encapsulating instance operations and output logging. |
| frontend/src/router/index.ts | Adds router with / route to the container list view. |
| frontend/src/main.ts | New TS entry wiring Pinia + Router + i18n. |
| frontend/src/main.js | Removes old JS entry. |
| frontend/src/locales/zh-CN.json | Adds zh-CN translations. |
| frontend/src/locales/en-US.json | Adds en-US translations. |
| frontend/src/i18n.ts | Adds vue-i18n initialization and message schema typing. |
| frontend/src/env.d.ts | Adds TS module declaration for .vue. |
| frontend/src/components/TopBar.vue | Adds language-switch dropdown UI. |
| frontend/src/components/Sidebar.vue | Adds responsive sidebar UI (mobile overlay + desktop expand/collapse). |
| frontend/src/assets/main.css | Reworks global theme variables and layout styling. |
| frontend/src/api/index.ts | New TS API wrapper and typed Instance interface. |
| frontend/src/api/index.js | Removes old JS API wrapper. |
| frontend/src/App.vue | Replaces MVP single-page UI with shell layout + <router-view>. |
| frontend/package.json | Adds deps (pinia/router/i18n) and lint/format scripts + toolchain deps. |
| frontend/package-lock.json | Locks new dependency graph (includes Node engine constraints for ESLint packages). |
| frontend/index.html | Switches app entry to main.ts and updates title. |
| frontend/eslint.config.js | Adds ESLint flat config for TS/Vue. |
| frontend/.prettierrc.json | Adds Prettier config. |
| frontend/.prettierignore | Adds Prettier ignore rules. |
| docs/ops_engineering_standards.md | Updates ops/CI engineering standards text. |
| docs/domain_instance_lifecycle.md | Simplifies lifecycle doc and links to API contracts doc. |
| docs/02_API_Contracts.md | Adds API contract doc for instance lifecycle endpoints. |
| docs/01_Frontend_Standards.md | Adds frontend standards (i18n + CSS variables, etc.). |
| docs/01_Backend_Standards.md | Adds backend standards (error JSON example currently inconsistent with implementation). |
| docs/00_Root_Context.md | Updates project scope/boundaries + directory layout; contains a typo. |
| Taskfile.yml | Adds frontend fmt/lint tasks and global lint wiring. |
| .gitignore | Adds agent-related ignore entries. |
| .github/workflows/release.yml | Adds frontend fmt/lint checks in release workflow. |
| .github/workflows/ci.yml | Runs global fmt + lint checks in CI workflow. |
Files not reviewed (1)
- frontend/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| parser: tsParser, | ||
| project: "./tsconfig.json", | ||
| tsconfigRootDir: import.meta.dirname, | ||
| sourceType: "module", | ||
| ecmaVersion: "latest", |
There was a problem hiding this comment.
eslint.config.js uses import.meta.dirname for tsconfigRootDir. This property is not available in all Node 20 runtimes and can cause ESLint to crash in CI/local. Prefer deriving an absolute path from import.meta.url (via fileURLToPath/path.dirname) or use process.cwd() if the config is always run from the frontend directory.
frontend/src/api/index.ts
Outdated
| const resp = await fetch(`${BASE_URL}${path}`, { | ||
| headers: { "Content-Type": "application/json" }, | ||
| ...options, |
There was a problem hiding this comment.
The request() helper overwrites headers with a fixed { "Content-Type": "application/json" } and then spreads options. If callers pass options.headers, it will replace the entire header object (dropping Content-Type) rather than merging. Consider merging default headers with options.headers so custom headers can be added without accidentally removing defaults.
| const resp = await fetch(`${BASE_URL}${path}`, { | |
| headers: { "Content-Type": "application/json" }, | |
| ...options, | |
| const { headers, ...restOptions } = options; | |
| const resp = await fetch(`${BASE_URL}${path}`, { | |
| ...restOptions, | |
| headers: { | |
| "Content-Type": "application/json", | |
| ...(headers ?? {}), | |
| }, |
| } catch (err) { | ||
| printError(err as Error); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Several catches cast err as Error and then read .message. If a non-Error value is thrown (common with fetch/third-party libs), this will print ERROR: undefined and lose context. Consider normalizing unknown errors (e.g., err instanceof Error ? err : new Error(String(err))) before calling printError.
frontend/src/components/Sidebar.vue
Outdated
| <a href="#" class="menu-item active" @click.prevent> | ||
| <div class="menu-icon"> | ||
| <svg viewBox="0 0 24 24" fill="currentColor"> | ||
| <!-- 象征“容器/集装箱”的图标 --> | ||
| <path d="M4 8h16v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8zm0-4h16v2H4V4z" /> | ||
| </svg> | ||
| </div> | ||
| <div class="menu-text">{{ $t("sidebar.containerList") }}</div> | ||
| </a> |
There was a problem hiding this comment.
Sidebar navigation uses <a href="#" @click.prevent> even though Vue Router is introduced in this refactor. Using <RouterLink> (or a <button> when it isn't a real navigation) avoids dummy hrefs, improves accessibility, and keeps navigation consistent with router state (active class, history, etc.).
| - name: Run frontend format checks | ||
| run: task frontend:fmt | ||
|
|
||
| - name: Run frontend lint checks | ||
| run: task frontend:lint | ||
|
|
||
| - name: Build frontend once | ||
| run: task frontend:build |
There was a problem hiding this comment.
The added frontend fmt/lint steps can fail under Node "20" because some ESLint dependencies in package-lock.json require Node >=20.19.0. Consider pinning setup-node to >=20.19.x for the release workflow (or adjust the ESLint dependency versions to match the Node version constraint).
| }, | ||
| "engines": { | ||
| "node": "^20.19.0 || ^22.13.0 || >=24" | ||
| } |
There was a problem hiding this comment.
This lockfile entry requires Node ^20.19.0 || ^22.13.0 || >=24, which will cause npm install to fail on Node 20.0.x (including GitHub Actions setup-node: 20). Align CI/runtime Node versions accordingly or pin toolchain versions that support the intended Node baseline.
| - name: Run formatting checks | ||
| run: task fmt | ||
|
|
||
| - name: Run lint checks | ||
| run: task lint |
There was a problem hiding this comment.
The new lint/format steps can fail under the configured Node "20" because the newly added ESLint toolchain in frontend/package-lock.json declares engines like ^20.19.0 || .... Consider pinning the workflow Node version to >=20.19.x (or downgrading ESLint deps to versions compatible with Node 20.0.x).
| - 容器的生命周期管理与资源配额调度 | ||
| - 容器内游戏服务器的快速安装与运行 | ||
| - 在线终端交互与控制指令下发 | ||
| - 游戏数据的持久化与灾灾备 (快照、备份与回档) |
There was a problem hiding this comment.
Typo: "灾灾备" looks like a duplicated word. If this is meant to be "灾备" (disaster recovery) or "容灾备份", please correct to avoid confusion in the project scope description.
| - 游戏数据的持久化与灾灾备 (快照、备份与回档) | |
| - 游戏数据的持久化与灾备 (快照、备份与回档) |
| ## 编码质量与规范 | ||
| - **代码格式化与校验**:`go fmt` 与 `go vet` | ||
| - **错误处理**: | ||
| - 核心逻辑层要求显式返回 `error`,并在合适的网络层封装为统一规范的 JSON HTTP 响应体(如 `{"status": "error", "message": "..."}`)。 |
There was a problem hiding this comment.
The error response example uses {"status": "error", "message": "..."}, but the current backend handlers actually serialize errors under the error field (e.g., {"status":"error","error":"..."}). Please align this doc example with the implemented contract to avoid misleading API consumers.
| - 核心逻辑层要求显式返回 `error`,并在合适的网络层封装为统一规范的 JSON HTTP 响应体(如 `{"status": "error", "message": "..."}`)。 | |
| - 核心逻辑层要求显式返回 `error`,并在合适的网络层封装为统一规范的 JSON HTTP 响应体(如 `{"status": "error", "error": "..."}`)。 |
| "strict": true, | ||
| "skipLibCheck": true | ||
| }, | ||
| "include": ["vite.config.ts"] |
There was a problem hiding this comment.
tsconfig.node.json only includes "vite.config.ts", but this repo currently has vite.config.js (no vite.config.ts). This makes the Node TS project reference effectively empty and can break typechecking/linting expectations for the Vite config. Either rename/migrate the Vite config to vite.config.ts, or update the include to match the actual filename(s).
主要改动
影响范围