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

相关概念

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

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

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

将 npm 项目迁移到 pnpm

  1. 安装 pnpm

    bash 复制代码
    npm i pnpm -g

    查看是否安装成功及版本号

    bash 复制代码
    pnpm -v
  2. 基本迁移

    • 删除 npm 的锁定文件和 node_modules:
    bash 复制代码
    rm -rf node_modules package-lock.json
    • 使用 pnpm 安装依赖:
    bash 复制代码
    pnpm install

    这会创建 pnpm-lock.yaml 文件代替 package-lock.json

  3. 更新 package.json 脚本

    • 将 npm 命令替换为 pnpm:
    json 复制代码
    {
      "scripts": {
        "dev": "pnpm run dev",  // 原先是 npm run dev
        "build": "pnpm run build"
      }
    }

改造为 Monorepo

1. 配置工作区

  • 在项目根目录创建 pnpm-workspace.yaml

    yaml 复制代码
    packages:
      - 'packages/*'
    复制代码
      配置:
      - `packages/*`       - 存放共享的库/包
      - `!**/__tests__`    - 排除测试目录
  • 或者在 package.json 中添加

    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-processor,thread-pool,shared

进入这两个目录中分别执行命令:

bash 复制代码
pnpm init

编辑生成的 package.json 的 name:

json 复制代码
{
  "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. 安装依赖

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

    bash 复制代码
    pnpm add -D -w typescript vite @types/node
    # 或
    pnpm add -Dw typescript vite @types/node

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

  • 安装 packages 的子包的依赖

    bash 复制代码
    pnpm add moment --filter @my-monorepo/thread-pool
    pnpm add lodash --filter @my-monorepo/task-processor

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

  • 子包之间相互依赖

    bash 复制代码
    pnpm add @my-monorepo/shared@workspace:* --filter @my-monorepo/thread-pool

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

    4. 常用命令

    • 在所有包中运行命令

      bash 复制代码
      pnpm -r run build

      -r 表示递归执行

    • 在特定包中运行命令

      bash 复制代码
      pnpm --filter @my-monorepo/web run dev
    • 安装所有依赖

      bash 复制代码
      pnpm install

5. 高级配置

共享配置

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

json 复制代码
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
  }
}

限制依赖版本

在根目录 package.json 中添加:

json 复制代码
{
  "pnpm": {
    "overrides": {
      "react": "18.2.0",
      "typescript": "^4.9.0"
    }
  }
}

版本管理、发布

安装并初始化 Changesets

bash 复制代码
pnpm add -Dw @changesets/cli
pnpm changeset init

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

流程

  1. 添加变更说明

    bash 复制代码
    pnpm changeset

    交互式命令行会引导您:

    • 选择要版本化的包

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

    • 编写变更描述

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

  2. 版本升级

    bash 复制代码
    pnpm changeset version

    这个命令会:

    • 根据 changeset 文件更新包版本
    • 更新依赖关系
    • 生成 CHANGELOG.md 文件
    • 删除已处理的 changeset 文件
  3. 发布到 npm

    在各个子包的 package.json 中添加:

    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 中创建对应的 组织

    然后执行命令:

    bash 复制代码
    	nrm use npm
    	npm login
    	pnpm changeset publish

    npm login 前需要切换至 npm 源,不能使用 cnpm 或者 taobao 等源;

    扩展:在 git 中设置并提交对应的 tag 为此次的版本发布

相关推荐
计算机魔术师21 分钟前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端
米米商聊25 分钟前
图标能点,按钮就可用了吗?键盘、名称与收藏状态
前端·javascript
Younglina1 小时前
三个晚上,我和 WorkBuddy 做了个生图网站
前端·后端·ai编程
xy34531 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
陈随易2 小时前
副业搞钱点子之收入查看器
前端·后端
Profile排查笔记2 小时前
浏览器指纹逆向怎么分析:从网络请求追踪到 JavaScript 采集链
前端·人工智能·后端·自动化
hudie7653 小时前
LikeShop 二开最常改的 5 个文件(附改前改后对比)
前端·uni-app·php·个人开发
qetfw3 小时前
Bash 函数与流程控制:read、if、for、case 验证
linux·前端·javascript·bash
鬼手点金4 小时前
从 API 消息到模型 Token:Chat Template
java·前端·javascript·数据库·人工智能·深度学习·1024程序员节
Shadow(⊙o⊙)4 小时前
LangChain 自定义工具全解析:从 @tool 到 bind_tools 的完整调用链路
java·服务器·前端·1024程序员节