知识广场
按学科筛选:计算机科学 / 前端开发 / 工程化
«计算机科学 / 前端开发 / 工程化» 分类下共 1 篇帖子
## 起因 公司项目演化: - 1 个 web app → 加 mobile app(React Native) - 加 admin dashboard - 加 marketing site - 加 design system 组件库 - 加 shared TS types / API client 多 repo 痛点: - shared code 要 publish package - 跨 repo PR 难 coordinate - 升级 dep 各 repo 跟不齐 monorepo 解决但 build / test / cache 是新挑战。 **Turborepo** / **Nx** 解决"哪些 task 要跑 + 缓存什么"。 ## Turborepo Vercel 收购,2022+。 ``` monorepo/ ├── apps/ │ ├── web/ # Next.js │ ├── mobile/ # React Native │ └── admin/ ├── packages/ │ ├── ui/ # shared component │ ├── api-client/ │ └── tsconfig/ ├── package.json ├── turbo.json └── pnpm-workspace.yaml ``` `pnpm-workspace.yaml`: ```yaml packages: - 'apps/*' - 'packages/*' ``` `turbo.json`: ```json { "tasks": { "build": { "dependsOn": ["^build"], "outputs": [".next/**", "dist/**"] }, "test": { "dependsOn": ["build"] }, "lint": {}, "dev": { "cache": false, "persistent": true } } } ``` `^build` = 先跑依赖 package 的 build。 ## 用法 ```bash pnpm turbo build # build 所有 package(按 dep order) pnpm turbo test # 同上 pnpm turbo dev # 跑所有 dev server pnpm turbo build --filter=web # 只 build web app + 它依赖 ``` 第一次跑 build:跑全部 task。 第二次跑 build(无改动):**全部 cache hit,零执行**。 ## cache 怎么工作 Turbo 把每 task 的: - input file content hash - env var - dependency hash → cache key。命中 cache:直接复用 output(dist/)。 ``` ✔ ui:build cached (3.2s saved) ✔ api-client:build cached ○ web:build finished (cached) 4.5s ``` 改 1 个 package 的 source → 它跟它的 dependent 重 build;其它仍 cache hit。 ## 远程 cache Turbo cache 默认本地。多人开发 / CI 同一计算重复跑。 remote cache: ```bash npx turbo login npx turbo link ``` 把 cache 推 Vercel cloud / 自托管 → 同事 pull 后 cache 命中(同 commit 他不必再跑 build)。 我们 6 人团队 CI 时间从 12 分钟 → 2 分钟(90% cache hit)。 ## Nx Nrwl 出,2017+。比 turbo 更老更全。 ```bash npx create-nx-workspace@latest myorg ``` Nx 提供: - task scheduling + cache(跟 Turbo 类似) - generator(一键 scaffold app / lib) - 依赖图可视化 - 多语言(不只 JS,也支持 .NET / Go via plugin) - consistent project structure 强制 `nx.json`: ```json { "targetDefaults": { "build": { "cache": true, "inputs": ["default", "^production"] } }, "tasksRunnerOptions": { "default": { "runner": "nx/tasks-runners/default", "options": { "cacheableOperations": ["build", "test", "lint"] } } } } ``` ```bash nx build web nx affected -t test # 只跑受影响 package nx graph # 浏览器看 dependency 图 ``` `nx affected` 是杀器:基于 git diff 判定哪 package 改了,只跑相关。 ## Turbo vs Nx | | Turbo | Nx | |---|---|---| | 设计 | 轻量 task runner | 全套 monorepo solution | | 学习曲线 | 低 | 中高 | | generator | 无 | 强(scaffold app / lib) | | 依赖图 UI | 无 | 强 | | 多语言 | JS only | JS + 插件 | | 远程 cache | Vercel / 自托管 | Nx Cloud / 自托管 | | 强约束 | 少 | 多("Nx way") | **Turbo**:你已有 monorepo + 想加 cache → 5 分钟接入。 **Nx**:从 0 开始 + 想 batteries-included → Nx。 我个人 Turbo 多(不喜欢被框架强约束)。 ## 内部 package 引用 ```json // apps/web/package.json { "dependencies": { "@myorg/ui": "workspace:*", "@myorg/api-client": "workspace:*" } } ``` `workspace:*` 让 pnpm 链接到本地 package(不发 npm)。 ```tsx // apps/web/app/page.tsx import { Button } from '@myorg/ui'; import { fetchPosts } from '@myorg/api-client'; ``` 跟普通 npm package 一样 import。 ## shared tsconfig ```json // packages/tsconfig/base.json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "strict": true, "moduleResolution": "Bundler" } } ``` ```json // apps/web/tsconfig.json { "extends": "@myorg/tsconfig/base", "compilerOptions": { ... } } ``` config 一处改 全 repo 受用。 ## CI 优化 ```yaml # GitHub Actions - uses: pnpm/action-setup@v2 - run: pnpm install - run: pnpm turbo build test lint --concurrency=4 ``` Turbo 跟 GH cache action 配合 → cache 远程拉。 PR 时间从 15 分钟 → 3 分钟(动几个 package 重 build,其余 cache)。 ## 真实 case 我们 monorepo 演化: ``` 最初: 单 Next.js 项目 ↓ 加 admin dashboard (Next.js) → 共享 component 想抽 ↓ 建 monorepo + pnpm workspace + Turbo ↓ packages/ui (shared component) packages/api-types (类型 + zod schema) packages/tsconfig apps/web, apps/admin, apps/marketing ↓ 后来加 packages/api-client (axios + types) ↓ team grow 到 8 人 → 加 remote cache ``` 效果: - 改 ui component → web + admin 一起测 - 共享 type 跨 frontend / backend(Node 后端也 import api-types) - CI 快 5x - 新成员 onboarding:clone 1 repo 全 setup ## 不要过早 monorepo 单 app + < 3 人 → 不必。 N app + shared code → monorepo + Turbo。 ## 与 yarn workspaces / npm workspaces pnpm 是 monorepo 最强: - 严格 dependency 隔离 - 链接速度快 - workspaces 原生 npm workspaces / yarn workspaces 也行但 pnpm 主流。 ## 踩过的坑 1. **依赖循环**:`@myorg/ui` 依赖 `@myorg/utils` → utils 依赖 ui → build 报错。`nx graph` / `turbo` 看依赖图理清。 2. **build output 没指定**:turbo 不知道 cache 啥 → cache miss 一直。 `"outputs": [".next/**", "dist/**"]` 必填。 3. **env 变量影响 cache**:env 改了应该 invalidate cache。 `"env": ["NODE_ENV"]` 配置。 4. **monorepo 大 后 IDE 慢**:100+ package 后 TS server 慢。 project references + 限 indexing scope。 5. **publish 仍麻烦**:内部 package 不 publish OK。但要 publish shared design system → changesets 工具帮 version + changelog。