背景
尝试一下使用pnpm构建大仓。
大仓常用的场景是:多个项目依赖于一个公共包,并且公共包经常不发npm包,在多人合作的大工程中经常会被使用。
多个项目中会有共享的代码则可以分包引用。并且每个 package 也可以在自己的作用域引入自己的 dependencies。
如果项目不是过于依赖建议不使用大仓形式。
搭建构建步骤
- 创建目录
test-monorep-v1
- 在项目目录中执行
pnpm init
,并创建packages
和projects
两个文件夹。 - 创建在根目录下创建
pnpm-workspace.yaml
,并输入用于配制包目录的路径。
packages:
- 'packages/*'
- 'projects/*'
- 在 projects 目录中创建react项目,或者是从现有的项目中复制进来。 复制进来的注意把node_modules删除掉。
这里进行创建一个新的app1项目。
cd projects
pnpm create vite app1 --template react-ts
先不对app1
进行install
。
- 在packages中创建
utils
文件夹,并执行pnpm init
。
修改生成的package.json
文件,并将name
修改为 @test/utils
修改入口 main
为 index.ts
最终utils中的 package.json
如下:
{
"name": "@test/utils",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
index.ts
文件中内容如下:
export const add = (a: number, b: number) => a + b + 10000002;
- 配置eslint用来进行语法检查
.eslintrc.cjs
文件内容如下:
module.exports = {
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'airbnb-base',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
plugins: ['react', 'import', '@typescript-eslint'],
rules: {
semi: ['error', 'always'],
quotes: ['error', 'single'],
'max-len': ['error', { code: 120, tabWidth: 2 }],
indent: ['error', 2],
'space-before-function-paren': ['error', 'always'], // 表达式后边的空格
'comma-dangle': ['error', 'never'],
'no-multi-spaces': 1, // 不能用多余的空格
'comma-spacing': [2, { before: false, after: true }], // 控制逗号前后的空格
'no-dupe-keys': 2, // 在创建对象字面量时不允许键重复 {a:1,a:1}
'no-else-return': 2, // 如果if语句里面有return,后面不能跟else语句
'no-empty': 2, // 块语句中的内容不能为空
'no-extra-parens': 2, // 禁止非必要的括号
'no-extra-semi': 2, // 禁止多余的冒号
'no-spaced-func': 2, // 函数调用时 函数名与()之间不能有空格
'no-use-before-define': 2, // 未定义前不能使用
'arrow-parens': 0, // 箭头函数用小括号括起来
'arrow-spacing': 1, // =>的前/后括号
'key-spacing': [1, { beforeColon: false, afterColon: true }], // 对象字面量中冒号的前后空格
'lines-around-comment': 1, // 行前/行后备注
'spaced-comment': 1// 注释风格不要有空格什么的
}
};
当前项目结构如下:
├── .eslintrc.cjs
├── package.json
├── packages
│ └── utils
│ ├── index.ts
│ └── package.json
├── pnpm-workspace.yaml
└── projects
└── app1
├── .eslintrc.cjs
├── .gitignore
├── index.html
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
安装依赖包
- 向根目录中安装
需要的话使用-w(–workspace-root) 例如下面eslint相关包。
pnpm add eslint eslint-config-airbnb-base eslint-plugin-import -w -D
pnpm add @typescript-eslint/parser @typescript-eslint/eslint-plugin -w -D
pnpm add eslint-plugin-react eslint-plugin-react-hooks -w -D
- 向单个目录中安装 某个pack的依赖
pnpm --filter app1 i @test/utils -r
这样我们就在 app1
项目中安装了@test/utils
依赖。
执行完成后,会在app1
的package.json
中产生如下配置
"dependencies": {
"@test/utils": "workspace:^1.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
启动某个项目
启动 app1
(pnpm语法其实很好记,对某个仓库操作直接使用 –filter)
pnpm --filter app1 run dev
项目中使用包
这样在项目中app1
中就可以使用 @test\utils
模块
import { add } from '@test/utils';
console.log(add(1, 5));
其他
-
修改被依赖包是否会进行HMR?
是的,使用vite作为开发工具时,修改依赖是可以进行热更新的。
-
WARN Issues with peer dependencies found
在依赖文件时会出现如下问题:
WARN Issues with peer dependencies found
projects/app1
├─┬ @project1/modle1 0.1.32
│ ├── ✕ unmet peer react@^16.8.0: found 17.0.2
什么是peeDependencies
?
当我们在一些npm包当中中,用到一些核心的依赖,这些依赖又是跟顶部应用的依赖的一样的时候,会把这些放到peerDependencies当中。
而且这个peerDependencies通常在插件当中出现。
问题来了,为什么不能直接把这些依赖直接放到dependencies当中呢?
例如: 想象一下,您正在开发一个ReactApp
,他依赖React
,有两个插件plugin1
,plugin2
,他们也依赖React
,如果在两个插件中使用dependencies
,那么在 install 之后,在两个插件下都会出现对React
的依赖。
React在顶层已经安装了一次,但是在plugin1 和 plugin2 中又进行了重复的安装,所以被安装了三次。
peerDependencies
就是干这事情的,避免重复安装依赖。
网上说了很多方法,不管哪种解决方法,都是需要用户自己去解决这些不一致问题。
所以说现在npm,pnpm本身并没很好的办法去解决库当中版本依赖不一致的问题,终局还需要手动升级包或者插件。
具体的结局方法可以参照: 传送门
如我上面所说,警告⚠️就是告诉你不一定会报异常,但是也不确定能一定能正常。
库当中的版本依赖不一致是有可能造成一些不不要的麻烦的,所以你看到如babel-loader,
babel
这些库在升级版本时候,官方要求多个库同步升级,否则会构建失败。
原文链接:https://juejin.cn/post/7243725147110391867 作者:大熊全栈分享