🎯 目标:搭建一个 Monorepo
我们将创建这样一个结构:
packages/ui: 一个共享组件库(提供一个按钮)。apps/web: 一个 React 网站(使用上面的按钮)。turbo: 负责一键启动所有项目。
🛠️ 第一步:初始化地基 (Root)
找个空文件夹,打开终端。
初始化项目:
bashmkdir my-monorepo && cd my-monorepo npm init -y修改
package.json
{
"name": "my-monorepo",
"version": "1.0.0",
// 👇 建议:加上 private: true,防止意外把整个根目录发布到 npm 仓库
"private": true,
"scripts": {
"dev": "turbo dev"
},
"devDependencies": {
"turbo": "^2.x.x"
},
//Turbo (尤其是 v2.0 版本后) 变得非常严格。它为了防止“在我的电脑上能跑,在你的电脑上跑不起来”这种问题,强制要求你在
//package.json 里显式声明你用的是什么包管理器(npm, yarn, pnpm 还是 bun),以及具体的版本号。
// 👇 查到当前pnpm的版本号填进去 pnpm -v
"packageManager": "pnpm@9.1.0"
}安装 pnpm (如果你还没有安装):
bashnpm install -g pnpm配置工作区 (核心): 在根目录新建文件
pnpm-workspace.yaml。这行代码告诉 pnpm:“apps和packages里的文件夹都是我的人,把它们连起来。” YAMLyamlpackages: - 'apps/*' - 'packages/*'
📦 第二步:创建共享 UI 库 (packages/ui)
我们要造一个“轮子”。
创建目录:
bashmkdir -p packages/ui cd packages/ui npm init -y修改
packages/ui/package.json: 把name改个有组织的名字,比如@repo/ui。这是我们以后引用的名字。json{ "name": "@repo/ui", "version": "1.0.0", "main": "./index.tsx", "dependencies": { "react": "^18.0.0" }, "devDependencies": { "@types/react": "^19.2.9" } }(注:为了演示方便,我们直接指向 tsx 源码,让消费端的 Vite 去编译它。生产环境通常会先编译成 JS。)
创建组件代码: 新建
packages/ui/index.tsx: TypeScripttsximport React from 'react'; export const Button = () => { return ( <button style={{ backgroundColor: 'blue', color: 'white', padding: '10px 20px', borderRadius: '5px', border: 'none', cursor: 'pointer' }}> 我是共享组件按钮 🚀 </button> ); };
🚀 第三步:创建应用 (apps/web)
现在我们要创建一个网站来使用这个按钮。回到根目录。
回到根目录并创建 Vite 项目:
bash# 使用 pnpm 创建 vite 项目,放入 apps/web 目录 pnpm create vite apps/web --template react-ts关键步骤:建立依赖连接! 我们要在
apps/web里安装刚才写的@repo/ui。 在根目录下运行:bash# --workspace 参数告诉 pnpm:别去 npm 仓库找,去本地文件夹找! pnpm add @repo/ui --filter web --workspace你去看看
apps/web/package.json,会发现多了一行:"@repo/ui": "workspace:*"。这就是 Monorepo 的魔法链接。
我们把它拆成三部分看:
1. **`pnpm add @repo/ui`**:
* **动作**:我要安装 `@repo/ui` 这个包。
2. **`--filter web`**:
* **地点(Target)**:但我不想安装在根目录,我要安装到 **名字叫 `web` 的那个包**(即 `apps/web/package.json`)里。
3. **`--workspace`**:
* **版本(Protocol)**:**关键点!** 这告诉 pnpm:“不要去 npm 仓库找版本号,直接用我本地 Monorepo 里的版本,并标记为 `workspace:*`”。
4. **在应用中使用组件**: 打开 **`apps/web/src/App.tsx`**,修改代码:
**TypeScript**- 直接引入我们的包!
import { Button } from '@repo/ui'
function App() {
return (
<div style={{ padding: 50 }}>
<h1>Web 应用</h1>
<p>下面这个按钮来自共享库:</p>
<Button />
</div>
)
}
export default App⚡️ 第四步:引入 Turborepo (提速)
现在我们有了两个项目。如果没有 Turbo,你需要分别去两个目录跑命令。有了 Turbo,我们在根目录指挥一切。
安装 Turbo (在根目录):
bashpnpm add turbo -D -w(
-w表示安装在根目录 workspace root)配置 Turbo: 在根目录新建
turbo.json。这是任务调度指挥中心。Turbo v2 刚刚发布不久,它做了一个重大的破坏性更新 (Breaking Change):为了让配置语义更清晰,它把原来的 "pipeline" 字段重命名为了 "tasks"。
json{ "$schema": "https://turbo.build/schema.json", //它把原来的 "pipeline" 字段重命名为了 "tasks"。 "tasks": { "dev": { "cache": false, "persistent": true }, "build": { "outputs": ["dist/**"] } } }配置根目录启动命令: 修改根目录的
package.json,添加scripts:bash"scripts": { "dev": "turbo dev" }
✅ 验证时刻
现在,见证奇迹的时刻到了。
在根目录运行:
bashpnpm dev观察终端: 你会看到 Turbo 启动了!它会同时启动
apps/web的dev命令(如果 ui 库有 dev 命令也会启动)。打开浏览器。 你应该能看到一个蓝色的按钮 “我是共享组件按钮 🚀”。
🧠 深度复盘
你刚才做的这几个步骤,其实模拟了大型前端团队的协作流:
- Workspace Protocol (
workspace:*):- 你在
ui文件夹里改了按钮颜色为red,保存。 - 你会发现
web页面瞬间变红了。 - 不需要
npm publish,不需要npm install。这就是 Monorepo 开发效率提升的核心。
- 你在
- Turborepo:
- 刚才只有一个 app,你可能感觉不明显。但如果你有 10 个 app,
turbo dev会并行启动它们。 - 如果你运行
turbo build,第二次运行时会发现耗时接近 0ms,因为它读取了缓存(Cache)。
- 刚才只有一个 app,你可能感觉不明显。但如果你有 10 个 app,
.gitignore
# 1. 依赖包 (自动覆盖根目录和所有子目录)
node_modules/
.pnpm-store/
# 2. 构建产物
dist/
build/
coverage/
# 3. Turborepo 缓存 (非常重要,不要提交缓存)
.turbo/
# 4. 环境变量 (包含敏感信息,绝对不能提交)
.env
.env.*.local
# 5. 系统文件 & 编辑器配置
.DS_Store
.vscode/
.idea/
*.log
# 6. (强烈不推荐忽略pnpm-lock.yaml❌)