项目改 pnpm 并使用 Monorepo 发布至 npm 上

相关概念

pnpm:
pnpm (Performant npm) 是一个快速、节省磁盘空间的 Node.js 包管理器,与 npmYarn 兼容但采用了不同的依赖管理方法。

  • 全局存储:所有依赖只保存一份在 ~/.pnpm-store
  • 硬链接技术:项目中 node_modules 只是指向全局存储的链接
  • 实际效果:相比 npm/Yarn 可节省 60-70% 的磁盘空间
  • 典型项目安装速度比 npm 快 2倍 以上
  • 解决幽灵依赖问题:无法引用未在 package.json 的依赖

Monorepo:
Monorepo(单一代码仓库)是一种软件开发策略,指的是将多个相关项目或包的代码存储在同一个版本控制仓库中,而不是为每个项目或组件使用单独的仓库。

将 npm 项目迁移到 pnpm

  1. 安装 pnpm
    npm i pnpm -g
    
    查看是否安装成功及版本号
    pnpm -v
    
  2. 基本迁移
    • 删除 npm 的锁定文件和 node_modules
    rm -rf node_modules package-lock.json
    
    • 使用 pnpm 安装依赖:
    pnpm install
    
    这会创建 pnpm-lock.yaml 文件代替 package-lock.json
  3. 更新 package.json 脚本
    • 将 npm 命令替换为 pnpm
    {
      "scripts": {
        "dev": "pnpm run dev",  // 原先是 npm run dev
        "build": "pnpm run build"
      }
    }
    

改造为 Monorepo

1. 配置工作区

  • 在项目根目录创建 pnpm-workspace.yaml
    packages:
      - 'packages/*'
    
      配置:
      - `packages/*`       - 存放共享的库/包
      - `!**/__tests__`    - 排除测试目录
    
  • 或者在 package.json 中添加
    {
      "private": true,  // monorepo 项目需要设置为私有
      "type": "module",  // 使用 ESM 模块系统
      "workspaces": [
        "packages/*"  // 指定工作空间目录
      ]
    }
    
      两种选一种配置即可,	
      如果同时存在 package.json 的 workspaces 和 pnpm-workspace.yaml:
      pnpm-workspace.yaml 优先级更高,pnpm 会忽略 package.json 的 workspaces 配置。
    

2. 创建子包

创建共享库包

在根目录下创建 packages 目录,以及子包的目录:task-processorthread-poolshared
进入这两个目录中分别执行命令:

pnpm init

编辑生成的 package.jsonname

{
  "name": "@my-monorepo/shared",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

3. 安装依赖

  • 安装全局依赖(所有包共享)

    pnpm add -D -w typescript vite @types/node
    # 或
    pnpm add -Dw typescript vite @types/node
    

    -D 表示开发依赖,没有则是生产依赖
    -w 表示 在 Monorepo 的根目录(工作区根目录)执行操作,而不是在某个具体的子包中执行。

  • 安装 packages 的子包的依赖

    pnpm add moment --filter @my-monorepo/thread-pool
    pnpm add lodash --filter @my-monorepo/task-processor
    

    --filter:指定在特定子项目中安装依赖。

  • 子包之间相互依赖

    pnpm add @my-monorepo/shared@workspace:* --filter @my-monorepo/thread-pool
    

    workspace:* 表示总是使用工作区内的最新版本

    4. 常用命令

    • 在所有包中运行命令
      pnpm -r run build
      
      -r 表示递归执行
    • 在特定包中运行命令
      pnpm --filter @my-monorepo/web run dev
      
    • 安装所有依赖
      pnpm install
      

5. 高级配置

共享配置

可以在根目录创建共享的配置文件(如 tsconfig.base.json),然后在各包中继承:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
  }
}

限制依赖版本

在根目录 package.json 中添加:

{
  "pnpm": {
    "overrides": {
      "react": "18.2.0",
      "typescript": "^4.9.0"
    }
  }
}

版本管理、发布

安装并初始化 Changesets

pnpm add -Dw @changesets/cli
pnpm changeset init

这会创建 .changeset 目录和配置文件。

流程

  1. 添加变更说明

    pnpm changeset
    

    交互式命令行会引导您:

    • 选择要版本化的包

    • 选择版本更新类型 (major/minor/patch) 【未选中时,点击回车切换更新类型】

    • 编写变更描述

      这会生成一个 changeset 文件在 .changeset 目录中。

  2. 版本升级

    pnpm changeset version
    

    这个命令会:

    • 根据 changeset 文件更新包版本
    • 更新依赖关系
    • 生成 CHANGELOG.md 文件
    • 删除已处理的 changeset 文件
  3. 发布到 npm
    在各个子包的 package.json 中添加:

      "publishConfig": {
        "access": "public",
        "registry": "https://registry.npmjs.org/"
      }
    

    否则会报错:402 Payment Required - PUT https://registry.npmjs.org/xxx - You must sign up for private packages

    然后需要在 npm 中创建对应的 组织
    在这里插入图片描述
    然后执行命令:

    	nrm use npm
    	npm login
    	pnpm changeset publish
    

    npm login 前需要切换至 npm 源,不能使用 cnpm 或者 taobao 等源;
    扩展:在 git 中设置并提交对应的 tag 为此次的版本发布

