普通视图

发现新文章,点击刷新页面。
昨天 — 2025年7月1日首页

Turborepo 完全指南:从零到生产

2025年7月1日 15:09

简介:为什么 Monorepos 如此重要(以及为什么大多数人不知道它们) 残酷的现实是,99% 的软件工程师从未听说过 Monorepos,更不用说正确实现它了。这并非出于个人喜好,而是基于一些团队在实际工作中的经验,他们面对的是一个简单 React 应用程序的构建时间超过一小时的情况。

我亲眼目睹了糟糕的 monorepo 实现所带来的后果:20 多名工程师组成的团队每次推送到 dev 分支都要等待一个多小时才能构建完成。罪魁祸首是什么?一个包含压缩版 Ant Design 组件的 React 项目,在 CI/CD 流水线中解压,编译耗时过长。解决方案很简单——使用 Ant Design 的内置主题或创建私有 npm 包——但由于组织阻力,我们不得不将整个文件夹复制粘贴到源代码中,只为将构建时间从 60 多分钟缩短到 5 分钟。

本指南将教您如何使用 Turborepo 以正确的方式构建 monorepos,让您从完全的初学者变成熟练的实践者。

Turborepo 是什么? Turborepo 是一个专为 Monorepos 设计的高性能 JavaScript 和 TypeScript 代码库构建系统。它解决了 Monorepos 面临的根本性扩展问题:随着代码库的增长,构建时间会变得异常缓慢。

Monorepo 扩展问题 Monorepos 有很多优势——共享代码、一致的工具、跨项目的原子提交——但它们难以高效扩展。每个工作区都有各自的优势:

测试套件 Linting 规则 构建过程 依赖项 单个 Monorepo 可能需要执行数千个任务。如果没有合适的工具,这会导致速度急剧下降,影响团队构建和交付软件。

Turborepo 通过智能缓存和任务编排解决了这个问题。它的远程缓存存储了所有任务的结果,这意味着您的 CI 无需重复执行相同的工作。

先决条件和平台说明 重要提示: Turborepo 在类 Unix 系统上效果最佳。如果您使用的是 Windows 11,请考虑使用 WSL 2.0,因为您可能会遇到特定于平台的问题。文件系统命令可能因平台而异。

分步实施指南 让我们使用 Next.js 前端、Express.js API 和共享包构建一个完整的 monorepo。

最终项目结构 my-monorepo/ ├── apps/ │ ├── web/ # Next.js frontend │ └── api/ # Express backend ├── packages/ │ ├── ui/ # Shared UI components │ ├── types/ # Shared TypeScript types │ └── docs/ # Documentation (optional) ├── turbo.json ├── tsconfig.base.json ├── package.json └── .gitignore 步骤 1:Clean Slate 设置 首先,确保您有一个干净的环境:

Remove any existing Turbo installation

npm uninstall -g turbo rm -rf node_modules rm package-lock.json 步骤 2:初始化 Monorepo mkdir my-turborepo && cd my-turborepo npm init -y 编辑你的根package.json:

{ "name": "my-monorepo", "private": true, "scripts": { "dev": "turbo run dev", "build": "turbo run build", "lint": "turbo run lint", "test": "turbo run test" },
"workspaces": [ "apps/", "packages/" ], "devDependencies": { "turbo": "2.5.4" }, "packageManager": "npm@10.9.2" } 安装 Turborepo:

npm install 步骤3:配置Turborepo turbo.json在根目录中创建:

{ "$schema": "", "tasks": { "build": { "dependsOn": ["^build"], "outputs": ["dist/", ".next/", "!.next/cache/**"] }, "dev": { "cache": false, "persistent": true }, "lint": { "dependsOn": ["^lint"] }, "test": { "dependsOn": ["^test"] }, "check-types": { "dependsOn": ["^check-types"] } } } 步骤4:创建项目结构 mkdir -p apps/web apps/api packages/ui packages/types packages/docs 步骤 5:设置 Next.js 前端 导航到 Web 应用程序目录并创建 Next.js 应用程序:

cd apps/web npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" 更新apps/web/package.json以包含共享依赖项www.mytiesarongs.com

{ "name": "web", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "check-types": "tsc --noEmit" }, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", "next": "15.3.4", "@repo/ui": "", "types": "" }, "devDependencies": { "typescript": "^5", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "tailwindcss": "^4", "eslint": "^9", "eslint-config-next": "15.3.4" } } 步骤6:设置Express.js API 导航到 API 目录:

cd ../../apps/api npm init -y 安装依赖项:

npm install express cors npm install --save-dev typescript ts-node @types/express @types/node @types/cors nodemon 创造tsconfig.json:

