Appearance
1.2 技术选型与项目结构
AI CODING · STAGE 1 · ARCHITECTURE
把技术选择、目录责任和依赖方向写进 architecture 文件。后续 diff 越界时,按这份约定退回。
时间 40–60 分钟改动 docs/architecture.md目录 4
Runtime
uni-app · Vue 3
本阶段验收 H5。页面组合状态与导航,组件展示数据并上报动作。
Contract
TypeScript
StageId 与 Recommendation 锁住阶段和推荐接口,不维护第二套别名。
Check
Vitest
确定性规则放进 unit test。component event 和导航另走浏览器路径。
先确认 Starter 还能构建
在教学 repository 根目录运行:
bash
npm run build:web命令应 exit 0。现在记录这个结果,后面新增代码导致 build 失败时,才有明确的对比点。
这条命令不验证业务。它只确认当前 uni-app、Vue 3 和 TypeScript 配置可以生成 H5。
再确认 Starter 里还没有本阶段答案:
bash
git ls-tree -r --name-only starter -- apps/web/src
git show starter:package.json | sed -n '/"scripts"/,/}/p'第一条命令应只看到基础入口、配置和 pages/index/index.vue,没有 domain、data、components 或详情页。第二条命令应包含 dev:web、build:web、test:web、typecheck:web 和 check。
这里是在确认起点,不是让 AI 重新生成脚手架。Starter 已经固定依赖版本和 workspace script;删除 lockfile 或重新执行项目初始化会制造与本阶段任务无关的 diff。
选型只写交付相关原因
把下面选择写进 docs/architecture.md:
| 选择 | 本阶段负责什么 | 暂时不展开 |
|---|---|---|
| uni-app | 用同一套页面代码生成 H5,并保留小程序入口 | 小程序端适配 |
| Vue 3 | 连接阶段状态、列表和详情界面 | Composition API 系统教学 |
| TypeScript | 定义 StageId、Recommendation 和函数输入输出 | 高级类型技巧 |
| Vitest | 检查阶段、筛选和详情查找规则 | E2E test 体系 |
Starter 已安装并锁定 Pinia 版本,阶段 2 开始把它接到 state 与 local persistence。FastAPI 在阶段 3 替换 Mock 数据。本阶段不提前接线。
写 docs/architecture.md
Starter 已有 apps/web/src/pages/index/index.vue。下面三个目录和详情页会在 1.4 创建。
| 目录 | 责任 | 1.4 对应文件 |
|---|---|---|
pages | 保存页面状态,调用 domain,组合 data 和 component,处理导航 | pages/index/index.vue、pages/detail/index.vue |
components | 通过 props 接收数据,通过 events 上报动作 | components/StagePicker.vue、components/RecommendationCard.vue |
domain | 类型与纯函数:阶段校验、推荐筛选、详情查找 | domain/stages.ts、domain/recommendations.ts |
data | 可替换的 Mock 内容 | data/recommendations.ts |
一个文件越界的典型信号:
RecommendationCard.vue直接调用uni.navigateTo。- 首页自己写
item.stageIds.includes(...)。 - component 重新声明阶段数组。
- data 层定义另一套阶段字符串。
看到这些改动,先退回对应责任,不要在调用方再加兼容分支。
检查依赖有没有反向
docs/architecture.md 中写完整依赖关系:
text
pages → components
pages → domain
pages → data
components → domain(type)
data → domain(type)首页从 data 取得推荐内容,调用 domain 的筛选函数,再把结果交给 component。详情页调用 domain 的查找函数。component 和 data 只从 domain 引用 type。
不允许 domain → pages、domain → components 或 components → pages。
docs/architecture.md 完整样例
markdown
# 阶段 1 前端架构
```text
pages ──────→ components
│ │
├──────────→ domain ←── data
└──────────→ data
components ──→ domain(类型)
data ────────→ domain(类型)
```
- `pages` 组合状态、筛选结果和导航,并引用 `components`、`domain` 与 `data`。
- `components` 只通过 props 和 events 通信,并从 `domain` 引用类型。
- `domain` 保存类型与纯函数。
- `data` 提供可替换的 Mock 内容,并从 `domain` 引用类型。
- 阶段 ID 的唯一真源是 `apps/web/src/domain/stages.ts`。
- 页面和组件不得自行声明阶段别名。两种常见越界
卡片自己导航:
diff
function openRecommendation() {
- emit("open", item.id)
+ uni.navigateTo({ url: `/pages/detail/index?id=${item.id}` })
}这会把 RecommendationCard 绑定到一个 URL。退回这段改动,保留 open(id) event,由 page 决定导航。
首页复制筛选规则:
diff
-const visibleRecommendations = computed(() =>
- recommendationsForStage(RECOMMENDATIONS, selectedStage.value),
-)
+const visibleRecommendations = computed(() =>
+ RECOMMENDATIONS.filter((item) => item.stageIds.includes(selectedStage.value)),
+)这段代码可以运行,但规则已经从 domain 泄漏到 page。继续调用 recommendationsForStage,不要为省一个 import 复制业务规则。
提交架构约定
bash
git status --short
git add docs/architecture.md
git diff --cached -- docs/architecture.mdCached diff 中只应有 docs/architecture.md。确认技术选择、四个目录和五条依赖都写完整,再提交:
bash
git commit -m "docs: define week one architecture"Build 或 Diff 不符合预期时
| 现象 | 先查 |
|---|---|
npm run build:web 找不到 script | 当前目录是否为教学 repository root;根 package.json 是否包含脚本 |
| Node / npm 版本不符 | 回看 0.2 的版本记录;应为 Node 24、npm 11 |
| build 报多个源码错误 | 只处理 terminal 中第一处具体文件和行号,然后重跑 |
Architecture commit 准备好后,进入 1.3 页面与组件拆解。