6 min read

包管理工具全解析:npm、yarn、pnpm 与 Monorepo 实战

Table of Contents

引言

现代前端开发离不开包管理工具,而随着项目规模增大,Monorepo 架构越来越受欢迎。本文将全面介绍 npm、yarn、pnpm 的特性与对比,并深入讲解 Monorepo 的实战方案,帮助你构建高效的前端项目架构。


npm:官方标配

npm(Node Package Manager)是 Node.js 官方自带的包管理工具,生态最为庞大。

核心特性

  • 最大生态:npm Registry 拥有最多的包数量
  • npx 命令:无需安装即可运行可执行包
  • nvm 版本管理:轻松切换 Node 版本
  • 丰富的脚本支持

常用命令

# 初始化项目
npm init
npm init -y # 快速初始化

# 安装依赖
npm install lodash              # 安装生产依赖
npm install -D typescript        # 安装开发依赖
npm install                     # 安装 package.json 中的所有依赖

# 运行脚本
npm run dev
npm run build

# 查看包信息
npm view lodash versions         # 查看所有版本
npm outdated                     # 查看过期依赖
npm audit                        # 安全审计

npm scripts 进阶

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint src --ext .ts,.tsx",
    "lint:fix": "eslint src --fix",
    "test": "vitest",
    "test:coverage": "vitest --coverage",
    "prepare": "husky install",
    "postinstall": "node ./scripts/postinstall.js"
  }
}

适用场景

  • 个人项目和小团队项目
  • 需要使用最大生态库的场景
  • 快速原型开发

小技巧

  1. 使用 npx 运行一次性命令npx create-vite my-app
  2. npm config 加速npm config set registry 配置国内镜像
  3. package-lock.json:锁定依赖版本,确保团队一致

yarn:Facebook 出品

yarn 由 Facebook 开发,早期以速度快、离线安装著称。

核心特性

  • 离线缓存:首次安装后,后续无需网络
  • 并行安装:同时下载多个包,速度快
  • 版本锁定:yarn.lock 确保确定性安装
  • Workspaces:原生支持 Monorepo

常用命令

# 初始化
yarn init
yarn init -y

# 安装依赖
yarn add lodash              # 生产依赖
yarn add -D typescript       # 开发依赖
yarn install                 # 安装所有依赖
yarn upgrade                 # 升级依赖

# 运行脚本
yarn dev
yarn build

# 其他常用
yarn outdated                # 查看过期包
yarn why lodash              # 查看依赖原因
yarn list                    # 查看依赖树

yarn workspaces 基础配置

{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "dev": "yarn workspace @myapp/web dev",
    "build": "yarn workspaces foreach -pt run build"
  }
}

适用场景

  • 需要确定性安装的项目
  • Monorepo 项目(原生支持)
  • 大型团队项目

小技巧

  1. 使用 yarn dlx 替代 npxyarn dlx create-vite my-app
  2. 交互式升级yarn upgrade-interactive
  3. 严格模式yarn install --frozen-lockfile 确保 lockfile 不被修改

pnpm:高效存储

pnpm(Performant npm)采用独特的软链接策略,极大节省磁盘空间。

核心特性

  • 磁盘节省:通过硬链接共享依赖,节省 60-70% 空间
  • 快速安装:比 npm 快 2-3 倍
  • 严格模式:避免 phantom dependencies
  • pnpm workspace:优秀的 Monorepo 支持

常用命令

# 安装
pnpm install
pnpm add lodash
pnpm add -D typescript

# 运行脚本
pnpm run dev

# 其他
pnpm update
pnpm remove lodash
pnpm list                      # 查看依赖树
pnpm why lodash                # 查看依赖来源

pnpm workspace 配置

# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
{
  "name": "my-monorepo",
  "private": true,
  "scripts": {
    "dev": "pnpm -r --parallel run dev",
    "build": "pnpm -r run build",
    "test": "pnpm -r run test"
  }
}

