Quiet
  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我

bajiu

  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我
Quiet主题
  • 前端工程化

pnpm搭建Monorpeo项目

bajiu
前端

2025-08-18 15:31:03

解决的问题

Monorepo 管理方式解决了如下问题:

  • 跨项目的改动困难:更改核心库需要在多个仓库中手动更新。
  • 版本不一致:不同项目可能因为未及时更新依赖而导致的版本冲突。
  • 流程复杂化:多个代码仓可能意味着重复配置多个 CI/CD 流程。
  • 团队协作问题:不同的项目分属不同的仓库,增加了团队之间沟通的工作量。

初始化仓库

# Node 18+、pnpm 9+ 建议
mkdir my-monorepo && cd my-monorepo
git init
pnpm init -y

在根 package.json 补充(指定工作区包管理器、方便工具识别):

{
  "name": "my-monorepo",
  "private": true,
  "packageManager": "pnpm@9.0.0",
  "scripts": {
    "dev": "pnpm -r --parallel dev",
    "build": "pnpm -r build",
    "lint": "pnpm -r lint",
    "test": "pnpm -r test"
  }
}

新建 .npmrc(一些常用工作区优化):

; 在工作区根目录只维护一个 pnpm-lock.yaml(所有子包共享同一把锁),
; 方便 CI 和保证各包依赖版本一致。设为 false 时每个子包都会各自生成锁文件。
shared-workspace-lockfile = true

; 当依赖能在本地工作区里找到且版本满足时,用符号链接直接链接本地包,
; 而不是从 registry 下载,提升本地开发联调效率。
link-workspace-packages = true

; 当既能用本地工作区的包也能用远端版本时,优先使用本地工作区包。
;(若想模拟“真实用户安装远端包”的场景,可临时关掉)
prefer-workspace-packages = true

; 自动安装缺失的 peerDependencies,减少“缺少 peer 依赖”的报错。
; 注意:自动装的 peer 通常不会写入 package.json,想显式固定版本建议手动添加。
auto-install-peers = true

定义工作区

根目录新建 pnpm-workspace.yaml:

packages:
  - "apps/*"
  - "packages/*"

跨项目依赖

my-monorepo/
  pnpm-workspace.yaml
  packages/
    utils/
      package.json
      src/index.ts
  apps/
    web/
      package.json
      src/main.ts

pnpm-workspace.yaml

packages:
  - "apps/*"
  - "packages/*"

packages/utils/package.json

{
  "name": "@acme/utils",
  "version": "0.0.0",
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsup src/index.ts --dts"
  },
  "devDependencies": {
    "tsup": "^8.0.0",
    "typescript": "^5.4.0"
  }
}

packages/utils/src/index.ts

export const sum = (a: number, b: number) => a + b;

apps/web/package.json

{
  "name": "web",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "node src/main.ts",
    "build": "echo web build"
  },
  "dependencies": {
    "@acme/utils": "workspace:*"
  }
}

apps/web/src/main.ts

import { sum } from "@acme/utils";
console.log("sum:", sum(1, 2));

大概就是这样

加入 Turbo 做任务编排与缓存

官网: https://www.npmjs.com/package/turbo

文档:https://turborepo.com/docs

pnpm -w add -D turbo

turbo.json:

{
  "pipeline": {
    "build": {
      "outputs": ["dist/**", "build/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "test": {}
  }
}

根 package.json 脚本可改为:

{
  "scripts": {
    "dev": "turbo run dev --parallel",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test"
  }
}

版本管理与发包

如果 packages/* 要发布到 npm:

pnpm dlx changeset init
pnpm changeset            # 交互选择要发版的包与版本类型
pnpm changeset version    # 写回 package.json
pnpm -r publish --access public

每个可发布包建议加上:

"publishConfig": { "access": "public" }

常见坑

  • peerDependencies 未满足:在根或 app 安装 React 等 peer 依赖即可(auto-install-peers=true 能减少报错)。
  • 包互相引用循环或类型没刷:给库包加 tsup/tsc -b 构建,app 依赖构建产物;或使用 paths + tsup --watch。
  • 路径解析问题:确保 moduleResolution: "Bundler"(或 NodeNext)与工具一致;x 下通常没问题。
  • 过滤器不好使:确认包名与 --filter 值一致(可用 pnpm list -r 查看工作区包)。
下一篇

AnnData数据结构

©2025 By bajiu.