pnpm搭建monorepo项目

751 阅读3分钟

首先看下pnpm的特点

  • 快速:pnpm比传统方案(yarn, npm)安装包的速度快了两倍,甚至比yarn2,pnp模式还要快
  • 更严格高效:node_modules 中的文件是从一个单一的可内容寻址的存储中链接过来的,代码无法访问任意包
  • monorepo:天然内置支持当仓库多包

pnpm包管理模式是 软连接+硬链接,磁盘根目录创建.pnpm-store目录,所有项目在node_modules中根据package.json创建需要包的软连接,只有需要包在这一层,不会像yarn和npm拉平后有所有包,造成幽灵依赖问题,这些软连接到.pnpm目录下有所有依赖包的版本,这里是硬链接到.pnpm-store的硬链接。

由此好处有节省磁盘空间,更多缓存下载包很快,依赖包可靠性无幽灵依赖,内置monorepo

配置模板 gitee.com/rootegg/pnp…

初始化项目

npm i -g pnpm

pnpm init 

git config --global core.autocrlf false

git init

创建 pnpm-workspace.yaml

www.pnpm.cn/pnpm-worksp…

留一句就行

packages:
  - 'packages/*'

eslint 配置

装eslint

-w 是因为当前是monorepo项目需要指明安装到哪个项目,-w 是指安装到根目录中

pnpm i eslint -D -w

npx eslint --init

报错注意项

  • 用eslint检查语法,不修改代码风格,后面用prettier管理代码风格

  • 其他配置项看图片

  • 会出现两次报错,第一次是没有 -w ,第二次是 @latest 不识别,手动执行下面语句,没有逗号

pnpm i -D -w @typescript-eslint/eslint-plugin @typescript-eslint/parser

image.png

image.png

修改 .eslintrc.json 内容

{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier",
    "plugin:prettier/recommended"
  ],
  "overrides": [],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint", "prettier"],
  "rules": {
    "prettier/prettier": "error",
    "no-case-declarations": "off",
    "no-constant-condition": "off",
    "@typescript-eslint/ban-ts-comment": "off"
  }
}

装ts的eslint插件

pnpm i -D -w @typescript-eslint/eslint-plugin

装 prettier

pnpm i -D -w prettier

配置文件 .prettierrc.json

{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": true,
  "singleQuote": true,
  "semi": true,
  "trailingComma": "none",
  "bracketSpacing": true
}

处理eslint和prettier风格冲突

pnpm i -D -w eslint-config-prettier eslint-plugin-prettier

vscode 装插件 eslint 和 prettier

image.png

image.png

设置vscode默认格式化和自动保持格式化

当文件保存时,自动触发格式化

image.png image.png

package.json 中配置lint命令

--quiet 静默不打印输出

"scripts": {
    "lint": "eslint --ext .ts,.tsx,.jsx,.js --fix --quiet ./packages"
},

hushky 拦截git命令

typicode.github.io/husky/#/?id…

pnpm i -D -w husky

初始化husky

npx husky install

根目录出现 .husky 目录

package.json 增加命令

"scripts": { 
    "prepare": "husky install" 
}

lint命令加入husky的pre-commit中

npx husky add .husky/pre-commit "pnpm lint"

.husky 目录中出现pre-commit文件,并看到加入pnpm lint

扩展pnpm lint会对代码全量检查,当项目复杂后,运行速度可能比较慢,届时可以考虑使用lint-staged实现只对暂存区代码进行检查

使用commitlint对git提交信息检查

pnpm i -D -w @commitlint/cli @commitlint/config-conventional

新建 .commitlintrc.js 配置文件

module.exports = {
	extends: ['@commitlint/config-conventional']
};

将commitlint集成到husky中

npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"

在.husky目录下新增了commit-msg文件

验证下,eslint触发了,commitlint也触发了,但是报错

因为 commit msg写 1,报错,说明对了,需要按照 feat: 1 等格式书写

image.png

image.png

typescript配置

装包

npm i -g typescript
tsc --init

修改tsconfig.json

baseUrl指项目入口

{
	"compileOnSave": true,
	"compilerOptions": {
		"target": "ESNext",
		"useDefineForClassFields": true,
		"module": "ESNext",
		"lib": ["ESNext", "DOM"],
		"moduleResolution": "node",
		"strict": false,
		"sourceMap": true,
		"resolveJsonModule": true,
		"isolatedModules": true,
		"esModuleInterop": true,
		"noEmit": true,
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"noImplicitReturns": false,
		"skipLibCheck": true,
		"baseUrl": "./packages"
	}
}

正式建包

packages 下建 react 文件夹,在react文件夹下执行 init

pnpm init
  • 因为项目是esm规范,所以去掉package.json的main字段
  • 增加"module": "index.ts",

1、建一个react包和shared包

2、react包引用shared包,注意修改react的package.json,指明依赖shared

"dependencies": {
    "shared": "workspace:*"
},

rollup 打包工具

pnpm i -D -w rollup
pnpm i -D -w rollup-plugin-typescript2 @rollup/plugin-commonjs rimraf rollup-plugin-generate-package-json

打包出三个文件:@react/jsx-dev-runtime.js,@react/jsx-runtime.js,React