1. 主题背景
单体应用架构 vs 多仓多模块管理 vs 单仓多模块管理 三种代码组织和维护的方式各有有缺点:
- 单体应用架构(monolithic): 软件开发前期, 业务不复杂, 依赖较少, 使用分层方式组织代码, 简单易用, 维护效率较高
- 多仓多模块管理(multirepo): 因为业务复杂和代码量增多, 单体架构难以有效组织代码, 编译时间过长, code review和代码维护也面临困难, 通常从单体架构拆分为微服务, 每个微服务是一个代码仓库, 独立升/编译/维护/上线
- 单仓多模块管理(monorepo): 多仓库模式在仓库数量持续增加后面临公共资源重复引用, CI/CD等脚本重复分散到各个项目维护, 单仓多模块管理的组织方式减轻了重复项维护的痛点, 另外在主干开发的GitFlow模式中单仓库更简单, 无需在多仓库模式中分别创建和维护主干分支
参考文档:
2. 演练
nx命令行不需要额外, npm安装后默认自带这个子命令, 可以使用一下命令验证:
演练主要使用nest插件作为脚手架工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| npx create-nx-workspace nx-tutorial --preset=nest --appName tutotial --nxCloud false cd nx-tutorial/ && npm install -D @nrwl/nest
yarn create nx-workspace nx-tutorial --preset=nest --appName tutotial --nxCloud false cd nx-tutorial/ && yarn add -D @nrwl/nest
tree . -L 1 . ├── README.md ├── node_modules ├── nx.json ├── package-lock.json ├── package.json ├── apps ├── libs ├── tools └── tsconfig.base.json
|
上面的apps和libs是存放自项目的位置
1 2 3 4
| yarn nx generate @nrwl/nest:app main-api
yarn nx generate @nrwl/nest:lib auth --publishable --importPath=@org/auth --buildable
|
在main-api中调用auth lib中的一个方法
1 2 3 4 5 6 7 8 9 10 11 12
| yarn nx build auth yarn nx build main-api
yarn nx run-many --projects=auth,main-api --target=build
yarn nx affected --target=build
yarn nx serve main-api
yarn nx affected --target=serve
|
**演练代码仓库: **nx-tutorial
- 工作区 workspace
工作区是monorepo组织多个项目框架, 这个概念和golang/yarn等技术中的工作区概念一致
- 工作区是
nx.json所在的文件夹, 而项目一般存放到 packages/apps/libs等目录下
- 项目存放的目录名称可以在在nx.json中配置, 并不一定使用自动生成的目录
1 2 3 4
| "workspaceLayout": { "appsDir": "demos", "libsDir": "packages" },
|
- 项目 project
- 项目是组织单仓库多项目架构的基础概念, 项目会被放置在一个workspace中
- 命令 target
- 提供一种命令的定义, 可以定义在工作区(nx.json)和项目(project.json)级别
- 优先使用项目级别的, 项目级别的target是和工作区的target做合并的
- 执行任务
- 任务定义位置有两处
- package.json中的scripts
- project.json中的targets
- 执行任务的方式
- nx [project] [target]
- nx run [project][:target][:configuration] [_..]
- nx run-many: 执行全部
- 支持并行
- 支持依赖执行: nx affected –targets=a,b,c,d
- 缓存任务结果
- 目的: 方式代码未变更却重复的执行任务, 减少执行次数, 增加执行效率
- 执行任务缓存可配置(nx.json)
1 2 3 4 5 6 7 8 9 10
| { "tasksRunnerOptions": { "default": { "runner": "nx/tasks-runners/default", "options": { "cacheableOperations": ["build", "test"] } } } }
|
- 使用缓存: 任务执行之前通过任务的
input结合缓存判断代码是否发生变更, 如果未发生变更则从缓存中恢复output, 例如: 文件/终端输出
- 缓存位置和文件: node_modules/.cache/nx/run.json
- 清除缓存: nx reset
- 生成器 generator
- 命令行 CLI
- nx affected:graph: 可以开启一个本地website,在该界面上可以查看依赖关系和
target
- 自动更新依赖
1 2 3 4 5 6
| yarn nx migrate latest
yarn nx migrate --run-migrations
rm migrations.json
|
为了方式项目引用到其他项目内部的的对象, 让依赖关系变得凌乱, 为此可以通过强制限定项目边界限定依赖关系仅通过项目引用.
1
| yarn add npm i @nrwl/eslint-plugin-nx @nrwl/devkit -D
|
1 2 3 4 5 6
| { "tags": [ "scope:lib", "scope:app" ] }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| { // ... more ESLint config here
// @nrwl/nx/enforce-module-boundaries should already exist within an "overrides" block using `"files": ["*.ts", "*.tsx", "*.js", "*.jsx",]` "@nrwl/nx/enforce-module-boundaries": [ "error", { "allow": [], // update depConstraints based on your tags "depConstraints": [ { "sourceTag": "scope:lib", "onlyDependOnLibsWithTags": ["scope:lib"] }, { "sourceTag": "scope:app", "onlyDependOnLibsWithTags": ["scope:app", "scope:lib"] } ] } ]
// ... more ESLint config here }
|