name: monorepo-tooling description: 用于设置 monorepo 工具、优化构建或迁移工具,使用 Turborepo、Nx、Bazel、Lerna 实现高效的任务运行、缓存和代码生成。 allowed-tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
Monorepo 工具技能
概述
这个技能提供关于 monorepo 构建系统、任务运行器、包管理器和开发工具的全面指导,支持跨多个包的高效开发、构建和测试。
构建系统
Turborepo
高性能构建系统,具有智能缓存和任务编排功能。
管道配置
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [
".env",
"tsconfig.json"
],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [
"dist/**",
".next/**",
"build/**"
],
"cache": true
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"lint": {
"outputs": [],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
},
"deploy": {
"dependsOn": ["build", "test", "lint"],
"cache": false
}
},
"globalEnv": [
"NODE_ENV",
"CI"
]
}
远程缓存配置
{
"remoteCache": {
"enabled": true
}
}
与 Vercel:
# 链接到 Vercel 进行远程缓存
turbo login
turbo link
与自定义缓存:
{
"remoteCache": {
"enabled": true,
"signature": true,
"preflight": true
}
}
关键特性
- 增量构建:仅重建更改的包
- 远程缓存:在团队和 CI 中共享缓存
- 并行执行:在安全时并行运行任务
- 管道依赖关系:自动任务排序
- 修剪:提取 monorepo 的子集
- 过滤:在特定包上运行任务
用法:
# 在所有包中运行构建
turbo run build
# 使用过滤器运行
turbo run build --filter=@myorg/web
# 使用依赖关系运行
turbo run build --filter=@myorg/web...
# 强制重建(跳过缓存)
turbo run build --force
# 试运行
turbo run build --dry-run
# 为部署修剪
turbo prune --scope=@myorg/web
Nx
可扩展构建系统,具有强大的代码生成和分析功能。
工作空间配置
{
"extends": "nx/presets/npm.json",
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": [
"build",
"test",
"lint"
],
"parallel": 3,
"cacheDirectory": "node_modules/.cache/nx"
}
}
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"outputs": ["{projectRoot}/dist"],
"cache": true
},
"test": {
"inputs": [
"default",
"^production"
],
"cache": true
}
},
"namedInputs": {
"default": [
"{projectRoot}/**/*"
],
"production": [
"default",
"!{projectRoot}/**/*.spec.ts"
]
}
}
项目配置
{
"name": "web",
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/web",
"main": "apps/web/src/main.ts",
"tsConfig": "apps/web/tsconfig.app.json"
}
},
"serve": {
"executor": "@nx/webpack:dev-server",
"options": {
"buildTarget": "web:build"
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/web"],
"options": {
"jestConfig": "apps/web/jest.config.ts"
}
}
}
}
Nx 云配置
{
"nxCloudAccessToken": "YOUR_ACCESS_TOKEN",
"tasksRunnerOptions": {
"default": {
"runner": "nx-cloud",
"options": {
"cacheableOperations": ["build", "test", "lint"],
"accessToken": "YOUR_ACCESS_TOKEN"
}
}
}
}
Nx 关键特性
- 计算缓存:本地和远程缓存
- 受影响命令:仅对更改的项目运行任务
- 代码生成器:新项目的脚手架
- 依赖关系图:可视化项目关系
- 模块边界:强制执行架构规则
- 分布式执行:并行任务执行
用法:
# 在所有项目上运行目标
nx run-many --target=build --all
# 仅对受影响的项目运行
nx affected --target=test --base=main
# 查看依赖关系图
nx graph
# 生成新库
nx generate @nx/js:library my-lib
# 在特定项目上运行任务
nx build web
# 清除缓存
nx reset
Bazel
谷歌的可扩展构建系统,适用于非常大的 monorepo。
WORKSPACE 文件
workspace(name = "my_workspace")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# 加载 Node.js 规则
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "...",
urls = ["https://github.com/bazelbuild/rules_nodejs/..."],
)
load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories")
node_repositories(
node_version = "18.16.0",
package_manager = "pnpm",
)
BUILD 文件
# packages/ui/BUILD.bazel
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
load("@npm//@bazel/typescript:index.bzl", "ts_library")
ts_library(
name = "ui",
srcs = glob(["src/**/*.ts", "src/**/*.tsx"]),
deps = [
"@npm//react",
"@npm//react-dom",
"@npm//@types/react",
],
visibility = ["//visibility:public"],
)
pkg_npm(
name = "ui_pkg",
deps = [":ui"],
package_name = "@myorg/ui",
substitutions = {
"0.0.0-PLACEHOLDER": "{STABLE_VERSION}",
},
)
Bazel 关键特性
- 密封构建:可重复的构建
- 远程执行:在机器间分发构建
- 细粒度缓存:在文件级别缓存
- 语言无关:支持多种语言
- 可扩展性:处理海量代码库
- 构建正确性:可靠的依赖跟踪
用法:
# 构建目标
bazel build //packages/ui:ui
# 构建包中的所有目标
bazel build //packages/ui/...
# 测试目标
bazel test //packages/ui:ui_test
# 运行目标
bazel run //apps/web:serve
# 清理构建
bazel clean
# 查询依赖关系图
bazel query 'deps(//packages/ui:ui)'
Lerna
多包存储库管理和发布工具。
Lerna 配置
{
"version": "independent",
"npmClient": "pnpm",
"useWorkspaces": true,
"packages": [
"packages/*",
"apps/*"
],
"command": {
"publish": {
"conventionalCommits": true,
"message": "chore(release): publish",
"ignoreChanges": [
"**/__tests__/**",
"**/*.md"
]
},
"version": {
"allowBranch": ["main", "next"],
"message": "chore(release): version packages"
},
"bootstrap": {
"npmClientArgs": ["--no-package-lock"]
}
}
}
Lerna 关键特性
- 版本管理:固定或独立版本控制
- 发布:自动化包发布
- 引导:链接本地包
- 更改检测:识别修改的包
- 约定提交:自动化变更日志
- 工作空间集成:与 NPM/Yarn/PNPM 配合使用
用法:
# 引导包
lerna bootstrap
# 在所有包中运行命令
lerna run build
# 在更改的包中运行命令
lerna run test --since origin/main
# 发布包
lerna publish
# 从 git 标签发布
lerna publish from-git
# 版本包
lerna version
# 列出包
lerna list
Rush
可扩展的 monorepo 管理器,具有严格的依赖管理。
Rush 配置
{
"rushVersion": "5.108.0",
"pnpmVersion": "8.10.0",
"nodeSupportedVersionRange": ">=18.0.0",
"projectFolderMinDepth": 1,
"projectFolderMaxDepth": 2,
"projects": [
{
"packageName": "@myorg/web",
"projectFolder": "apps/web",
"reviewCategory": "production"
},
{
"packageName": "@myorg/ui",
"projectFolder": "packages/ui",
"reviewCategory": "production"
}
]
}
Rush 构建配置:
{
"operationSettings": [
{
"operationName": "build",
"outputFolderNames": ["dist", "lib"]
}
]
}
Rush 关键特性
- 防止幻影依赖:严格的依赖检查
- 子集安装:仅安装所需的包
- 更改跟踪:检测哪些项目更改
- 构建缓存:在团队中共享构建
- 策略执行:包管理规则
- 增量构建:仅重建更改的包
用法:
# 安装依赖
rush install
# 更新依赖
rush update
# 构建所有项目
rush build
# 构建更改的项目
rush rebuild
# 自定义命令
rush my-command
# 发布包
rush publish
任务运行
并行执行
跨包并行执行任务以提高速度。
Turborepo 并行执行:
# 自动检测并行性
turbo run build
# 限制并发数
turbo run build --concurrency=4
# 无限制
turbo run build --concurrency=100
Nx 并行执行:
# 默认并行(3)
nx run-many --target=build --all
# 自定义并行
nx run-many --target=build --all --parallel=5
# 最大并行
nx run-many --target=build --all --parallel=false
PNPM 并行执行:
# 在所有包中运行(并行)
pnpm -r run build
# 顺序执行
pnpm -r --workspace-concurrency=1 run build
# 自定义并发数
pnpm -r --workspace-concurrency=4 run build
任务依赖关系
定义哪些任务必须在其他任务之前完成。
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"]
}
}
}
依赖类型:
^build- 首先构建依赖(拓扑顺序)build- 当前包构建首先["^build", "lint"]- 多个依赖
选择性任务执行
仅在特定包或更改的包上运行任务。
Turborepo 过滤:
# 单个包
turbo run build --filter=@myorg/web
# 包及其依赖
turbo run build --filter=@myorg/web...
# 包及其依赖者
turbo run build --filter=...@myorg/web
# 多个包
turbo run build --filter=@myorg/web --filter=@myorg/api
# 更改的包
turbo run build --filter=[HEAD^1]
Nx 受影响:
# 受当前更改影响
nx affected --target=build
# 提交间受影响
nx affected --target=test --base=main --head=HEAD
# 受影响文件
nx affected:apps
nx affected:libs
PNPM 过滤:
# 单个包
pnpm --filter @myorg/web run build
# 包及其依赖
pnpm --filter @myorg/web... run build
# 包及其依赖者
pnpm --filter ...@myorg/web run build
# 更改的包
pnpm --filter "[main]" run test
跨包监视模式
在文件更改时自动重建。
{
"scripts": {
"dev": "turbo run dev --parallel",
"dev:web": "turbo run dev --filter=@myorg/web..."
}
}
使用 concurrently:
{
"scripts": {
"dev": "concurrently \"pnpm:dev:*\"",
"dev:web": "pnpm --filter @myorg/web run dev",
"dev:api": "pnpm --filter @myorg/api run dev"
}
}
使用 Turborepo 监视:
# 开发监视模式
turbo run dev --parallel --no-cache
缓存策略
本地计算缓存
本地缓存任务输出以加速重建。
Turborepo 本地缓存:
{
"pipeline": {
"build": {
"outputs": ["dist/**", ".next/**"],
"cache": true
}
}
}
缓存位置:node_modules/.cache/turbo
Nx 本地缓存:
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheableOperations": ["build", "test", "lint"],
"cacheDirectory": "node_modules/.cache/nx"
}
}
}
}
缓存位置:node_modules/.cache/nx
远程缓存
在团队成员和 CI 环境间共享缓存。
Turborepo 远程缓存与 Vercel:
# 登录到 Vercel
turbo login
# 链接存储库
turbo link
# 启用远程缓存(自动)
turbo run build
Nx 云:
# 连接到 Nx 云
nx connect-to-nx-cloud
{
"tasksRunnerOptions": {
"default": {
"runner": "nx-cloud",
"options": {
"cacheableOperations": ["build", "test", "lint"],
"accessToken": "YOUR_TOKEN"
}
}
}
}
自定义远程缓存:
// turbo-remote-cache.ts
import { createServer } from 'turbo-remote-cache';
createServer({
storage: {
type: 's3',
bucket: 'my-turbo-cache',
region: 'us-east-1'
},
port: 3000
});
缓存键和失效
控制什么使缓存失效。
Turborepo 缓存键:
{
"globalDependencies": [
".env",
"tsconfig.json",
".eslintrc.js"
],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"inputs": [
"src/**/*.ts",
"src/**/*.tsx",
"package.json"
],
"outputs": ["dist/**"]
}
}
}
Nx 缓存输入:
{
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"production": [
"default",
"!{projectRoot}/**/*.spec.ts",
"!{projectRoot}/**/*.test.ts"
],
"sharedGlobals": [
"{workspaceRoot}/tsconfig.base.json",
"{workspaceRoot}/.eslintrc.json"
]
},
"targetDefaults": {
"build": {
"inputs": ["production", "^production", "sharedGlobals"]
}
}
}
缓存失效:
# 清除所有缓存
turbo run build --force
# 清除 Nx 缓存
nx reset
# 单次运行跳过缓存
nx build web --skip-nx-cache
Docker 层缓存
在 monorepo 上下文中优化 Docker 构建。
# web 应用的 Dockerfile
FROM node:18-alpine AS base
# 仅当需要时安装依赖
FROM base AS deps
WORKDIR /app
# 复制根包文件
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY .npmrc ./
# 复制依赖的包文件
COPY packages/ui/package.json ./packages/ui/
COPY packages/utils/package.json ./packages/utils/
COPY apps/web/package.json ./apps/web/
# 安装依赖
RUN corepack enable pnpm && pnpm install --frozen-lockfile
# 构建阶段
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 使用 Turbo 构建
RUN pnpm turbo run build --filter=@myorg/web...
# 生产阶段
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/apps/web/.next ./apps/web/.next
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "apps/web/.next/server.js"]
代码生成
Nx 生成器
创建自定义代码生成器以确保一致性。
// tools/generators/library/index.ts
import {
Tree,
formatFiles,
generateFiles,
joinPathFragments
} from '@nx/devkit';
export interface LibraryGeneratorSchema {
name: string;
directory: string;
}
export default async function (tree: Tree, schema: LibraryGeneratorSchema) {
const projectRoot = joinPathFragments('packages', schema.directory);
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectRoot,
{
...schema,
tmpl: ''
}
);
await formatFiles(tree);
}
模板文件:
// tools/generators/library/files/src/index.ts__tmpl__
export function <%= name %>() {
return '<%= name %>';
}
// tools/generators/library/files/package.json__tmpl__
{
"name": "@myorg/<%= name %>",
"version": "0.0.1"
}
用法:
nx generate @myorg/tools:library --name=my-lib --directory=shared
Plop 模板
使用 Plop 进行更简单的代码生成。
// plopfile.js
export default function (plop) {
plop.setGenerator('package', {
description: '创建新包',
prompts: [
{
type: 'input',
name: 'name',
message: '包名称:'
},
{
type: 'list',
name: 'type',
message: '包类型:',
choices: ['library', 'app', 'service']
}
],
actions: [
{
type: 'addMany',
destination: 'packages/{{name}}',
templateFiles: 'templates/package/**/*',
base: 'templates/package'
}
]
});
}
模板:
// templates/package/package.json
{
"name": "@myorg/{{name}}",
"version": "0.0.1",
"type": "{{type}}"
}
用法:
pnpm plop package
包脚手架
自动化新包创建。
#!/bin/bash
# scripts/create-package.sh
NAME=$1
TYPE=$2
if [ -z "$NAME" ]; then
echo "用法:create-package.sh <name> <type>"
exit 1
fi
DIR="packages/$NAME"
# 创建目录结构
mkdir -p "$DIR/src"
mkdir -p "$DIR/__tests__"
# 创建 package.json
cat > "$DIR/package.json" << EOF
{
"name": "@myorg/$NAME",
"version": "0.0.1",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"test": "vitest"
}
}
EOF
# 创建初始文件
echo "export const $NAME = '$NAME';" > "$DIR/src/index.ts"
# 创建 README
cat > "$DIR/README.md" << EOF
# @myorg/$NAME
$NAME 包的描述。
EOF
echo "创建包:@myorg/$NAME"
一致样板
使用共享模板保持一致。
// scripts/new-component.ts
import fs from 'fs';
import path from 'path';
interface ComponentOptions {
name: string;
package: string;
}
function createComponent({ name, package: pkg }: ComponentOptions) {
const dir = path.join('packages', pkg, 'src', 'components', name);
fs.mkdirSync(dir, { recursive: true });
// 组件文件
fs.writeFileSync(
path.join(dir, `${name}.tsx`),
`import React from 'react';
export interface ${name}Props {
children?: React.ReactNode;
}
export function ${name}({ children }: ${name}Props) {
return <div>{children}</div>;
}
`
);
// 测试文件
fs.writeFileSync(
path.join(dir, `${name}.test.tsx`),
`import { render } from '@testing-library/react';
import { ${name} } from './${name}';
describe('${name}', () => {
it('渲染子元素', () => {
const { getByText } = render(<${name}>Hello</${name}>);
expect(getByText('Hello')).toBeInTheDocument();
});
});
`
);
// 索引文件
fs.writeFileSync(
path.join(dir, 'index.ts'),
`export { ${name} } from './${name}';
export type { ${name}Props } from './${name}';
`
);
}
受影响分析
基于 Git 的更改检测
基于 Git 历史识别哪些包更改。
Turborepo:
# 自上次提交后更改
turbo run build --filter=[HEAD^1]
# 最近 3 次提交中更改
turbo run build --filter=[HEAD^3]
# 分支间更改
turbo run build --filter=[origin/main...HEAD]
Nx:
# 自主分支后受影响
nx affected --target=build --base=main
# 特定提交间受影响
nx affected --target=test --base=abc123 --head=def456
# 显示受影响项目
nx affected:apps
nx affected:libs
依赖关系图分析
了解项目关系以实现智能构建。
使用 Nx 可视化:
# 完整依赖关系图
nx graph
# 受影响依赖关系图
nx affected:graph
# 特定项目图
nx graph --focus=web
使用 Nx 查询:
# 显示项目的依赖
nx show project web --web
# 列出所有项目
nx show projects
Turborepo 图:
# 生成任务图
turbo run build --graph
# 输出到文件
turbo run build --graph=graph.html
智能重建策略
仅基于更改重建必要内容。
Nx 受影响策略:
{
"affected": {
"defaultBase": "main"
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
}
}
Turborepo 受影响策略:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
}
}
}
CI 配置:
# .github/workflows/ci.yml
- name: 构建受影响
run: |
turbo run build --filter=[origin/main...HEAD]
增量构建
仅构建包内更改的文件。
TypeScript 增量构建:
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./dist/.tsbuildinfo"
}
}
Webpack 增量构建:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
}
};
Next.js 增量构建:
// next.config.js
module.exports = {
experimental: {
incrementalCacheHandlerPath: './cache-handler.js'
}
};
包管理
PNPM 工作空间
快速、磁盘高效的包管理器,具有严格的依赖模型。
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
- 'services/*'
# .npmrc
shared-workspace-lockfile=true
link-workspace-packages=true
prefer-workspace-packages=true
strict-peer-dependencies=false
auto-install-peers=true
save-workspace-protocol=rolling
关键优势:
- 内容可寻址存储(节省磁盘空间)
- 严格的 node_modules 结构(无幻影依赖)
- 最快的安装速度
- 内置 monorepo 支持
- 工作空间协议支持
命令:
# 安装所有工作空间依赖
pnpm install
# 向包添加依赖
pnpm --filter @myorg/web add react
# 添加工作空间依赖
pnpm --filter @myorg/web add @myorg/ui
# 更新依赖
pnpm --filter @myorg/web update react
# 在所有包中运行脚本
pnpm -r run build
# 在更改的包中运行
pnpm --filter "[main]" run test
Yarn 工作空间
Yarn 的工作空间实现,具有插件生态系统。
Yarn Classic:
{
"workspaces": [
"packages/*",
"apps/*"
]
}
Yarn Berry (v2+):
# .yarnrc.yml
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-3.6.4.cjs
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
关键优势:
- 插件架构(Berry)
- 零安装选项(Berry)
- 高级工作空间命令
- 广泛的生态系统支持
- 良好的 TypeScript 支持
命令:
# 安装依赖
yarn install
# 添加依赖
yarn workspace @myorg/web add react
# 在工作空间中运行脚本
yarn workspace @myorg/web run build
# 在所有工作空间中运行
yarn workspaces foreach run build
# 在更改的工作空间中运行(Berry)
yarn workspaces foreach --since=main run test
NPM 工作空间
原生 NPM 工作空间支持(v7+)。
{
"workspaces": [
"packages/*",
"apps/*"
]
}
关键优势:
- 原生 NPM 支持
- 无需额外工具
- 简单配置
- 广泛兼容性
- 文档齐全
命令:
# 安装依赖
npm install
# 向工作空间添加依赖
npm install react --workspace=@myorg/web
# 在工作空间中运行脚本
npm run build --workspace=@myorg/web
# 在所有工作空间中运行
npm run build --workspaces
# 在特定工作空间中运行
npm run test --workspaces --if-present
工具比较和迁移
性能比较(1000 包,冷安装):
- PNPM:约 30 秒
- Yarn Berry:约 45 秒
- NPM:约 90 秒
- Yarn Classic:约 120 秒
从 NPM 迁移到 PNPM:
# 删除 node_modules 和 package-lock.json
rm -rf node_modules package-lock.json
# 安装 PNPM
corepack enable pnpm
# 创建工作空间文件
cat > pnpm-workspace.yaml << EOF
packages:
- 'packages/*'
- 'apps/*'
EOF
# 使用 PNPM 安装
pnpm install
# 更新 package.json 脚本
# 将 "npm" 替换为 "pnpm"
从 Yarn 迁移到 PNPM:
# 删除 node_modules 和 yarn.lock
rm -rf node_modules yarn.lock
# 创建工作空间文件(从 package.json 转换)
cat > pnpm-workspace.yaml << EOF
packages:
- 'packages/*'
- 'apps/*'
EOF
# 使用 PNPM 安装
pnpm install --lockfile-only
pnpm install
最佳实践
1. 广泛使用缓存
利用本地和远程缓存以获取最大速度。
实施:
- 为所有确定性任务启用缓存
- 为 CI/CD 配置远程缓存
- 设置适当的缓存键
- 监控缓存命中率
- 记录缓存配置
2. 为 CI 配置远程缓存
在 CI 运行和开发者间共享构建工件。
实施:
- 设置远程缓存服务(Vercel、Nx 云、S3)
- 配置认证
- 在 CI 环境中启用
- 监控缓存使用
- 实施缓存预热
3. 利用受影响命令
仅在更改的包上运行任务。
实施:
- 在 CI 中使用受影响分析
- 正确配置基础分支
- 本地测试受影响策略
- 记录受影响命令
- 与缓存结合
4. 优化任务管道
设计高效的任务依赖图。
实施:
- 最小化任务依赖
- 启用并行执行
- 配置适当的并发数
- 使用管道可视化
- 分析管道性能
5. 使用代码生成确保一致性
自动化包和组件创建。
实施:
- 为常见模式创建生成器
- 记录生成器用法
- 维护生成器模板
- 在 CI 中使用生成器进行验证
- 定期更新模板
6. 版本控制 monorepo 中的锁定文件
提交锁定文件以确保可重复构建。
实施:
- 提交根锁定文件
- 不要提交包锁定文件
- 在 CI 中使用
--frozen-lockfile - 定期更新锁定文件
- 记录锁定文件策略
7. 记录工具使用
为所有工具维护清晰的文档。
实施:
- 包含工具概述的 README
- 命令参考
- 配置说明
- 故障排除指南
- 迁移指南
8. 监控构建性能
跟踪和优化构建时间。
实施:
- 在 CI 中测量构建时间
- 跟踪缓存命中率
- 分析慢速任务
- 设置性能预算
- 定期性能审查
9. 保持工具更新
保持 monorepo 工具版本最新。
实施:
- 定期更新计划
- 在 CI 中测试更新
- 查看变更日志
- 逐步推出
- 回滚计划
10. 验证工作空间完整性
确保工作空间正确配置。
实施:
- CI 中自动化验证
- 检查幻影依赖
- 验证包关系
- 验证版本
- 审计安全
常见陷阱
1. 不使用构建缓存
错失显著的性能提升。
解决方案:启用本地和远程缓存,正确配置输出。
2. 管道配置不当
任务依赖和排序效率低下。
解决方案:最小化依赖,启用并行,可视化管道。
3. 总是运行所有任务
未使用受影响分析。
解决方案:实施受影响命令,配置基础分支,本地测试。
4. 忽略受影响分析
在 CI 中浪费未更改包的时间。
解决方案:在 CI 中使用受影响,正确配置,监控节省。
5. 手动创建包
包结构不一致。
解决方案:创建生成器,记录用法,在审查中强制执行。
6. 工具使用不一致
不同团队成员使用不同命令。
解决方案:记录标准命令,使用 package.json 脚本,代码审查。
7. 缓存失效问题
由于不正确的缓存配置导致陈旧构建。
解决方案:正确配置输入/输出,测试缓存行为,监控。
8. 管道过于复杂
复杂的任务图难以维护。
解决方案:简化依赖,定期审查,文档。
9. 不必要地混合工具
使用多个重叠的工具。
解决方案:选择一个主要工具,证明添加合理性,定期审计。
10. 无性能监控
未跟踪构建性能随时间变化。
解决方案:实施指标,定期审查,设置预算,优化。
何时使用此技能
在以下情况应用 monorepo 工具化实践:
- 设置新 monorepo - 选择并配置工具
- 优化构建性能 - 提高速度和效率
- 迁移工具间 - 从一个工具迁移到另一个
- 配置 CI/CD - 设置自动化构建和测试
- 实施缓存 - 本地和远程缓存设置
- 创建生成器 - 自动化代码脚手架
- 故障排除构建 - 解决构建和依赖问题
- 扩展 monorepo - 处理增长和复杂性
- 团队入职 - 教导开发者 monorepo 工作流
- 评估工具 - 比较和选择 monorepo 工具
资源
- Turborepo 文档 - Turborepo 特性和配置的全面指南
- Nx 文档 - 完整的 Nx 工作空间指南和示例
- PNPM 工作空间 - PNPM 工作空间特性和配置
- Yarn 工作空间 - Yarn 工作空间实施指南
- Bazel 文档 - 开始使用 Bazel 构建系统
- Lerna 文档 - 使用 Lerna 管理 JavaScript monorepo
- Rush 文档 - Node.js 的可扩展 monorepo 解决方案
- Monorepo.tools - monorepo 工具和特性的全面比较