Skip to content
On this page

Monorepo 性能优化

性能挑战

Monorepo 随着项目数量和规模的增长,可能会面临性能挑战:

  1. 构建时间增加: 随着包数量增加,整体构建时间可能显著增加
  2. 依赖安装缓慢: 大型 monorepo 的依赖安装可能变得缓慢
  3. 测试执行时间长: 所有测试的执行时间可能变得不可接受
  4. 开发环境启动慢: IDE 和开发服务器启动时间可能增加

依赖管理优化

1. 依赖提升策略

将公共依赖提升到根目录,减少重复安装:

json
// package.json (root)
{
  "devDependencies": {
    "typescript": "^4.9.0",
    "eslint": "^8.0.0",
    "@types/node": "^18.0.0"
  }
}

2. 使用 pnpm 节省空间

pnpm 通过硬链接和符号链接节省磁盘空间和安装时间:

yaml
# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'

3. 依赖预构建

配置构建工具进行依赖预构建:

javascript
// vite.config.js
export default {
  optimizeDeps: {
    include: ['react', 'react-dom', 'lodash']
  }
}

构建性能优化

1. 增量构建

实现仅构建更改文件的增量构建:

bash
# 使用 Nx 的增量构建
nx build my-app --with-deps

# 使用 pnpm 的影响分析
pnpm --filter "...[origin/main]" build

2. 并行构建

利用多核 CPU 并行执行构建任务:

json
// package.json
{
  "scripts": {
    "build:parallel": "pnpm --parallel --recursive build"
  }
}

3. 缓存策略

使用构建缓存避免重复工作:

json
// nx.json
{
  "tasksRunnerOptions": {
    "default": {
      "runner": "@nx/workspace/tasks-runners/default",
      "options": {
        "cacheableOperations": ["build", "test", "lint"]
      }
    }
  }
}

测试性能优化

1. 影子测试

仅运行受影响的测试:

bash
# Nx 影子测试
nx affected:test

# Lerna 影响分析
lerna exec --since=main -- npm test

2. 测试并行化

并行运行独立的测试套件:

javascript
// jest.config.js
module.exports = {
  maxWorkers: '50%',
  testPathIgnorePatterns: ['/node_modules/', '/dist/']
};

3. 分层测试策略

  • 单元测试: 快速、独立的测试
  • 集成测试: 验证模块间交互
  • 端到端测试: 验证完整功能流

CI/CD 优化

1. 智能缓存

在 CI 环境中使用智能缓存:

yaml
# .github/workflows/ci.yml
- name: Setup pnpm
  uses: pnpm/action-setup@v2
  with:
    version: 7
    
- name: Get pnpm store directory
  id: pnpm-cache
  run: |
    echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"

- name: Setup pnpm cache
  uses: actions/cache@v3
  with:
    path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
    key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-pnpm-store-

2. 工作流分割

将大型工作流拆分为多个并行执行:

yaml
jobs:
  test-unit:
    runs-on: ubuntu-latest
    steps:
      - run: pnpm run test:unit
      
  test-integration:
    runs-on: ubuntu-latest
    steps:
      - run: pnpm run test:integration

3. 增量部署

仅部署更改的部分:

bash
# 仅部署受影响的应用
nx affected:deploy

开发体验优化

1. 快速启动

优化开发服务器启动时间:

javascript
// vite.config.js
export default {
  server: {
    warmup: {
      clientFiles: ['./src/**']
    }
  }
}

2. 智能监听

仅监听相关文件的变化:

json
{
  "scripts": {
    "dev": "nodemon --watch 'packages/*/src/**/*' --exec 'tsc -b'"
  }
}

3. 按需加载

实现开发时的按需加载:

javascript
// 动态导入
const loadModule = async (modulePath) => {
  return await import(modulePath);
};

监控和度量

1. 性能指标

监控关键性能指标:

  • 构建时间
  • 测试执行时间
  • 依赖安装时间
  • 开发服务器启动时间

2. 性能预算

设置性能预算以防止性能退化:

json
{
  "performance": {
    "maxAssetSize": 250000,
    "maxEntrypointSize": 250000,
    "hints": "warning"
  }
}

3. 性能分析工具

使用工具分析性能瓶颈:

bash
# 分析构建性能
npx webpack-bundle-analyzer dist/stats.json

# 分析依赖大小
npx cost-of-modules

工具特定优化

Lerna 优化

json
// lerna.json
{
  "command": {
    "publish": {
      "ignoreChanges": ["*.md", "**/__tests__/**"],
      "registry": "https://registry.npmjs.org/"
    }
  }
}

Nx 优化

json
// nx.json
{
  "namedInputs": {
    "default": ["{projectRoot}/**/*"],
    "production": [
      "default",
      "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.[jt]s",
      "!{projectRoot}/.eslintrc.json"
    ]
  },
  "targetDefaults": {
    "build": {
      "inputs": ["production", "^production"],
      "cache": true
    }
  }
}

最佳实践总结

  1. 持续监控: 定期监控性能指标,及时发现性能退化
  2. 渐进优化: 逐步实施优化策略,避免一次性大规模更改
  3. 工具选择: 选择适合项目规模的工具和配置
  4. 自动化: 实现性能优化的自动化,确保持续改进
  5. 团队协作: 确保整个团队了解并遵循性能优化实践

通过实施这些性能优化策略,可以显著改善 Monorepo 的开发体验和构建效率,确保项目在增长过程中仍能保持高性能。