pnpm workspace 实践
项目架构采用 pnpm workspace + changelog + husky
github 示例地址1 - Vue+Nest 全栈模版 github 示例地址2 - Vue+TS 前端模版
pnpm
项目初始化,修改车生成的 package.json 文件中的 private:true,防止根目录发布
sh
pnpm init
根目录创建 pnpm-workspace.yaml
文件
配置 pnpm 的 monorepo 工作区,比如这里我们配置 blog 是博客主体,play 是测试用的,packages 下面又可以有主题包、组件包、工具包等等
这里注意一下,如果是多项目方式,根目录 package.json 中的 name 为项目名(看自己想定什么就设置一下)
而子项目中的 package.json 文件中的 name 就需要以 @ + 根目录 package.json 中的 name 名 + / + 子项目名
yaml
packages:
- 'packages/*'
- 'doc'
指定运行Node、pnpm 版本
json
{
"engines": {
"node": ">=20",
"pnpm": ">=8"
}
}
接下来我们切换到 packages 目录中,创建子项目 比如我这里要创建 vitepress 项目
sh
cd doc
pnpm dlx vitepress init
创建 vue 项目就使用
sh
pnpm create vite
只允许使用 pnpm
如果不希望其他人使用 yarn、npm 等包管理器,只需要在 package.json 文件添加以下命令
json
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
只要有人使用其他包管理器安装依赖就会报错!
添加依赖
- 全局依赖
sh
pnpm add xxx -D -W
# or
pnpm add xxx -Dw
-W:workspace-root 把依赖安装到全局 node_modules -D:开发依赖
依赖区别: dependencies:生产依赖 devDependencies:开发依赖 peerDependencies:宿主依赖(运行主依赖),指定当前模块包在使用需要安装的依赖
- 局部依赖
sh
# 路径在需要引入依赖的目录
pnpm add xxx -D
# 在根目录 @xxx/xxx 为子项目 name 名
pnpm add xxx -F @xxx/xxx
ESLint && Prettier
引入依赖
sh
pnpm add eslint prettier -Dw
# 初始化 eslint 配置
pnpm eslint --init
# 其他依赖
pnpm add -Dw @typescript-eslint/parser eslint-plugin-vue @typescript-eslint/eslint-plugin
# 解决冲突
pnpm add eslint-config-prettier eslint-plugin-prettier -Dw
解决冲突
.eslintrc.cjs
js
{
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-essential",
// 将 prettier 放在最后面,让它的优先级比 eslint 低一点
"plugin:prettier/recommended",
],
}
添加检查命令
json
{
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
"format": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}",
}
内部包的引用
husky + lint-staged 代码预检查
引入依赖
sh
pnpm add husky lint-staged -Dw
添加脚本命令到 json 中
json
{
"prepare": "husky install"
}
运行一下命令,创建一个 pre-commit 钩子
sh
#手动运行
pnpm prepare
#添加 pre-commit 钩子
npx husky add .husky/pre-commit "npx --no-install lint-staged"
pre-commit
sh
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# 这是自己加的
echo "--------- 代码预检查 ---------"
npx --no-install lint-staged
配置 lint-staged,在 package.json 中添加下面的配置信息
json
//与 scripts 同一级
{
"lint-staged": {
"*.{js,vue,ts,jsx,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{html,css,less,scss,md}": [
"prettier --write"
]
},
}
提交规范
引入依赖
sh
pnpm add @commitlint/cli @commitlint/config-conventional cz-git -Dw
添加命令
json
{
"type":"module",
"scripts": {
"cz": "git cz",
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
}
我们用它来限制不符合规范的提交信息,根目录创建commitlint.config.js文件-如果后面报错就需要将文件改为 .cjs
同时还需修改一些内容
js
// commitlint.config.js
/** @type {import('cz-git').UserConfig} */
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"build",
"chore",
"perf",
"ci",
"revert",
],
],
"type-case": [2, "always", "lower-case"],
"type-empty": [2, "never"],
"subject-full-stop": [2, "never", "."],
"header-max-length": [2, "always", 100],
"subject-case": [
2,
"never",
["sentence-case", "start-case", "pascal-case", "upper-case"],
],
},
prompt: {
useEmoji: true,
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
messages: {
type: "选择你要提交的类型 :",
scope: "选择一个提交范围(可选):",
customScope: "请输入自定义的提交范围 :",
subject: "填写简短精炼的变更描述 :\n",
body: "填写更加详细的变更描述(可选)。使用 '|' 换行 :\n",
breaking: "列举非兼容性重大的变更(可选)。使用 '|' 换行 :\n",
footerPrefixesSelect: "选择关联issue前缀(可选):",
customFooterPrefix: "输入自定义issue前缀 :",
footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
confirmCommit: "是否提交或修改commit ?",
},
types: [
{
value: "feat",
emoji: "✨",
name: "feat: 新增功能 | A new feature",
},
{ value: "fix", name: "fix: 修复缺陷 | A bug fix" },
{
value: "docs",
emoji: "📚",
name: "docs: 文档更新 | Documentation only changes",
},
{
value: "style",
emoji: "💎",
name: "style: 代码格式 | Changes that do not affect the meaning of the code",
},
{
value: "refactor",
emoji: "📦",
name: "refactor: 代码重构 | A code change that neither fixes a bug nor adds a feature",
},
{
value: "perf",
emoji: "🚀",
name: "perf: 性能提升 | A code change that improves performance",
},
{
value: "test",
emoji: "🚨",
name: "test: 测试相关 | Adding missing tests or correcting existing tests",
},
{
value: "build",
emoji: "🛠",
name: "build: 构建相关 | Changes that affect the build system or external dependencies",
},
{
value: "ci",
emoji: "⚙️",
name: "ci: 持续集成 | Changes to our CI configuration files and scripts",
},
{
value: "revert",
emoji: "🗑",
name: "revert: 回退代码 | Revert to a commit",
},
{
value: "chore",
emoji: "♻️",
name: "chore: 其他修改 | Other changes that do not modify src or test files",
},
],
},
};
使用 husky 生成 commit-msg 文件,验证提交信息
sh
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
commit-msg
sh
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# 自己加的
echo "--------- 执行commit-msg校验 ---------"
npx --no-install commitlint --edit $1
changeset
引入依赖并初始化
sh
# -D 开发依赖
# -w 公共依赖
pnpm add -Dw @changesets/cli
# 初始化
pnpm changeset init
初始化后会在根目录下生成 .changeset 文件夹
其中 config.json 作为默认 changeset 配置文件
- changelog: changelog 生成方式
- commit: 不要让 changeset 在 publish 的时候帮我们做 git add
- linked: 配置哪些包要共享版本
- access: 公私有安全设定,内网建议 restricted ,开源使用 public
- baseBranch: 项目主分支
- updateInternalDependencies: 确保某包依赖的包发生 upgrade,该包也要发生 version upgrade 的衡量单位(量级)
- ignore: 不需要变动 version 的包
- ___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH: 在每次 version 变动时一定无理由 patch 抬升依赖他的那些包的版本,防止陷入 major 优先的未更新问题
changeset 常用命令及说明
sh
# 使用 changeset 进行记录版本修改
npx changeset add
# 使用 changeset version 提交版本修改
npx changeset version
# 使用 changeset publish 进行发包
npx changeset publish
版本号一般有三个部分,以.
隔开,就像 X.Y.Z
,其中
- X:主版本号,不兼容的大改动,major
- Y:次版本号,功能性的改动,minor
- Z:修订版本号,问题修复,patch
changeset version 提交版本修改
.npmrc
pnpm 常用
.npmrc
strict-peer-dependencies=false
shell-emulator=true
auto-install-peers=false