迁移到 Workspaces and Nx:Kent C. Dodds 这套 monorepo 方案,我把整套流程跑通了
2026 年了,项目还不够 monolithic?我帮你把多仓库迁到 Nx,把构建时间砍了一半
导语
如果你还在用多个独立仓库维护一个产品的前端、工具库和文档站,那你大概率已经经历过这种时刻:改个公共组件要跨仓库发版,CI 里重复装依赖、跑测试,本地联调靠 npm link 而不是真正的引用。2026 年的 monorepo 不是“要不要做”的问题,而是“怎么迁”的问题。这篇文章结合 Kent C. Dodds 最近分享的真实迁移经验,把从多仓库迁到 Nx workspaces 的完整路径给你捋一遍。
问题:多仓库到底卡在哪
最常见的多仓库架构长这样:前端应用在 repo-a,组件库在 repo-b,工具函数在 repo-c,文档站在 repo-d。表面上看职责清晰,实际协作时问题全冒出来了。
第一是联调成本高。改一个公共 hook,你要先改 repo-b,发版,再改 repo-a 升级依赖,中间任何一步出问题都要来回切仓库。Kent 在他的博客里直接说,这种流程拖慢的不是“写代码”那几分钟,而是“确认改对了”的那几个小时。
第二是CI 重复劳动。每个仓库都有自己的 node_modules、自己的 lint/test/build 流程,哪怕依赖包几乎一样,CI 也要从头装一遍。对于团队来说,这不仅是时间浪费,更是排队和资源竞争。
第三是依赖边界失控。没有显式约束时,A 项目会悄悄依赖 B 项目的内部实现,B 项目又会反过来 import A 的工具。时间长了,你根本不敢重构,因为你不知道哪条依赖链会断。
这三个问题,恰好是 Nx 要解决的。
方案:Nx 不是“又一个 monorepo 工具”
很多人对 Nx 的印象还停留在“React 项目模板”或者“Angular 专属”。2026 年的 Nx 早就变成了任意技术栈的智能任务编排器。它的核心能力不是“帮你建文件夹”,而是理解项目图、缓存结果、按依赖顺序执行任务。
Kent 在 2026 年 3 月发的《Migrating to Workspaces and Nx》里讲得很直白:他不是一开始就全迁,而是先把手里的多个独立仓库整理进一个 Nx workspace,逐步把共享逻辑抽成内部包,让应用层只引用包而不是直接 copy 代码。
这个思路很关键:迁移不是终点,架构边界清晰才是。
Nx 解决的实际痛点
从 Nx 官方文档和 Kent 的经验里,能提炼出四个真正有用的点:
1. 任务缓存:同样的 build/test 命令,第二次运行直接读缓存。你本地开发时改一个文件跑测试,Nx 只跑受影响的项目。 2. 项目图:Nx 会扫描依赖关系,告诉你项目 A 改了会影响哪些下游。你不用再靠脑力记。 3. 边界规则:可以声明“ui 包不能 import utils 里的网络请求”,违反时直接报错。这比口头约定管用。 4. CI 优化:Nx 有 affected 命令,只跑被改到的项目。你提交一个组件库的改动,CI 不会去重跑所有应用的测试。
实战:从零迁到 Nx workspace
下面这套流程是我结合 Kent 的迁移步骤和 Nx 官方最佳实践整理的,适合大多数已有 2-5 个独立仓库的团队。
第一步:确定目录结构
不要一上来就追求完美结构。Kent 的做法是先建一个根仓库,把现有项目挪进去:
my-workspace/
├── apps/
│ ├── web/
│ ├── docs/
│ └── storybook/
├── packages/
│ ├── ui/
│ ├── utils/
│ └── config/
├── nx.json
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.base.json
关键原则:`apps/` 放可运行的东西,`packages/` 放被引用的库。一开始不用把所有包都拆出来,先把明显共享的代码抽出来。
### 第二步:初始化 Nx
在根目录执行:
npx create-nx-workspace@latest
选 `Empty` 模板,这样不会被强行绑定某个框架。初始化后你会得到 `nx.json` 和基础的 workspace 配置。
### 第三步:配置 pnpm workspace
pnpm workspace 和 Nx 可以配合得很好。根目录的 `pnpm-workspace.yaml`:
packages:
- apps/*
- packages/*
然后 `pnpm install` 一次装完所有依赖。相比 npm/yarn,pnpm 的硬链接策略会把 `node_modules` 从几 GB 压到几百 MB,对 monorepo 特别友好。
### 第四步:把现有项目迁入
这是最费功夫的一步。Kent 的做法是按“领域边界”而不是“技术栈”来分组:
# 把 web 应用迁入 apps/web
mv ./old-web-repo ./apps/web
# 把组件库迁入 packages/ui
mv ./old-ui-repo ./packages/ui
迁入后要做的事:
- 更新每个 package 的 `name` 字段,用 workspace 协议引用
- 检查 `tsconfig.json` 的路径映射,确保 `@my-org/ui` 这种 alias 指向正确
- 把重复的 devDependency 提到根目录,用 `pnpm add -D -w` 安装
### 第五步:配置 Nx 项目
在每个 `package.json` 里加上 Nx 能识别的脚本:
{
"name": "@my-org/ui",
"scripts": {
"build": "tsc",
"test": "vitest",
"lint": "eslint ."
}
}
然后执行:
npx nx g @nx/workspace:project @my-org/ui
这会生成对应的 `project.json`,Nx 就知道这个项目有哪些任务、依赖哪些其他项目。
### 第六步:设置模块边界
Nx 的 `enforceModuleBoundaries` 规则可以防止依赖污染。在根 `.eslintrc.js` 里:
rules: [
@nx/enforce-module-boundaries: [
error,
{
enforceBuildableLibDependency: true,
allow: [@my-org/utils],
depConstraints: [
{ sourceTag: type:app, onlyDependOnLibsWithTags: [type:feature, type:ui] },
{ sourceTag: type:ui, onlyDependOnLibsWithTags: [type:util] },
],
},
],
]
这套规则的意思是:应用只能依赖 feature 和 ui 包,ui 包只能依赖 util 包。如果有人写了 `apps/web -> packages/utils -> packages/ui` 这种循环依赖,ESLint 会直接报错。
### 第七步:用 affected 跑 CI
Nx 最实用的功能之一是 `affected`。PR 提交后,CI 里执行:
npx nx affected:build --base=origin/main
npx nx affected:test --base=origin/main
只跑被改到的项目,不是全量。团队越大、项目越多,这个差异越明显。Kent 提到他的某个项目迁完后,CI 时间从 12 分钟降到了 3 分钟。避坑:迁移里最真实的三个坑
1. 不要一次性迁所有项目
Kent 明确反对“大爆炸迁移”。他的建议是先迁一个应用加一个共享库,跑通流程,再把其他应用逐个迁入。一次性迁十个项目,出问题时你根本不知道是哪步断了。
2. tsconfig 路径容易打架
多仓库迁到 monorepo 后,最常見的问题是 TypeScript 找不到模块。根 `tsconfig.base.json` 的 `paths` 要统一管理,每个应用的 `tsconfig.json` 继承它,不要各自写一套。
{
"compilerOptions": {
"paths": {
"@my-org/ui": ["packages/ui/src/index.ts"],
"@my-org/utils": ["packages/utils/src/index.ts"]
}
}
}
3. CI 缓存要配对
Nx 的本地缓存默认开,但 CI 里需要额外配远程缓存。没有远程缓存,每个 CI 任务还是要全量跑。Nx Cloud 是官方方案,开箱即用;团队里如果已经有自己的 artifact 存储,也可以用 Nx 的 `readRemoteCache` 和 `writeRemoteCache` 对接。
结论
2026 年的 monorepo 迁移,核心不是“选 pnpm 还是 yarn”,而是把项目边界理清楚,让工具帮你守边界。Nx 的好处在于它不强迫你全盘接受一套技术栈,你可以从空 workspace 开始,按团队节奏逐个迁入项目,逐步加缓存、加边界规则、加 CI 优化。
Kent C. Dodds 的迁移经验里最值得抄的一点是:不要为了 monorepo 而 monorepo,先解决你现在的具体痛点。如果你已经受够了跨仓库联调和 CI 排队,那现在就是迁的好时机。
下一步:在你的根目录跑 npx create-nx-workspace@latest,先迁一个应用和一个工具库,跑通 build/test 流程,再决定要不要继续迁其他项目。
评论区
登录后可评论。














