代码生成工具Schematics详解(1)

为什么要学习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
  1. 创建Schematics项目
    使用下面的命令新建一个 scheamtics 项目
$ schematics schematic --name my-schematics
$ cd my-schematics
$ npm install
  1. 编译和运行
    以上命令创建了一个简单的命令行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)
  1. 代码讲解
    从上面的执行结果可以看出: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的源代码
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容