强大的构建系统:NX
【前言】
nx是一个强大的构建系统,
这么说可能比较模糊,
本文实践一个项目,带大家了解nx,
感兴趣的也可以自己探索: https://nx.dev/
nx一些典型的应用场景:
1.基于package的monorepo管理
2.完整的前端项目管理
3.react,angular等项目管理
4.nodejs项目管理

本文从monorepo的场景做介绍
【创建项目】
可以使用nx-cli这个工具创建项目,
一种方式是不全局安装nx,使用npx命令,如下
npx create-nx-workspace@latest package-based --preset=npm
一种方式是全局安装nx
npm install -g nx
本文采用全局安装的方式,
安装完成后使用下面的命令初始化项目,
nx init
通过一些命令行交互后会创建项目,

创建好一个monorepo项目,文件结构如下

可以看到一个monorepo常见的文件结构已经创建好了,
比较有意思的是readme里的两个命令,

这两个命令后续会讲到。
【构建项目】
文章开头介绍到nx是一个构建系统,
和常见的webpack,rollup等构建工具做区分,
nx提供对整个项目的管理,而不是具体的构建工具,
下面创建一个文件夹pacages/is-even,结构如下

可以看到这里使用rollup来构建,
nx官网的demo使用tsc来构建,
所以nx并不介入具体的构建工具,
而是一个构建系统,用来管理项目。
package.json内容
{
"name": "is-even",
"version": "0.0.0",
"main": "index.js",
"scripts": {
"build": "rollup -c"
}
}
src/index.js内容
export const isEven = (x) => x % 2 === 0;
可以看到is-even这个文件夹下有build命令,
通过使用nx可以不用进入到packages/is-even来构建,
直接在最外层执行下面命令即可,
nx build is-even
效果如下

无需进入packages中,在最外层构建,是nx特性之一
【管理任务依赖】
接着创建is-odd文件夹,与is-even类似,
关键的index.js内容
import { isEven } from 'is-even';
export const isOdd = (x) => !isEven(x);
这里可以看到is-odd这个package依赖is-even,
执行nx build is-odd,效果如下

这里虽然成功了,
但是构建好的is-odd代码中会require is-even,
所以最好是每次构建is-odd的时候提前构建好is-even,
也就是is-odd的build依赖于is-even的build,
这里只需要在nx.json中添加如下内容,
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
意思是build任务的执行依赖于依赖包中的build执行完成,
即build is-odd时,需要先build is-even,
查看下效果,

可以看到再次执行is-odd的时候会自动查找依赖项,并build依赖项
管理多个包的任务依赖,也是nx的特性之一
【使用缓存】
再次执行下面命令的时候,
nx默认会使用之前的缓存,如下
nx build is-odd

默认使用缓存,也是nx的特性之一
【多包任务执行】
nx也支持多个包同时执行任务,效果如下
nx run-many --target=build

多包任务执行,也是nx特性之一
【执行任务】
nx是一个构建系统,不是构建工具,
nx用来管理代码项目,项目中可以有各种构建工具,
一个主要的功能就是执行任务,
任务的定义比较简单,
package.json中的scripts即可定义,
例如下面,对is-even这个包定义了build任务,
{
"name": "is-even",
"version": "0.0.0",
"main": "index.js",
"devDependencies": {},
"scripts": {
"build": "rollup -c"
}
}
执行单个任务:
nx run is-even:build
执行多个任务:
npx nx run-many --target=build
启用缓存,
在nx.json中添加如下配置即可启用本地缓存,
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "lint", "test", "e2e"]
}
}
},
启用缓存后效果如下

【使用分布式缓存】
上面的本地缓存其实意义不大,
当有代码修改的时候,本地缓存效果比较弱,
nx最惊艳的是nx-cloud,
简单来说就是支持云端缓存,
就是一个团队中,
当某一个人本地build过一次,
可以将cache同步到云端,
团队内其他的人再次build时就可以共用云端的缓存,

连接nx-cloud,如下
nx connect-to-nx-cloud
效果如下

访问上图中的url,需要注册用户,登录进去后,
nx会把本地生成的accessToken和你的账户绑定,

然后按提示执行几个命令

执行以上步骤后,
就可以在nx-cloud上看到构建的汇总和详情了

基于nx-cloud的分布式缓存,是nx最惊艳的特性
【依赖分析】
使用nx graph命令可以查看项目中的包依赖关系,
效果如下

访问url后可以看到本项目的依赖关系,

示例demo比较简单,is-odd依赖于is-even,
如果是一个很复杂的项目,依赖分析是一个挺好用的功能,
包依赖分析,也是nx特性之一
【再谈缓存】
nx最强大的特性之一就是缓存,
下面集中讲一下nx的缓存。
清空缓存
可以使用下面的命令清空缓存
nx clear-cache

默认本地缓存
如果是通过nx init初始化的项目,
默认生成的nx.json内容如下,
{
"extends": "nx/presets/npm.json",
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build"]
}
}
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
默认启动了对build任务的缓存,
本地build效果如下,

可以看到清空缓存后首次build耗时1s,
再次执行时命中了本地缓存,耗时24ms。
定制本地缓存
如果你删除build的产物index.js,
再次执行命令,你会发现也会命中缓存,
但是没有生成index.js,

这是因为没有定制本地缓存,
nx默认会检测一些文件夹,例如dist文件夹,
定制方法是在package下添加project.json,
或者直接在package下的package.json中添加nx属性,
后者如下:
{
"name": "is-even",
"version": "0.0.0",
"main": "index.js",
"devDependencies": {},
"scripts": {
"build": "rollup -c"
},
"nx": {
"namedInputs": {
"default": ["{projectRoot}/src/**/*"]
},
"targets": {
"build": {
"inputs": ["default"],
"outputs": ["{projectRoot}"],
"dependsOn": ["^build"]
}
},
"includedScripts": ["build"]
}
}
可以看到nx下配置了input输入是package下的src文件,
输出是package文件夹,
配置后每次build,nx会检测输出文件夹是否有缓存,
没有则将nx系统中的缓存还原到输出文件夹,
再次执行命令,效果如下

可以看到提示命中了local cache,
nx的localcache位置在node_modules/.cache/nx/
更多定制缓存信息: https://nx.dev/reference/project-configuration#outputs
分布式缓存
按上文介绍的方式连接nx-cloud后,
就可以使用强大的分布式缓存了,
先清空缓存,然后执行build,效果如下,

这相当于整个团队的首次构建。
再次清空缓存,执行build,效果如下

可以看到命中remote cache了,
也就是模拟了,
团队内某一个伙伴完成构建,
其他伙伴都可以共享remote cache。
强大的缓存系统,是nx最核心的特性
【更多】
nx还有很多有意思的特性,
感兴趣的小伙伴,可以自己探索,
官网: https://nx.dev/
nx-cloud: https://nx.dev/nx-cloud/intro/what-is-nx-cloud
packages:https://nx.dev/packages