适用场景

  • 磁盘空间有限
  • Monorepo 项目
  • 需要更严格依赖管理的团队

小技巧

  1. 使用 filter 筛选包pnpm --filter @myapp/web build
  2. 只安装 dependenciespnpm install --prod
  3. 严格依赖检查.npmrc 中设置 shamefully-hoist=false

横向对比

特性npmyarnpnpm
安装速度中等最快
磁盘占用中等最低
Lock 文件package-lock.jsonyarn.lockpnpm-lock.yaml
Monorepo❌ 原生不支持✅ workspaces✅ workspace
依赖安全中等最好
生态大小最大中等
Node 版本所有全部全部

Monorepo:现代项目管理

什么是 Monorepo?

Monorepo(Monolithic Repository)是将多个项目放在同一个代码仓库中管理的架构方式。

优点:

  • 代码共享方便
  • 统一版本管理
  • 一次性构建所有项目
  • 简化依赖管理

缺点:

  • 仓库体积可能很大
  • CI/CD 配置复杂
  • 权限管理较难

方案对比

方案工具特点适用场景
yarn workspacesyarn简单易用,原生支持小型 Monorepo
pnpm workspacepnpm高效,磁盘节省中大型项目
TurborepoVercel智能缓存,极速构建大型复杂项目
NxNrwl企业级,功能全面超大型项目

Turborepo 实战

Turborepo 是 Vercel 推出的构建加速工具,配合任意包管理器使用。

项目结构

my-monorepo/
├── apps/
│   ├── web/          # React 主应用
│   ├── mobile/       # React Native
│   └── admin/       # 管理后台
├── packages/
│   ├── ui/          # 共享 UI 组件库
│   ├── utils/       # 工具函数
│   └── config/      # 共享配置
├── turbo.json
├── pnpm-workspace.yaml
└── package.json

turbo.json 配置

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "build/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

package.json 配置

{
  "name": "@myorg/web",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "test": "turbo run test"
  },
  "devDependencies": {
    "turbo": "latest"
  },
  "dependencies": {
    "@myorg/ui": "workspace:*",
    "@myorg/utils": "workspace:*"
  }
}

pnpm workspace 完整配置

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
# .npmrc
public-hoist-pattern[]=*
strict-peer-dependencies=false
auto-install-peers=true

共享配置最佳实践

ESLint 共享配置

// packages/eslint-config-custom/index.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
  ],
  plugins: ['@typescript-eslint', 'react', 'react-hooks'],
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
  rules: {
    'react/react-in-jsx-scope': 'off',
  },
};

TypeScript 共享配置

// packages/ts-config/base.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}
// packages/ts-config/react.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "moduleResolution": "bundler"
  }
}

实战技巧

1. 依赖版本管理

// 在根 package.json 中管理版本
{
  "dependencies": {
    "lodash": "^4.17.21",
    "react": "^18.2.0"
  },
  "pnpm": {
    "overrides": {
      "lodash": "^4.17.21"
    }
  }
}

2. CI/CD 优化

# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      - run: pnpm turbo run build
      - run: pnpm turbo run test

3. 本地开发技巧

# 使用 pnpm 的 workspace 协议
# 在 @myorg/ui/package.json 中
{
  "name": "@myorg/ui",
  "version": "1.0.0",
  "main": "./src/index.ts"
}

# 在 apps/web 中引用
{
  "dependencies": {
    "@myorg/ui": "workspace:*"
  }
}

总结

选择建议

  • 小团队/个人项目:npm + 单仓库足够
  • 中型团队:pnpm workspace,平衡效率和兼容性
  • 大型团队:Turborepo + pnpm,获得最佳构建性能
  • 企业级项目:Nx,功能最全

最佳实践

  1. 使用 lockfile 锁定版本
  2. 合理拆分 packages 和 apps
  3. 统一代码规范和配置
  4. 利用 Turborepo 加速构建
  5. 配置合适的 CI/CD 流程

掌握这些工具和架构,你的前端工程化能力会更上一层楼!🚀