Skip to content

1.2 技术选型与项目结构 ​

AI CODING · STAGE 1 · ARCHITECTURE

把技术选择、目录责任和依赖方向写进 architecture 文件。后续 diff 越界时,按这份约定退回。

时间 40–60 分钟改动 docs/architecture.md目录 4
检查 Starter build →
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.md

Cached 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 页面与组件拆解。

晨悦 AI 实践手册