背景

个人空间项目(Space)最初使用 Ant Design Vue 构建,随着时间推移,组件风格与设计诉求产生了明显偏差——界面偏重、配色不够统一,缺乏整体的「简约科技风」质感。因此发起了这次 UI 全量重构,核心目标:

  • 组件库从 Ant Design Vue 迁移至 Element Plus
  • 主色调统一为淡蓝(#409EFF 系列)+ 白色
  • 建立完整的 SCSS 设计 Token 系统
  • 不新增业务功能,仅重构样式与交互

整个过程严格遵循 Speckit 工程规范,从立项到交付形成了完整的文档链路。


什么是 Speckit

Speckit 是一套面向 AI 辅助开发场景的结构化工程流程,核心理念是:先规范需求,再编码实现。它将一个功能的完整生命周期拆成五个有序阶段:

1
Constitution → Specify → Plan → Tasks → Implement

每个阶段都有对应的脚本与文档模板,确保 AI 的每一步行为都有据可查、可复盘。


Speckit 五阶段详解

第一阶段:Constitution(项目宪法)

目的:在项目启动时,用一份「宪法」固化所有不可动摇的原则与约束。

产出物.specify/memory/constitution.md

宪法的内容通常包含:

  • 技术栈约束(使用哪个框架、哪个组件库、哪种包管理器)
  • 业务边界(哪些功能在范围内,哪些明确排除)
  • 代码规范(命名风格、文件结构)
  • 性能与安全红线

本次重构的宪法片段:

1
2
3
4
5
6
7
8
9
## Core Principles

### I. 单一前端应用(Vue 3 SPA)
无需身份认证系统——单用户场景下所有路由均可直接访问。

### II. 组件库统一(Element Plus)
UI 组件库 MUST 使用 Element Plus(按需引入)。
禁止在新代码中引入 Ant Design Vue 组件。
主色调为淡蓝(#409EFF 系列)与白色。

宪法是整个项目的「最高法律」,后续所有规格说明和任务都必须符合宪法约束。


第二阶段:Specify(功能规格)

目的:将模糊的需求转化为可验收的用户故事和接受标准。

产出物specs/{feature-id}/ 目录,包含:

  • spec.md:用户故事 + 验收标准
  • checklists/requirements.md:质量检查清单

运行 create-new-feature.sh 脚本自动创建 feature branch 并初始化目录结构。

本次的 spec 包含 5 个用户故事(US),例如:

1
2
3
4
5
6
7
8
9
## US1 — 全局导航与布局
**As** 用户
**I want** 看到统一风格的顶部导航
**So that** 我能在不同模块间流畅切换

### Acceptance Criteria
- [ ] 导航使用 Element Plus 组件,无 Ant Design 残留
- [ ] 主色调符合 #409EFF 系列
- [ ] 移动端响应式正常

第三阶段:Plan(技术实施计划)

目的:在写代码之前,对实现方案进行深度调研,输出可执行的技术方案。

产出物

  • specs/{feature-id}/plan.md:整体实施计划
  • specs/{feature-id}/research.md:技术调研记录
  • specs/{feature-id}/data-model.md:数据模型文档

运行 setup-plan.sh 初始化 plan 目录后,重点调研内容包括:

调研项 结论
Element Plus 按需引入 使用 unplugin-auto-import + unplugin-vue-components
Ant Design → Element Plus 组件映射 a-buttonel-buttona-modalel-dialog,等
主题定制方案 通过 CSS 变量覆盖 :root { --el-color-primary: #409EFF }
Markdown 编辑器兼容性 @kangc/v-md-editor 与 Element Plus 共存无冲突

运行 update-agent-context.sh 将调研结论写入 AI 上下文,确保后续实现阶段 AI 能准确引用正确方案。


第四阶段:Tasks(任务分解)

目的:将规格说明拆解为原子级别的可执行任务列表,每个任务映射到具体文件路径。

产出物specs/{feature-id}/tasks.md

运行 check-prerequisites.sh --json --require-tasks 验证前置条件后生成任务列表。

任务的格式规范:

1
2
3
4
5
6
## Phase 1: Setup — 依赖安装与配置

- [ ] T001 卸载 ant-design-vue:在 package.json 中移除依赖
- [ ] T002 安装 Element Plus 及相关依赖
- [ ] T003 配置 Vite 插件:启用 Element Plus 按需引入
- [ ] T004 更新 src/main.ts:移除旧样式,引入新主题

关键设计原则:

  • 每个任务都有明确的文件路径
  • 标注 [P] 的任务可在同阶段内并行执行
  • 标注 [US1][US3] 等的任务可追溯到对应用户故事
  • 完成后立即在任务列表中标记 [x],保持实时同步

本次共生成 42 个任务,分 8 个 Phase 执行。


第五阶段:Implement(编码实现)

目的:严格按照 tasks.md 逐任务执行,完成一个标记一个。

核心纪律:

  1. 不跳任务:按 Phase 顺序执行,不提前跳到后面的 Phase
  2. 实时标记:每完成一个任务,立即在 tasks.md 中将 [ ] 改为 [x]
  3. 不偏离规格:如发现需求变化,应先更新 spec.md,再继续实现

技术实施细节

设计 Token 系统

建立了完整的 SCSS 变量体系,所有颜色、间距、圆角均通过变量管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 主色
$primary: #409EFF;
$primary-light: #66B1FF;
$primary-ghost: rgba(64, 158, 255, 0.08);
$primary-gradient: linear-gradient(135deg, #409EFF 0%, #337ECC 100%);

// 背景层次
$bg-primary: #FFFFFF; // 卡片背景
$bg-secondary: #F5F7FA; // 页面背景

// 间距基准 8px
$spacing-md: 12px;
$spacing-xl: 24px;
$spacing-xxl: 32px;

Element Plus 主题覆盖

通过 CSS 变量在 :root 层统一覆盖 Element Plus 默认主题:

1
2
3
4
5
6
7
8
// src/style/element-theme.scss
:root {
--el-color-primary: #409EFF;
--el-color-primary-light-3: #66B1FF;
--el-border-radius-base: 6px;
--el-border-radius-round: 10px;
--el-font-size-base: 14px;
}

Vite 按需引入配置

1
2
3
4
5
6
7
8
9
10
11
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
plugins: [
AutoImport({ resolvers: [ElementPlusResolver()] }),
Components({ resolvers: [ElementPlusResolver()] }),
]
})

TypeScript 配置修复

迁移过程中发现 @vue/tsconfig 0.1.3 使用了 TS 5.5+ 已删除的选项(preserveValueImportsimportsNotUsedAsValues),导致 IDE lint 报错。解决方案:放弃继承 @vue/tsconfig,改写独立配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "preserve",
"strict": true,
"isolatedModules": true,
"skipLibCheck": true,
"noEmit": true
}
}

