学习文档 Monorepo + pnpm + 项目结构

一、Monorepo 概念与价值

  1. 什么是 Monorepo
  • Monorepo(Monolithic Repository):
    用 一个代码仓库 管理多个项目、多个包(apps、服务、组件库、工具库等)。
    代码按"目录/包"划分,但物理上都在一个仓库里。
  • 与 Polyrepo 对比:
    • Polyrepo:每个项目一个仓库(web 一个、server 一个、组件库一个...)。
    • Monorepo:一个仓库,内部按 apps/、packages/ 等目录划分。
  1. 为什么要用 Monorepo(核心是"依赖复用 + 中心化管理")

优点:

  • 依赖和代码复用更方便

    • 公共组件库、工具函数、类型定义、hooks 等可以做成单独包,比如 packages/ui、packages/utils、packages/types。
    • 一个仓库里,子包之间 直接本地依赖,不必频繁发布到 npm 再安装。
  • 统一管理 & 中心化思想

    • 统一的 lint、test、build、release 流程。
    • 统一的工具链和规范(如 ESLint、Prettier、TypeScript 配置)。
    • 一处升级依赖,可以影响所有 apps / packages,容易保持版本一致。
  • 跨项目联调效率高

    • 比如 web 应用依赖本地组件库 @my-org/ui:
      • 修改组件库代码 → 立刻在 web 应用跑起来验证。
      • 不需要发布版本、切换仓库、重新安装依赖。
  • 更好地支撑大型前端体系

    • 多个业务线、多种终端(H5、PC、管理后台、小程序...)共用基础能力时,Monorepo 可以作为"前端平台底座"。

缺点 / 需要注意:

  • 仓库体积会变大,历史记录更多,CI/CD 流程更复杂(一般要做到"只构建改动影响到的包")。
  • 权限粒度不如多个仓库细(一个仓库里默认都能看到全部代码)。
  • 需要配套工具(如 pnpm workspace、TurboRepo、Nx 等)协助管理任务和依赖。

二、pnpm:适合 Monorepo 的包管理工具

  1. pnpm 是什么
  • pnpm 是一种 快速、省空间 的包管理工具,可替代 npm、yarn、cnpm。
  • 核心特性:内容寻址存储 + 软链接机制。
  1. 关键特性
  • 磁盘占用小

    • pnpm 使用 全局的 store(仓库) 保存下载过的依赖。
    • 不同项目、不同 workspace 共享同一份依赖内容。
    • 每个项目的 node_modules 里不是完全复制依赖,而是大量 软链接 指向全局 store。
  • 安装速度快

    • 有效利用缓存,重复项目安装时几乎不重新下载。
    • 并行安装能力强。
  • 严格的依赖隔离

    • 与 npm、yarn 相比,pnpm 对依赖的"提升"更严格,有利于暴露错误的依赖声明(比如包 A 其实没在 dependencies 写某个依赖,却依赖了它)。
  • 天然支持 Monorepo(Workspace)

    • 通过 pnpm-workspace.yaml 管理多个子项目/子包。
    • 顶层可以执行 pnpm install、pnpm -r run build 等命令,给所有包统一操作。
  1. 基本使用(针对 Monorepo)
  • 初始化项目(已有项目可跳过)
    pnpm init
  • 配置 workspace
    在项目根目录创建 pnpm-workspace.yaml:

packages:

  • 'apps/*'
  • 'packages/*'
  • 统一安装依赖
    pnpm install
  • 在某个包/应用中安装依赖

在 apps/web 中安装 React

pnpm add react react-dom --filter apps/web

在 packages/ui 中安装 antd

pnpm add antd --filter packages/ui

  • 对所有包执行命令(递归)

对所有包执行 lint

pnpm -r run lint

对所有包执行 build

pnpm -r run build

这里的 -r 就是 recursive(递归)的意思。


三、典型 Monorepo 项目结构(前端为主)