<think>嗯,用户问的是“pnpm add @monorepo/public --filter project1 这一步是什么意思呢?”看起来他们之前已经了解了在pnpm workspaces中如何管理多项目仓库,现在具体询问这个命令的含义。首先,我需要回忆一下pnpm的过滤参数(--filter)的作用,以及如何在工作区中使用它。 用户提到的命令是给project1添加一个依赖,这个依赖是@monorepo/public,也就是公共模块。这里的关键在于--filter参数,它用来指定操作的目标项目。在pnpm的工作区中,通常所有项目共享一个根node_modules,但每个项目可能有自己的依赖。通过--filter,可以在根目录下为特定项目添加依赖,而不需要切换到项目目录。 接下来,我需要解释这个命令的各个部分:“pnpm add”是添加依赖,@monorepo/public是公共模块的名称,--filter project1则是告诉pnpm这个依赖是给project1项目添加的。同时,需要强调工作区协议(workspace:*)的作用,确保使用的是本地公共模块的版本,而不是从远程仓库安装。 可能用户在使用pnpm工作区时,对于如何正确添加项目特定依赖还不清楚,或者在多个项目中如何共享公共模块存在疑问。需要说明这个命令的好处,比如保持依赖集中管理,避免重复安装,以及如何维护版本一致性。 另外,用户可能想知道如果不使用--filter会有什么问题,比如是否会导致依赖安装到根目录而不是特定项目,或者如何正确引用本地模块。需要对比在项目目录直接运行pnpm add和使用--filter的区别,强调在根目录操作的优势。 还需要考虑用户的实际应用场景,比如他们可能有多个项目需要引用同一个公共模块,确保他们理解如何通过工作区配置来实现这一点。可能还需要提到package.json中的依赖声明,以及执行命令后的实际效果,比如符号链接的创建等。 最后,要确保解释清晰,步骤明确,帮助用户理解这个命令在monorepo环境中的重要性,以及如何正确使用它来维护项目结构。可能还需要提醒常见的错误做法,比如在子目录单独安装导致的问题,从而强调最佳实践。</think>### 分步解释:`pnpm add @monorepo/public --filter project1` 的作用 --- #### **1. 命令拆解** - `pnpm add`: 表示安装依赖。 - `@monorepo/public`: 要安装的依赖名称(通常是工作区内的公共模块)。 - `--filter project1`: 指定操作的目标为 `project1` 子项目。 --- #### **2. 核心目的** **将公共模块 `@monorepo/public` 添加为 `project1` 的依赖**,同时: - **建立符号链接**:直接引用本地公共模块(而非从 npm 远程仓库安装)。 - **声明依赖关系**:在 `project1/package.json` 的 `dependencies` 中自动添加 `@monorepo/public: "workspace:*"`。 - **依赖隔离性**:仅在 `project1` 中生效,其他子项目(如 `project2`)不会受到影响。 --- #### **3. 操作流程** 1. **定位公共模块**: pnpm 会根据工作区配置(`pnpm-workspace.yaml`)找到 `public` 目录,将其视为名为 `@monorepo/public` 的本地包。 2. **绑定版本协议**: 通过 `workspace:*` 表示始终使用本地最新代码(直接软链到源码,无需发布npm)。 3. **更新依赖关系**: 在 `project1/package.json` 中添加: ```json { "dependencies": { "@monorepo/public": "workspace:*" } } ``` 4. **生成符号链接**: 公共模块会被软链到根目录的 `node_modules/@monorepo/public`,`project1` 通过此链接访问公共模块。 --- #### **4. 关键优势** - **代码实时同步**: 修 `public` 模块的代码后,`project1` 会立即生效(无需重新安装依赖)。 - **避免重复安装**: 公共模块仅在根目录的 `node_modules` 中保留一份,节省磁盘空间。 - **版本一致性**: 所有子项目通过 `workspace:*` 引用同一份代码,避免版本分裂。 --- #### **5. 对比场景** - **错误操作**: 直接在 `project1` 目录运行 `pnpm add @monorepo/public`(不带 `--filter`)会导致: - 依赖被错误安装到根目录的 `node_modules`,但 `project1` 的 `package.json` 可能未正确声明依赖。 - 可能触发全局依赖解析,影响其他子项目。 - **正确操作**: 始终通过 `--filter` 在根目录操作,确保依赖关系清晰可控。 --- #### **6. 实际效果示例** 假设 `public` 模块导出一个工具函数: ```typescript // public/src/utils.ts export const sum = (a: number, b: number) => a + b; ``` 在 `project1` 中可直接引用: ```typescript // packages/project1/src/index.ts import { sum } from "@monorepo/public"; console.log(sum(1, 2)); // 输出 3 ``` --- ### 总结 此命令的本质是 **建立子项目与公共模块的依赖关系**,通过 pnpm 工作区机制实现代码共享和高效管理,是 monorepo 架构中的核心操作之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值