Per user request: split the development process into per-topic docs under docs/dev-log/. Each entry follows the same structure: What was asked → Problems → How solved Files: - README.md index - 01-initial-scope-and-design.md - 02-ui-primitives-api-design.md - 03-monorepo-scaffold.md - 04-ui-primitive-impl.md - 05-drag-and-drop.md - 06-three-games.md - 07-bugfixes-round-1.md - lessons-learned.md all gotchas consolidated - decisions.md locked decisions with dates Total: 1071 lines across 10 files.
110 lines
2.8 KiB
Markdown
110 lines
2.8 KiB
Markdown
# 03 · 项目骨架搭建
|
||
|
||
## 做什么
|
||
|
||
创建 monorepo 骨架:
|
||
|
||
```
|
||
tts-like/
|
||
├── packages/
|
||
│ ├── protocol/ 共享类型
|
||
│ ├── engine/ boardgame.io 封装 + 游戏定义
|
||
│ ├── ui/ React 原语
|
||
│ └── server/ 中转服务器
|
||
├── apps/
|
||
│ ├── web/ Vite + React SPA
|
||
│ └── desktop/ Tauri 壳
|
||
├── docs/
|
||
└── 配置文件
|
||
```
|
||
|
||
## 遇到什么问题
|
||
|
||
### 问题 1:pnpm 不在 PATH
|
||
|
||
`which pnpm` 报 NOT FOUND,但 `corepack` 路径下能找到 shim。
|
||
|
||
**解决**:每次 Bash 命令前先 export PATH:
|
||
```bash
|
||
export PATH="/home/e2hang/.nvm/versions/node/v22.22.2/lib/node_modules/corepack/shims:$PATH"
|
||
```
|
||
|
||
### 问题 2:boardgame.io 0.50.2 发布的类型导出不全
|
||
|
||
`Game` / `Ctx` 等类型**只在主 entry**(`boardgame.io`,指向 `dist/types/src/types.d.ts`)里有。子包 `/react` `/server` `/multiplayer` 只导出运行时值。
|
||
|
||
**解决**:
|
||
```ts
|
||
// ✅ 正确
|
||
import type { Game, Ctx } from 'boardgame.io'; // 类型从主 entry
|
||
import { Client } from 'boardgame.io/react'; // 运行时从子包
|
||
```
|
||
|
||
### 问题 3:boardgame.io move 用 Immer 风格
|
||
|
||
最初写 War 游戏时用 return-style,typecheck 报错。
|
||
|
||
**解决**:直接 mutate G:
|
||
```ts
|
||
// ✅ 正确
|
||
moves: {
|
||
flip: ({ G, ctx }) => {
|
||
G.p0Deck = G.p0Deck.slice(0, -1);
|
||
// Immer 在内部处理
|
||
}
|
||
}
|
||
```
|
||
|
||
### 问题 4:pnpm workspace exports 模式
|
||
|
||
子包 `import '@tts-like/engine/games/war'` 解析不到。
|
||
|
||
**解决**:`engine/package.json` 加 `exports` 字段:
|
||
```json
|
||
"exports": {
|
||
".": "./src/index.ts",
|
||
"./games/*": "./src/games/*.ts"
|
||
}
|
||
```
|
||
|
||
注意:wildcard 后缀必须带 `.ts`,否则解析出来没扩展名。
|
||
|
||
### 问题 5:Vite 项目需要 `vite-env.d.ts`
|
||
|
||
否则 `import.meta.env` 报 `Property 'env' does not exist on type 'ImportMeta'`。
|
||
|
||
**解决**:在 `apps/web/src/vite-env.d.ts` 写:
|
||
```ts
|
||
/// <reference types="vite/client" />
|
||
```
|
||
|
||
## 怎么解决
|
||
|
||
分三步走:
|
||
|
||
1. **建目录 + 写包结构**(手写 + Write)
|
||
2. **`pnpm install`**(312 个依赖,19 秒)
|
||
3. **逐包 `tsc --noEmit`**(按 protocol → engine → ui → server → web 顺序)
|
||
|
||
### 关键决策:engine 用 `import type` 而不是 `export type`
|
||
|
||
```ts
|
||
// ❌ 不好用:在严格 TS 配置下 export type 不一定让名字进入本地 scope
|
||
export type { Game, Ctx } from 'boardgame.io';
|
||
|
||
// ✅ 工作中
|
||
import type { Game as BgGame } from 'boardgame.io';
|
||
export type Game<G = any> = BgGame<G>;
|
||
```
|
||
|
||
## 成果
|
||
|
||
- 6 个包全部通过 `tsc --noEmit`
|
||
- 初始 commit `c5e5515 chore: scaffold monorepo skeleton`
|
||
- Memory 写入 6 条踩坑记录
|
||
|
||
## 关联
|
||
|
||
- [04-ui-primitive-impl.md](./04-ui-primitive-impl.md) — 骨架就绪后开始填 UI
|
||
- [lessons-learned.md §1-6](./lessons-learned.md) — 本阶段踩坑详细记录
|