前言
玩过Angular的同学都知道Angular作为一个Framework,拥有一套完备的生态,还集成了强大的CLI。而React则仅仅是一个轻量级的Library,官方社区只定义了一套组件的周期规则,而周边社区可以基于此规则实现自己的组件,React并不会提供给你一套开箱即用的方案,而需要自己在第三方市场挑选满意的组件形成“全家桶”,这也是React社区活跃的原因之一。
最近工作中在考虑使用monorepo对项目进行管理,发现了一套dev toolkit叫做Nx,Nx使用monorepo的方式对项目进行管理,其核心开发者vsavkin同时也是Angular项目的早期核心成员之一,他把Angular CLI这套东西拿到Nx,使其不仅可以支持Angular项目的开发,现在还支持React项目。
Nx支持开发自己的plugin,一个plugin包括schematics和builders(这两个概念也分别来自Angular的schematics以及cli-builders),schematics按字面意思理解就是“纲要”的意思,也就是可以基于一些模板自动化生成所需的文件;而builders就是可以自定义构建流程。
今天要讲的就是如何开发一个属于自己的Nx plugin (包含schematics),我会使用它来自动化创建一个页面组件,同时更新router配置,自动将其加入react router的config。
关于Monorepo
这篇文章不会详细介绍什么是monorepo,mono有“单个”的意思,也就是单个仓库(所有项目放在一个仓库下管理),对应的就是polyrepo,也就是正常一个项目一个仓库。如下图所示:
更多关于monorepo的简介,可以阅读以下文章:
- Advantages of monorepos
- How to develop React apps like Facebook, Microsoft, and Google
- Misconceptions about Monorepos: Monorepo != Monolith
关于Nx plugin
先贴一张脑图,一个一个讲解schematic的相关概念:
前面提到Nx plugin包括了builder(自动化构建)和schematic(自动化项目代码的增删改查)。一个成型的Nx plugin可以使用Nx内置命令执行。
对于文章要介绍的schematics,可以认为它是自动化代码生成脚本,甚至可以作为脚手架生成整个项目结构。
Schematics要实现的目标
Schematics的出现优化了开发者的体验,提升了效率,主要体现在以下几个方面:
-
同步式的开发体验,无需知道内部的异步流程
Schematics的开发“感觉”上是同步的,也就是说每个操作输入都是同步的,但是输出则可能是异步的,不过开发者可以不用关注这个,直到上一个操作的结果完成前,下一个操作都不会执行。
-
开发好的schematics具有高扩展性和高重用性
一个schematic由很多操作步骤组成,只要“步骤”划分合理,扩展只需要往里面新增步骤即可,或者删除原来的步骤。同时,一个完整的schematic也可以看做是一个大步骤,作为另一个schematic的前置或后置步骤,例如要开发一个生成Application的schematic,就可以复用原来的生成Component的schematic,作为其步骤之一。
-
schematic是原子操作
传统的一些脚本,当其中一个步骤发生错误,由于之前步骤的更改已经应用到文件系统上,会造成许多“副作用”,需要我们手动FIX。但是schematic对于每项操作都是记录在运行内存中,当其中一项步骤确认无误后,也只会更新其内部创建的一个虚拟文件系统,只有当所有步骤确认无误后,才会一次性更新文件系统,而当其中之一有误时,会撤销之前所做的所有更改,对文件系统不会有“副作用”。
接下来我们了解下和schematic有关的概念。
Schematics的相关概念
在了解相关概念前,先看看Nx生成的初始plugin目录:
your-plugin
|--.eslintrc
|--builders.json
|--collection.json
|--jest.config.js
|--package.json
|--tsconfig.json
|--tsconfig.lib.json
|--tsconfig.spec.json
|--README.md
|--src
|--builders
|--schematics
|--your-schema
|--your-schema.ts
|--your-schema.spec.ts
|--schema.json
|--schema.d.ts
Collection
Collection包含了一组Schematics,定义在plugin主目录下的collection.json
:
{
"$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json",
"name": "your-plugin",
"version": "0.0.1",
"schematics": {
"your-schema": {
"factory": "./src/schematics/your-schema/your-schema",
"schema": "./src/schematics/your-schema/schema.json",
"aliases": ["schema1"],
"description": "Create foo"
}
}
}
上面的json文件使用@angular-devkit/schematics下的collection schema来校验格式,其中最重要的是schematics
字段,在这里面定义所有自己写的schematics,比如这里定义了一个叫做"your-schema"的schematic,每个schematic下需要声明一个rule factory(关于rule
之后介绍),该factory指向一个文件中的默认导出函数,如果不使用默认导出,还可以使用your-schema#foo
的格式指定当前文件中导出的foo
函数。
aliases
声明了当前schematic的别名,除了使用your-schema
的名字执行指令外,还可以使用schema1
。description
表示一段可选的描述内容。
schema
定义了当前schematic的schema json定义,nx执行该schematic指令时可以读取里面设置的默认选项,进行终端交互提示等等,下面是一份schema.json
:
{
"$schema": "http://json-schema.org/schema",
"id": "your-schema",
"title": "Create foo",
"examples": [
{
"command": "g your-schema --project=my-app my-foo",
"description": "Generate foo in apps/my-app/src/my-foo"
}
],
"type": "object",
"properties": {
"project