假设你现在这个仓库是 React + SSR + H5,这里给出一个 通用的、相对理想的 项目结构,你可以对照自己的情况调整。

  1. 根目录结构
  • package.json

    • 存放根依赖(很通用的 devDependencies 可以放这里,比如 typescript、eslint、prettier、turbo 等)。
    • 配置统一的脚本,例如:
      • "lint": "pnpm -r run lint"
      • "build": "pnpm -r run build"
      • "test": "pnpm -r run test"
  • pnpm-workspace.yaml

    • 声明 workspace 包含哪些目录:

packages:

  • 'apps/*'

  • 'packages/*'

  • 统一配置文件(建议都放在根目录)

    • tsconfig.base.json:基础 TypeScript 配置,供各子包继承。
    • .eslintrc.cjs:统一 ESLint 配置。
    • .prettierrc:代码风格统一。
    • .editorconfig:编辑器统一规则。
    • turbo.json 或 nx.json(如果使用 TurboRepo 或 Nx 做任务编排和缓存)。
  • CI / 配置文件

    • .github/workflows/*(GitHub Actions)。
    • Dockerfile / docker-compose.yml(如果有容器部署)。
    • scripts/:放一些 Node 脚本,比如自动发布、版本管理等。
  1. apps/:最终可运行应用

一般放"真正对外运行的应用",例如前端站点、后端服务。

  • apps/web:前端 H5/SSR 应用(React)

    • src/
      • pages/:页面级组件(路由对应)。
      • components/:业务级或通用组件。
      • hooks/:应用级 hooks(可视情况提炼到 packages/hooks)。
      • store/:应用级状态管理(也可以放在 packages/store,供多应用共享)。
      • routes/:路由配置(React Router / 自研路由)。
      • entry.client.tsx / entry.server.tsx:SSR 入口文件。
    • package.json:
      • 声明依赖(如 react、react-dom、react-router-dom 等)。
      • 定义脚本:
        • "dev": "vite dev" / "start": "webpack-dev-server"
        • "build": "vite build"
        • "lint": "eslint src --ext .ts,.tsx"
  • apps/admin(可选):后台管理系统

  • apps/server(可选):Node 服务(如 SSR 服务、BFF、API 网关)

  1. packages/:可复用的库和模块
    这里是 Monorepo 的"精华部分",专门放 可以被多个 apps 共用 的东西。
  • packages/ui:组件库

    • 放通用 UI 组件(按钮、表单、列表、布局组件等)。
    • 对上层应用暴露统一的组件接口。
    • 可选择使用 storybook 来做组件文档。
  • packages/utils:工具库

    • 日期、格式化、URL 解析、请求封装等与 UI 无关的逻辑。
    • 提供纯函数或通用 helper。
  • packages/types:类型定义库(如果用 TS)

    • 接口响应数据类型、领域模型类型、枚举等。
    • 被 UI、服务端、工具库共同引用,确保类型统一。
  • packages/store:状态管理库(如果你希望多个应用共享 store 能力)

    • 封装 Redux / Zustand / Recoil / Jotai / 自研 store 等。
    • 暴露 hooks,比如 useUserStore、useTodoStore 等,给各个 apps/* 使用。
  • packages/config(可选)

    • 打包配置、Lint 规则、TS 配置等复用封装。
    • 比如 @my-org/eslint-config,在各个包中只需 "extends": "@my-org/eslint-config"。
  • packages/api(可选)

    • 请求封装(fetch/axios)、接口定义、API 客户端等。

每个 packages/* 子包一般都有自己的 package.json,像这样:

{

"name": "@my-org/ui",

"version": "0.0.1",

"main": "dist/index.js",

"module": "dist/index.esm.js",

"types": "dist/index.d.ts",

"scripts": {

"build": "tsup src/index.tsx --dts",

"lint": "eslint src --ext .ts,.tsx"

},

"dependencies": {

"react": "^18.0.0"

}

}

  1. 典型 Monorepo 总体结构示例

    .
    ├── package.json
    ├── pnpm-lock.yaml
    ├── pnpm-workspace.yaml
    ├── tsconfig.base.json
    ├── .eslintrc.cjs
    ├── .prettierrc
    ├── apps
    │ ├── web
    │ │ ├── package.json
    │ │ └── src
    │ │ ├── pages
    │ │ ├── components
    │ │ ├── store
    │ │ ├── hooks
    │ │ └── entry.client.tsx
    │ └── server
    │ ├── package.json
    │ └── src
    │ └── index.ts
    └── packages
    ├── ui
    │ ├── package.json
    │ └── src
    ├── utils
    │ ├── package.json
    │ └── src
    ├── types
    │ ├── package.json
    │ └── src
    └── store
    ├── package.json
    └── src

四、Monorepo + pnpm 的常见工作流

  1. 新增一个包 / 应用
  • 新增应用:apps/admin

    1. 创建目录 apps/admin。
    2. 在其中 pnpm init 或手动写 package.json。
    3. 在 pnpm-workspace.yaml 的 packages 中已经包含 apps/* 的话,不需要额外修改。
    4. 使用 pnpm add ... --filter apps/admin 安装依赖。
  • 新增包:packages/hooks

    1. 创建目录 packages/hooks。
    2. 初始化 package.json,指定 "name": "@my-org/hooks"。
    3. 编写业务无关的 React hooks。
    4. 在 apps/web 中通过 pnpm add @my-org/hooks --filter apps/web 使用本地包。
  1. 跨包开发
  • 在 packages/ui 新增组件。
  • 在 apps/web 中直接 import { Button } from '@my-org/ui'。
  • 一起运行:

同时在多个 app 中启动开发

pnpm --filter apps/web dev

pnpm --filter apps/admin dev

或者使用 Turbo/Nx 做统一的 task 管理。

  1. 统一执行测试/构建/检查
  • 在根 package.json 中定义脚本:

{

"scripts": {

"lint": "pnpm -r run lint",

"test": "pnpm -r run test",

"build": "pnpm -r run build"

}

}

  • 使用时:
    pnpm lint
    pnpm test
    pnpm build
    pnpm 会在所有包含对应脚本的 apps/* 和 packages/* 里依次执行。

五、如何从"简单项目"演进到 Monorepo

结合现在的仓库,可以按下面顺序演进:

  1. 先引入 pnpm
  • 切换包管理器,生成 pnpm-lock.yaml。
  1. 抽离公共代码到 packages
  • 把复用性强的部分(组件、工具、类型)从 src 中提炼到 packages/*。
  1. 拆出多应用到 apps(如果未来有多端)
  • 如 SSR 服务、管理后台、BFF 服务等。
  1. 统一配置 & 任务
  • 把 ESLint / TS / Prettier 配置提到根目录,apps 和 packages 尽量共享。
  • 根目录用 pnpm 脚本统一 lint/test/build。
相关推荐
说实话起个名字真难啊2 小时前
深入学习openclaw之记忆基础
人工智能·学习·openclaw
handler012 小时前
算法:查并集
开发语言·数据结构·c++·笔记·学习·算法·c
lajidecrd2 小时前
bat学习
学习
蓝染k9z2 小时前
非技术人员 AI 使用学习全历程研究报告
人工智能·学习
盐水冰2 小时前
【烘焙坊项目】后端搭建(13)- 数据统计--图形报表
java·后端·学习·spring
朗迹 - 张伟2 小时前
UE5 UMG学习笔记
笔记·学习·ue5
jinanwuhuaguo2 小时前
AI应用开发与自动化工具全景解析:Coze、Dify、FastGPT、n8n、MCP、Manus、Claude Code、OpenClaw
人工智能·学习·重构·新人首发·openclaw
EnglishJun2 小时前
ARM嵌入式学习(六) --- ARM基础介绍和相关专业术语讲解
arm开发·学习