踩坑记录

1. 空状态页面大面积空白

现象:笔记列表、动态广场在无数据时,页面出现大块难看的白色区域。

原因

  • 容器设置了 min-height: 100vh,无数据时整页被撑开
  • el-empty 组件孤立浮在页面中间

修复

1
2
3
4
5
6
7
8
9
10
// ❌ 原来
.posts-container { min-height: 100vh; }

// ✅ 修复后:用白色卡片包裹空状态
.empty-wrapper {
background: $bg-primary;
border-radius: $radius-xl;
padding: $spacing-4xl $spacing-xl;
border: 1px solid $border-lighter;
}

2. 页面背景层次不清

现象$bg-secondary (#F5F7FA)$bg-primary (#FFFFFF) 对比度过低,白色卡片在浅灰背景上看起来像一片空白。

修复:为内容卡片统一加上 border: 1px solid $border-lighterbox-shadow: $shadow-sm,通过轮廓而非颜色差建立层次感。

3. 不符合主题的硬编码颜色

现象:动画页头部使用了紫色渐变 linear-gradient(135deg, #667eea 0%, #764ba2 100%),与淡蓝白主题完全不符。

修复:将所有非品牌色改为使用 SCSS 变量,用全局搜索确保无遗漏:

1
rg "667eea|764ba2|f093fb" src/

Speckit 流程总结

阶段 输出物 核心价值
Constitution constitution.md 锁定不可变的技术边界和原则
Specify spec.md + 检查清单 将模糊需求转化为可验收标准
Plan plan.md + 调研文档 在编码前解决技术不确定性
Tasks tasks.md 将规格原子化为可执行指令
Implement 代码 + 实时打勾 确保实现与规格对齐

Speckit 的价值不只是让 AI 更可控,更重要的是它迫使开发者在动手之前把问题想清楚。宪法约束了边界,规格固化了验收标准,计划消除了技术风险,任务分解让进度可量化——这套流程同样适用于纯人工开发场景。


最终成果

  • ✅ 全量移除 Ant Design Vue,完整迁移至 Element Plus
  • ✅ 建立 SCSS 设计 Token 系统(变量、间距、阴影、动画)
  • ✅ TypeScript 类型检查零错误(pnpm vue-tsc --noEmit
  • ✅ 42 个任务全部完成,完整 Speckit 文档链路留存
  • ✅ 代码推送至 GitHub:Saberwode/space-v2

本文同时是一篇 Speckit 流程实践记录,希望对有类似 AI 辅助开发诉求的同学有所参考。