pnpm: 使用 monorepo 常见问题

1,921 阅读2分钟

常见问题

1. 依赖安装被阻止

monorepo 项目安装依赖到主工作区的方式与常规项目不一致,如果直接 pnpm add 将得到以下提示:

$ pnpm add xxx

Running this command will add the dependency to the workspace root, which might not be what you want - if you really meant it, make it explicit by running this command again with the -w flag (or --workspace-root). If you don't want to see this warning anymore, you may set the ignore-workspace-root-check setting to true.

解决方法如提示所示,添加 -w 标识即可。如:

$ pnpm add xxx -w

如果希望在所有子包中都安装此依赖,那么将 -w 替换为 -r 即可。

2、安装子包模块始终会走远程库查找依赖

./.npmrc 是项目级 pnpm 配置管理文件。对于子包安装未能优先查找本地的问题,可在 .npmrc 文件中添加以下配置即可。

link-workspace-packages = true # 启用工作区内部的包链接 
prefer-workspace-packages = true # 优先选择工作区中的包 
recursive-install = true # 递归地安装工作区中所有项目的依赖

补充.npmrc 文件配置讲解

3、无法找到子包导出引用

当时使用 pnpm init 初始化子包,同时添加设置导出配置如 exports/typesVersions。在项目中导入使用时,总是提示:

Cannot find module '@sa/enums' or its corresponding type declarations.  
There are types at 'c:/**/node_modules/@sa/demo/src/index.ts', but this result could not be resolved under your current 'moduleResolution' setting. Consider updating to 'node16', 'nodenext', or 'bundler'.

大致意思是当前模块导出方案无法找到 @sa/enums 依赖的导出。通过查看其他 monorepo 项目后发现,package.json 中的属性 exports/typesVersionsmain 是互斥的。 基本讲解:exportsmain 两个属性都是用以指定模块的导出规则的。main 通常用于指定包的入口文件, 而 exportsES Module 提出的一种以更细粒度指定包入口的方案。如果两者同时存在将产生歧义,处理器无法正常识别依赖的入口文件。
因此,移除其中之一即可。
补充node: package.json 属性讲解

其他

1、exports/typesVersions 使用场景

@sa/enums 子包为例,假设目录结构为:

enums 
├── node_modules
├── src
│  ├── index.ts
│  ├── ipc.ts
|  └── event.ts
├── tsconfig.json 
└── package.json

@sa/enums 的不同文件中存在名称相同但操作逻辑不同的函数时,那么在不改变命名的情况下,自然联想到直接把包文件直接导出不就解决了吗。如:

// main.ts
import { a as IPC_A } from "@sa/enums/ipc"
import { a as EVENT_A } from "@sa/enums/event"

如果 @sa/enums/package.json 中只是设置了 main 属性,那么 import 语句会得到异常:

Cannot find module '@sa/enums/ipc' or its corresponding type declarations.

此时 exports 就派上用场了(同时移除属性 main )。参考如下:

// package.json
{
  "exports": {
    ".": "./src/index.ts",
    "./ipc": "./src/ipc.ts",
    "./event": "./src/event.ts",
  }
}

// 由于当前是 `typescript` 项目,还可追加类型导出`typesVersions` 如下:
// package.json
{
  "typesVersions": {
    "*": {
      "*": ["./src/*"],
      "ipc": ["./src/ipc.ts"],
      "event": ["./src/event.ts"]
    }
  }
}