什么是 Monorepo
Monorepo(单一代码库)是一种将多个项目代码存储在一个仓库里的软件开发策略。相较于每个项目一个仓库的 MultiRepo 策略,Monorepo 更适合管理多个相互依赖的项目。这种策略常用于大型组织和开源项目,例如 Google、Facebook、Babel、Vue3 等都采用了 Monorepo 方案。
优劣势
优势:
- 易于代码复用和依赖管理
- 统一代码风格和规范
- 便于代码重构
- 促进开放、透明、共享的组织文化
劣势:
- 权限管理复杂
- 额外的学习成本
- 需要强大的工具链和自动构建工具的支持
基于 Nx 的 Monorepo 方案
初始化 Nx 工作区
首先,你需要安装 Nx 工具并初始化一个新的工作区。可以使用以下命令:
npx create-nx-workspace@latest my-workspace
选择适合的预设(例如 empty
预设)并提供工作区名称(如 my-workspace
)。
创建应用和库
在 Nx 中,可以创建多个应用和库。应用是可独立运行的项目,而库是可以在多个项目之间共享的模块。以下是创建应用和库的示例:
nx g @nrwl/react:app my-app
nx g @nrwl/react:lib my-lib
组织工作区结构
在 Monorepo 中,组织代码结构非常重要。通常会有以下目录结构:
my-workspace/
apps/
my-app/
src/
.eslintrc.json
...
libs/
my-lib/
src/
.eslintrc.json
...
tools/
package.json
tsconfig.base.json
.eslintrc.base.json
commitlint.config.js
...
apps/
目录包含所有应用。libs/
目录包含所有共享库。tools/
目录用于放置自定义工具和脚本。
配置 ESLint
为了统一代码风格和规范,可以在工作区根目录中创建一个共享的 ESLint 配置文件 .eslintrc.base.json
:
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"]
}
}
然后,在每个子项目的 ESLint 配置文件中引用这个共享配置。例如,在 my-app
和 my-lib
中:
{
"extends": "../../.eslintrc.base.json",
"parserOptions": {
"project": ["./tsconfig.json"]
},
"rules": {
// 可以为每个子项目添加特定的规则
}
}
统一配置 TypeScript 和 Babel
同样的,可以在工作区根目录中创建共享的 TypeScript 和 Babel 配置文件:
tsconfig.base.json
.babelrc
在各个子项目中引用这些共享配置:
// 在子项目的 tsconfig.json 中
{
"extends": "../../tsconfig.base.json",
...
}
构建和测试
使用 Nx 提供的命令进行构建和测试:
nx build my-app
nx test my-lib
Nx 支持并行构建和增量构建,这意味着只会构建发生变化的部分,从而提高效率。
管理依赖
Nx 能自动化管理项目之间的依赖关系。可以使用以下命令来查看受影响的项目并进行构建:
nx affected:build
该命令将检测哪些项目受到了代码变更的影响,并且只构建这些项目,从而节省时间。
利用 Lerna 统一包管理
Lerna 可以帮助解决多个子项目的版本控制和依赖管理问题。例如,可以在工作区根目录中初始化 Lerna:
npx lerna init
Lerna 提供了许多有用的命令,例如:
lerna bootstrap
:安装所有依赖包并创建符号链接。lerna run
:在所有子项目中运行 npm script 脚本。lerna publish
:发布代码变动的包。
设置 commitlint
为了规范化提交信息,可以使用 commitlint。首先,安装 commitlint 及其依赖:
npm install --save-dev @commitlint/{config-conventional,cli}
在项目根目录创建 commitlint.config.js
文件:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test'
]],
'type-case': [2, 'always', 'lower-case'],
'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']]
}
};
配置 Husky
接下来,使用 Husky 设置 Git hooks,以便在每次提交代码时自动运行 commitlint。首先,初始化 Husky:
npx husky install
然后,在项目根目录下创建一个 husky
文件夹,创建一个 commit-msg
钩子脚本:
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
示例 commit 信息
commitlint 强制约束提交信息的格式,例如以下提交信息:
feat(auth): add login functionality
feat
是提交类型,表示这是一个新特性。(auth)
是可选的范围,表示这是与认证相关的更改。add login functionality
是提交的描述。
验证提交信息
可以在命令行中手动验证提交信息是否符合规范:
echo "feat(auth): add login functionality" | npx commitlint
综合示例
以下是一个完整的项目目录结构示例,包括 commitlint 和 Husky 的配置:
my-workspace/
.husky/
commit-msg
apps/
my-app/
src/
.eslintrc.json
...
libs/
my-lib/
src/
.eslintrc.json
...
tools/
package.json
tsconfig.base.json
.eslintrc.base.json
commitlint.config.js
...
在 package.json
文件中配置 Husky 钩子:
{
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "eslint . --ext .ts,.tsx,.js,.jsx"
}
}
}
希望这个综合的说明对你有帮助!这样你就可以在 Monorepo 项目中既使用 commitlint 来规范提交信息,又使用 ESLint 来确保代码质量。如果你有任何具体的问题或需要进一步的说明,随时告诉我。