{ "extends": "../../tsconfig.base.json", "compilerOptions": { "target": "ES2020", "module": "CommonJS", "moduleResolution": "Node", "outDir": "dist", "rootDir": "src", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } 创造src/index.ts:

import express from 'express'; import cors from 'cors'; import type { User } from 'types';

const app = express(); const PORT = process.env.PORT || 3001;

app.use(cors()); app.use(express.json());

app.get('/', (req, res) => { res.json({ message: 'API is running successfully!' }); });

app.get('/users', (req, res) => { const users: User[] = [ { id: '1', name: 'John Doe' }, { id: '2', name: 'Jane Smith' } ]; res.json(users); });

app.listen(PORT, () => { console.log(🚀 API server running on ); }); 更新apps/api/package.json:

{ "name": "api", "version": "1.0.0", "scripts": { "dev": "nodemon src/index.ts", "build": "tsc", "start": "node dist/index.js", "check-types": "tsc --noEmit" }, "dependencies": { "express": "^4.18.2", "cors": "^2.8.5", "types": "*" }, "devDependencies": { "typescript": "^5.0.0", "ts-node": "^10.9.0", "@types/express": "^4.17.17", "@types/node": "^20.0.0", "@types/cors": "^2.8.13", "nodemon": "^3.0.0" } } 步骤 7:创建共享包 共享类型包 创造packages/types/index.ts:

export interface User { id: string; name: string; email?: string; }

export interface ApiResponse { data: T; message?: string; success: boolean; }

export interface ButtonProps { children: React.ReactNode; onClick?: () => void; variant?: 'primary' | 'secondary' | 'danger'; disabled?: boolean; } 创造packages/types/package.json:

{ "name": "types", "version": "1.0.0", "main": "index.ts", "types": "index.ts" } 共享 UI 组件包 创造packages/ui/src/Button.tsx:

import React from 'react'; import type { ButtonProps } from 'types';

export const Button: React.FC = ({ children, onClick, variant = 'primary', disabled = false }) => { const baseClasses = 'px-4 py-2 rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';

const variantClasses = { primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500', secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500', danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500' };

const disabledClasses = 'opacity-50 cursor-not-allowed';

const className = ${baseClasses} ${variantClasses[variant]} ${disabled ? disabledClasses : ''};

return ( {children} ); }; 创造packages/ui/src/index.ts:

export { Button } from './Button'; 创造packages/ui/package.json:

{ "name": "@repo/ui", "version": "0.0.0", "private": true, "main": "./src/index.ts", "types": "./src/index.ts", "exports": { ".": "./src/index.ts" }, "scripts": { "lint": "eslint . --max-warnings 0", "check-types": "tsc --noEmit" }, "dependencies": { "react": "^19.0.0", "types": "*" }, "devDependencies": { "@types/node": "^20.0.0", "@types/react": "^19.0.0", "typescript": "^5.0.0", "eslint": "^9.0.0" } } 步骤 8:配置 TypeScript tsconfig.base.json在根目录中创建:

{ "compilerOptions": { "target": "ES2020", "lib": ["dom", "dom.iterable", "es6"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "baseUrl": ".", "paths": { "@repo/ui": ["./packages/ui/src"], "@repo/ui/": ["./packages/ui/src/"], "types": ["./packages/types"], "types/": ["./packages/types/"] } }, "include": ["/*.ts", "/*.tsx"], "exclude": ["node_modules", "dist", ".next"] } 步骤9:更新Git配置 创建/更新.gitignore:

Dependencies

node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log*

Build outputs

dist/ .next/ .vercel/

Turborepo

.turbo/

Environment variables

.env .env.local .env.development.local .env.test.local .env.production.local

IDE

.vscode/ .idea/

OS

.DS_Store Thumbs.db 步骤 10:测试你的 Monorepo 安装所有依赖项:

npm install 构建一切:

npm run build 您应该看到如下输出:

Tasks: 4 successful, 4 total Cached: 0 cached, 4 total Time: 15.2s 运行开发服务器:

npm run dev 这将启动您的 Next.js 应用程序(通常在端口 3000 上)和 Express API(在端口 3001 上)。

步骤 11:验证一切正常 通过再次运行构建来测试缓存:

npm run build 您应该看到:

Tasks: 4 successful, 4 total Cached: 4 cached, 4 total Time: 185ms >>> FULL TURBO 恭喜!您已在几毫秒内成功构建并优化了 Monorepo。

Turborepo 关键命令 turbo build- 按照依赖关系图构建所有包 turbo build --filter=web- 仅构建 Web 应用程序及其依赖项 turbo build --dry- 展示无需执行即可构建的内容 turbo dev- 启动所有开发服务器 turbo lint- 对所有包进行 linting turbo test- 对所有包运行测试 高级配置 远程缓存 对于团队,设置远程缓存以共享构建工件:

npx turbo login npx turbo link 包过滤 针对特定包:

Build only frontend

turbo build --filter=web

Build frontend and its dependencies

turbo build --filter=web...

Build everything except docs

turbo build --filter=!docs 常见问题故障排除 构建失败:检查你的turbo.json任务依赖关系 导入错误:验证您的 TypeScript 路径映射tsconfig.base.json 工作区解析:确保package.json工作区配置正确 Windows 上的平台问题:使用 WSL 2.0 或确保您拥有最新的 Node.js 版本 结论 您现在拥有一个可用于生产的 Turborepo monorepo,它具有:

✅ 使用 TypeScript 的 Next.js 前端 ✅ 带有 TypeScript 的 Express.js API ✅ 共享 UI 组件 ✅ 共享类型定义 ✅ 智能缓存和任务编排 ✅ 初始设置后即可快速构建 这个基础架构可以扩展以支持数十个应用程序和软件包,同时保持快速的构建时间和开发人员的工作效率。关键在于理解 Turborepo 不仅仅是一个构建工具,它是一个完整的开发工作流程优化系统,可以改变您的团队交付软件的方式。访问了解更多相关代码资讯:www.ysdslt.com

❌
❌