monorepo架构
- 在一个项目结构,所有相关的工程形成子包进行管理
- 技术栈统一
- 项目间可共享,减少重复代码
- 依赖管理,版本统一管理
- 统一CI/CD流程
pnpm 优势
- 软链接机制,节省磁盘空间
- 安装速度快
- 一句话概括中心化思想解决依赖重复安装问题
开始
新建工程monorepo-demo 在根目录下执行pnpm init,初始化package.json
pnpm init
package.json添加type
# package.json
{ ......
"type": "module",
......
}
根目录下新建 pnpm-workspace.yaml
packages:
# 放你的项目
- 'apps/*'
# 公共组件,工具库
- 'packages/*'
在apps目录下新建vue3项目main-app,勾选ESLint和Prettier
```js
pnpm create vue@latest
当前目录结构
monorepo-demo
├── apps
│ ── main-app # 业务项目
│ ── other-app # 其他业务项目
├── packages
│ ── ui # 通用组件库
│ ── utils # 通用工具库
├── package.json
├── pnpm-workspace.yaml
写一个UI组件
在monorepo-demo/packages/ui目录下初始化package.json,并安装vue和typescript,版本尽量跟你业务工程里面版本号一致
pnpm init
pnpm add "vue@^3.5.13"
pnpm add "typescript@~5.8.3" -D
修改package.json里面name,子包的名称
# package.json
{
"name": "@wk/ui",
......
}
在monorepo-demo/packages/ui新建global.d.ts文件和tsconfig.json文件,配置ts环境,每个子包单独配置环境
global.d.ts
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
tsconfig.json
{
"compilerOptions": {
"outDir": "es",
"target": "ES2015",
"module": "ES2020",
"moduleResolution": "node",
"removeComments": true,
"strict": true,
"allowJs": true,
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "vue",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"resolveJsonModule": true,
},
"include": [
"components/**/*",
"icon/**/*",
"*.d.ts"
],
"exclude": [
"node_modules",
"dist",
"lib",
"es",
"json",
"**/__tests__/**/*"
]
}
ui子包的目录结构
ui
├── node_modules
├── src
│ ── components
│ ── layout
│ ── index.vue
│ ── index.ts
│ ── core
│ ── utils
├── global.d.ts
├── index.ts
├── package.json
├── tsconfig.json
ui/src/components/layout/index.vue
<template>
<div style="color: cadetblue;font-size: 100px;">
测试组件
</div>
</template>
<script setup lang="ts">
// 可以添加导航逻辑、inject、pinia 等
</script>
<style scoped>
</style>
ui/src/components/index.ts
export { default as Layout } from "./layout/index.vue"
ui/index.ts
export * from "./src/components"
在apps/main-app中使用layout组件 安装组件
pnpm add @wk/ui --workspace
使用组件
import { Layout } from "@wk/ui"
commitlint
在项目根目录下安装,要加上-w,pnpm默认不允许在根目录下安装依赖
pnpm add -D @commitlint/cli @commitlint/config-conventional -w
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
在commitlint.config.js文件里自定义git提交规则
# commitlint.config.js
export default {
extends: ['@commitlint/config-conventional'],
rules: {
// 自定义规则
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'revert']
],
// subject 大小写不做校验
'subject-case': [0]
}
};
Husky
根目录安装
pnpm add --save-dev husky -w
初始化
pnpm exec husky init
在.husky目录下新建commit-msg文件,和commitlint联系起来
# commit-msg
pnpm exec commitlint --edit $1
根目录下新建文件.gitmessage,设置提交格式提示,仅供参考
# .gitmessage
# 提交信息模板(遵循 Conventional Commits 规范)
# type(scope?): subject
# 格式:type(scope?): subject
# - type: 提交类型(必填)
# - scope: 影响范围(可选)
# - subject: 简短描述(必填,50字内)
#
# 支持的提交类型:
# - feat: 新功能 (示例:添加用户登录功能)
# - fix: 修复问题 (示例:修复按钮点击无效的问题)
# - docs: 文档变更 (示例:更新 README 文件)
# - style: 代码样式调整(不影响逻辑)(示例:格式化代码)
# - refactor: 代码重构(非功能变更)(示例:重构用户模块)
# - test: 测试相关 (示例:添加登录功能单元测试)
# - chore: 构建或工具变更 (示例:更新依赖)
# - revert: 回滚提交 (示例:回滚提交 abc1234)
根目录下执行
git config commit.template .gitmessage
lint-staged
在根目录下安装
pnpm add lint-staged -D -w
修改.husky/pre-commit文件,在提交之前做代码检查
# pre-commit
# 执行每个子包下面的lint-staged命令
pnpm -r run lint-staged
配置main-app子包 打开monorepo-demo/apps/main-app/package.json添加命令,并配置lint-staged
package.json
{
......
"scripts": {
......
"lint-staged": "lint-staged"
......
}
"lint-staged": {
"*.{js,ts,jsx,tsx,vue}": ["pnpm lint", "pnpm format"],
"*.{less,css}": ["pnpm format"]
}
......
}