Monorepo工具技能Skill monorepo-tooling

这个技能提供关于 monorepo 构建系统、任务运行器、包管理器和开发工具的全面指导,支持跨多个包的高效开发、构建和测试。关键词包括 monorepo、构建系统、缓存、任务运行、代码生成、Turborepo、Nx、Bazel、Lerna、CI/CD。

DevOps 0 次安装 2 次浏览 更新于 3/25/2026

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 工具

资源