Angular CLI 1.4 版以後,樣板的產生器就改使用 @angular-devkit/schematics ,而在 10 月初,Nrwl.io 也推出 nx 版的 schematics 樣版集合,所以什麼是 schematics ,我們可以利用他來做什麼樣的事情呢?
簡介
@angular/schematics 是包含在 @angular/devkit 內,他是一個定義樣板的架構,類似 ember cli 內的 blueprint,利用 json 設定檔及預設的檔案範本,可以利用指令產生出我們所設定的檔案內容
schematics 有分兩個部分,@angular-devkit/schematics 屬於 runner,而 @schematics/angular 屬於範本集合 (Angular CLI 所使用的範本集合)。

架構
collection.json
如之前所說,schematics 是一個集合,所有的定義項目都可以在 collection.json 內看到,也可以說是集合的進入點
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | {"schematics": {
 "application": {
 "factory": "./application",
 "schema": "./application/schema.json",
 "description": "Create an Angular application."
 },
 "class": {
 "aliases": [ "cl" ],
 "factory": "./class",
 "description": "Create a class.",
 "schema": "./class/schema.json"
 },
 "component": {
 "aliases": [ "c" ],
 "factory": "./component",
 "description": "Create an Angular component.",
 "schema": "./component/schema.json"
 },
 ...
 }
 }
 
 | 
collection.json 檔案的第一層是 schemtaics,在這一個節點下,就是各指令的定義檔,例如 application、class 或 component 等,都會對應一個資料夾
以 class 為例
| 12
 3
 4
 5
 6
 
 | "class": {"aliases": [ "cl" ],
 "factory": "./class",
 "description": "Create a class.",
 "schema": "./class/schema.json"
 },
 
 | 
- aliases: 指令的縮寫,例如 ng generate class也可以使用縮寫代替ng generate cl
- factory: 所有的邏輯存放的所在地
- description: 資訊描述
- schema: 參數設定檔
schema.json
進入 class 資料夾,並開啟 schema.json 檔案,內容如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 
 | {"$schema": "http://json-schema.org/schema",
 "id": "SchematicsAngularClass",
 "title": "Angular Class Options Schema",
 "type": "object",
 "properties": {
 "name": {
 "type": "string"
 },
 "appRoot": {
 "type": "string"
 },
 "path": {
 "type": "string",
 "default": "app"
 },
 "sourceDir": {
 "type": "string",
 "default": "src"
 },
 "spec": {
 "type": "boolean",
 "description": "Specifies if a spec file is generated.",
 "default": false
 },
 "type": {
 "type": "string",
 "description": "Specifies the type of class.",
 "default": ""
 }
 },
 "required": [
 "name"
 ]
 }
 
 
 | 
在 properties 下可以定義所有的變數的型別、描述及預設值,requried 設定必須輸入的欄位
index.ts
index.ts 檔案會是 factory 所指定的資料夾下首先會被執行的檔案
| 1
 | import { Schema as ClassOptions } from './schema';
 | 
Schema 是針對 schema.json 的 properties 區塊定義項目的介面檔,主要功能是提供 index.ts 內使用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | export interface Schema {name: string;
 appRoot?: string;
 path?: string;
 sourceDir?: string;
 
 
 
 spec?: boolean;
 
 
 
 type?: string;
 }
 
 | 
基本架構
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | export default function (options: ClassOptions): Rule {
 options.type = !!options.type ? `.${options.type}` : '';
 options.path = options.path ? normalize(options.path) : options.path;
 const sourceDir = options.sourceDir;
 if (!sourceDir) {
 throw new SchematicsException(`sourceDir option is required.`);
 }
 
 const templateSource = apply(url('./files'), [
 options.spec ? noop() : filter(path => !path.endsWith('.spec.ts')),
 
 template({
 ...stringUtils,
 ...options as object,
 }),
 
 move(sourceDir),
 ]);
 
 
 return chain([
 branchAndMerge(chain([
 mergeWith(templateSource),
 ])),
 ]);
 }
 
 | 
files  資料夾
會看到 __name@dasherize____type__.ts 的檔案,這裡看到的 __name (兩個底線) 會對應到 schema.json  properties 所定義的變數名稱 name ,同樣的 __type 也相對應於 type 的參數,同樣的規則,是用於資料夾名稱

@dasherize 是一個函式,接受後面的引數並處理後回結果,這段的效果等同於 dasherize(type)
但實際的傳入的值是透過 index.ts 內的 template 傳入的參數集合 (如下註解)
| 12
 3
 4
 
 | template({...stringUtils,
 ...options as object,
 }),
 
 | 
在該檔案內的內容,可以看到 name ,同樣的代表的 name 變數
| 12
 
 | export class <%= classify(name) %> {}
 
 | 
classify 函式的效果是將 someFunction 主換成 SomeFunction
自訂 schematics 集合
目前最快的方式,是直接複製 @schematics/angular 來改,但其實 @angular/dev-kit 有提供命令的方式來建立~~(還在研究中,等研究出來後在寫另外一篇文章分享)~~ 請參考下一段
| 12
 3
 
 | $ cd ~/n/lib/node_modules/@angular/cli/node_modules/ (angular cli 全域的安裝位置)$ mkdir -p @custom/myangular
 $ cp -R @schematics/angular/* @custom/myangular/
 
 | 
上述的指令,等同於直接在全域的 Angular CLI 下建立一個新的 schematics 範本集合
當在執行 ng new 時,可以加上 --collection 來設定要使用的 schematics
| 1
 | ng new --collection=@custom/myangular myapp
 | 
創建 schematic
@angular/dev-kit 有提供建立的指令,在這之前需先安裝三個工具
| 12
 3
 
 | npm i -g @angular-devkit/schematicsnpm i -g @schematics/schematics
 npm i -g rxjs
 
 | 
安裝完成後,即可透過 schematics 的指令建立範本集,預設有兩種範本 blank 和 schematic 。建立指令
| 12
 3
 4
 
 | // schematic templateschematics @schematics/schematics:schematic --name <<collection name>>
 // blank template
 schematics @schematics/schematics:blank --name <<collection name>>
 
 | 
建立後的專案結構

之後就可按上面所介紹的方式建立自己的範本,當然也可參考其他人的 schematics ,例如 nx 或是 ngrx,我相信之後會有更多各式各樣的範本出來
參考資料