为什么要学习Schematics?
schematics作为Angular-Devkit的一部分,用过Angular CLI的人肯定用过这个命令 :
ng g component my-component
此命令瞬间创建了一个名为my-component的组件。如果使用了module参数,还会自动添加到模块的声明中。这样写代码确实爽,生产力成倍提高。
如何自己创建一个Schematic?
1.安装Schematics CLI
npm install -g @angular-devkit/schematics-cli
- 创建Schematics项目
使用下面的命令新建一个 scheamtics 项目
$ schematics schematic --name my-schematics
$ cd my-schematics
$ npm install
- 编译和运行
以上命令创建了一个简单的命令行Schematics,编译后就可以运行和调试了,可以先执行以下命令,来测试下效果
$ npm run build # 编译 ts
$ npm link # link 当前项目
在你的Angular项目里执行以下命令:
$ ng new schematics-test # 新建一个 Angular 项目
$ cd my-angular-project # 进入项目目录
$ npm link my-schematics # 将上一步的 schematics link 进来
之后,执行以下命令:
$ ng g my-schematics:my-full-schematic --name hello
其中my-schematics是包名,my-full-schematic是Schematic的名称。由于我们link了包名,所以ng可以找到自定义的Schematic。
会发现项目中多了几个文件:
My Full Schematic: {"name":"hello","index":1}
My Other Schematic: {"option":true}
My Schematic: {"option":true}
CREATE hola (5 bytes)
CREATE allo (5 bytes)
CREATE test2 (35 bytes)
CREATE test1 (18 bytes)
- 代码讲解
从上面的执行结果可以看出:my-full-schematic调用了my-other-schematic,而my-other-schematic又调用了my-schematic。冒号后面的是参数。
- package.json
"schematics": "./src/collection.json"
指明了我们的Schematic的配置文件collection.json的位置
- collection.json
"schematics": {
"my-schematic": {
"description": "An example schematic",
"factory": "./my-schematic/index#mySchematic"
},
"my-other-schematic": {
"description": "A schematic that uses another schematics.",
"factory": "./my-other-schematic"
},
"my-full-schematic": {
"description": "A schematic using a source and a schema to validate options.",
"factory": "./my-full-schematic",
"schema": "./my-full-schematic/schema.json"
}
}
其中有三个Schematic,my-full-schematic有schema属性,指向一个配置文件schema.json,用来配置命令行的参数
- schema.json
{
"$schema": "http://json-schema.org/schema",
"id": "MyFullSchematicsSchema",
"title": "My Full Schematics Schema",
"type": "object",
"properties": {
"index": {
"type": "number",
"default": 1
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
properties属性定义了两个参数index和name,index有默认值1,name参数是必须的。还记得我们是怎么调用的吗?用户必须制定name参数,否则会有错误提示
$ ng g my-schematics:my-full-schematic --name hello
- my-full-schematic/index.ts
import {
Rule,
SchematicContext,
Tree,
apply,
chain,
mergeWith,
schematic,
template,
url,
} from '@angular-devkit/schematics';
export default function (options: any): Rule {
// chain是个特殊的rule,用来逐个调用rule传参
return chain([
(_tree: Tree, context: SchematicContext) => {
// 打印此Schematic的参数
context.logger.info('My Full Schematic: ' + JSON.stringify(options));
},
// 调用另一个schematic,并传参数
schematic('my-other-schematic', { option: true }),
// 合并树
mergeWith(apply(url('./files'), [
template({
INDEX: options.index,
name: options.name,
}),
])),
]);
}
导出匿名函数,函数返回Rule。Rule是对Tree的操作,用于转换树。而Tree是真实文件目录的树形结构,以当前目录为根目录。
chain是一个特殊的Rule,用于顺序执行Rule数组。
- Rule的定义
Rule = (tree: Tree, context: SchematicContext) => Tree | Observable<Tree> | Rule | Promise<void> | Promise<Rule> | void;
- schematic
用与调用其他schematic的Rule - mergeWith
合并树到输入树中。假想有一个文件树,base目录是当前目录,也就是你执行ng命令的目录,这个树作为输入树input tree,输入给schematic的工作流中。schematic就像一个转换器,可以在这棵树上创建文件,或者修改现有文件等。最后,Schematic根据此Tree生成代码到我们的项目中。mergeWith就是合并Source到这棵树中。 - Source
Source = (context: SchematicContext) => Tree | Observable<Tree>;
根据上下文,返回Tree。
- apply
应用Rule到Source后,返回新的Source - template
类似于模板引擎ejs - url
返回某一路径下的Source
这些函数都是angular-dev下的,可以直接使用。如深究,建议阅读Schematics的源代码
网友评论