基于pnpm搭建多Node.js项目Monorepo的最佳实践与示例咨询
pnpm Monorepo 最佳实践(多应用+共享组件场景)
一、完整的 pnpm-workspace.yaml 配置
packages: # 纳入工作区的所有子项目 - 'apps/**' - 'packages/**' # 排除无需参与工作区管理的目录(避免构建产物、依赖目录干扰) - '!apps/**/node_modules' - '!apps/**/dist' - '!packages/**/node_modules' - '!packages/**/dist' # 工作区全局脚本(根目录统一执行) scripts: # 按依赖顺序构建:先构建共享组件库,再构建应用(避免并行导致依赖未就绪) build: 'pnpm run -r --filter "./packages/**" build && pnpm run -r --filter "./apps/**" build' # 并行启动所有项目的开发服务 dev: 'pnpm run -r --parallel dev' # 统一安装所有子项目依赖 install: 'pnpm install' # 检查并更新所有子项目的依赖版本 update: 'pnpm update -r' # 批量运行所有子项目的测试用例 test: 'pnpm run -r test' # 补充子项目缺失的Peer依赖声明 packageExtensions: '@your-org/ui-components': peerDependencies: react: '^18.0.0' react-dom: '^18.0.0' # 锁定依赖版本策略 lockfile: strict: true # 强制所有子项目使用一致的依赖版本
二、标准项目结构
monorepo-root/ ├── apps/ │ ├── web-app-1/ # 业务应用1 │ │ ├── package.json │ │ ├── Dockerfile │ │ ├── src/ │ │ └── dist/ # 构建产物(被工作区排除) │ └── web-app-2/ # 业务应用2 │ ├── package.json │ ├── Dockerfile │ ├── src/ │ └── dist/ ├── packages/ │ ├── ui-components/ # 共享UI组件库 │ │ ├── package.json │ │ ├── src/ │ │ └── dist/ │ └── utils/ # 可选:共享工具函数库 │ ├── package.json │ ├── src/ │ └── dist/ ├── pnpm-workspace.yaml ├── package.json # 根目录仅声明全局脚本与依赖版本约束 └── .gitignore
三、核心命令与实用技巧
- 顺序构建:执行根目录的
pnpm run build,先完成共享组件库编译,再构建业务应用,避免依赖缺失问题 - 并行开发:
pnpm run dev同时启动所有项目的开发服务,提升效率 - 单个项目操作:单独构建某应用:
pnpm --filter web-app-1 build;给组件库新增依赖:pnpm --filter ui-components add lodash - 依赖版本统一:在根目录
package.json中添加pnpm.overrides,强制所有子项目使用相同版本的公共依赖:{ "pnpm": { "overrides": { "react": "^18.2.0", "react-dom": "^18.2.0" } } }
四、子项目 package.json 配置要点
共享组件库(packages/ui-components)
{ "name": "@your-org/ui-components", "version": "1.0.0", "type": "module", "scripts": { "build": "vite build", // 按实际构建工具调整 "dev": "vite" }, "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" }, "main": "./dist/index.js", "module": "./dist/index.es.js", "types": "./dist/index.d.ts" }
业务应用(apps/web-app-1)
{ "name": "@your-org/web-app-1", "version": "1.0.0", "scripts": { "build": "vite build", "dev": "vite", "docker:build": "docker build -t web-app-1 ." }, "dependencies": { "@your-org/ui-components": "workspace:*", // 引用工作区内的组件库版本 "react": "^18.2.0", "react-dom": "^18.2.0" } }
五、Docker构建注意事项
针对monorepo场景,应用的Dockerfile需处理依赖与构建的关联,示例如下:
# 构建阶段 FROM node:18-alpine as builder WORKDIR /app # 复制pnpm配置与子项目依赖声明 COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY apps/web-app-1/package.json ./apps/web-app-1/ COPY packages/ui-components/package.json ./packages/ui-components/ # 安装pnpm RUN npm install -g pnpm # 安装所有依赖 RUN pnpm install --frozen-lockfile # 复制源码 COPY apps/web-app-1/src ./apps/web-app-1/src COPY packages/ui-components/src ./packages/ui-components/src # 执行构建 RUN pnpm run build # 生产镜像阶段 FROM nginx:alpine COPY --from=builder /app/apps/web-app-1/dist /usr/share/nginx/html COPY apps/web-app-1/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
内容的提问来源于stack exchange,提问作者Paul Verest on LinkedIn




