iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 9
1
Modern Web

高效 Coding 術:Angular Schematics 實戰三十天系列 第 9

[高效 Coding 術:Angular Schematics 實戰三十天] Day08 - 增加對 Angular 專案的支援

玩了幾天的 Schematics ,不曉得大家有沒有發現一個問題:為什麼當我們在 Angular 專案裡使用 ng generate 的指令時,Angular CLI 會知道我們要將產生出來的檔案放在哪裡?而且在一個 Angular 專案中,可能會有多個 project ,所以 ng generate 才有一個 --project 參數,用來指定要在哪個 project 裡新增檔案。

所以如果我們要在現有的 Angular 專案中使用自己客製的 Schematics ,就勢必要增加關於這個部分的支援。

新增參數

事不宜遲,趕緊打開 schema.json 來新增 project 屬性:

{
  "//": "略",
  "properties": {
    "//": "略",
    "project": {
      "type": "string",
      "description": "Generate in specific Angular CLI workspace project"
    }
  },
  "//": "略"
}

定義介面

而隨著程式複雜度的提升與參數的增加,為了讓我們自己開發時可以更輕鬆且降低出錯的機率,我們可以在 /hello 資料夾裡新增一個 schema.d.ts 的檔案,把該 Schematic 會有哪些參數與各參數的資料型別都定義清楚:

export interface HelloSchema {
  name: string;
  project?: string;
}

既然都已經將參數的介面定義清楚了,後續只要我們有新增參數,就必須要維護這個介面檔,令它與 schema.json 檔裡的參數定義一致。

但同樣的東西要維護兩次實在是太麻煩也容易出錯,所以筆者要介紹一個非常好用的工具給大家,那就是 dtsgeneratordtsgenerator 可以根據我們的 schema.json 自動產生對應的 schema.d.ts ,簡直是 Schematics 神器!!

用法非常簡單,只要安裝好 dtsgenerator 之後再輸入以下指令:

dtsgen src/hello/schema.json -o src/hello/schema.d.ts

或者可以像筆者一樣,不用事先安裝,只要將指令記錄在 package.jsonscripts 裡,像是:

{
  "//": "略",
  "scripts": {
    "//": "略",
    "gen:schema": "npx -p dtsgenerator dtsgen src/hello-world/schema.json -o src/hello-world/schema.d.ts"
  },
  "//": "略"
}

然後要用的時候直接使用以下指令即可:

npm run gen:schema

小提醒: dtsgenerator 所產出的 schema.d.ts ,裡面介面名稱是根據 schema.jsonid 解析出來的,使用時稍微留意一下即可。

調整程式碼

整合的最後一步則是要修改程式碼,以解析出正確的檔案名稱與路徑,並將其產生出來的程式碼與檔案放到正確的位置:

import { 
  Rule, 
  SchematicContext, 
  Tree, 
  url, 
  apply, 
  template, 
  mergeWith, 
  SchematicsException, 
  move 
} from '@angular-devkit/schematics';
import { strings } from '@angular-devkit/core';

// 需要先在終端機中輸入 'npm install @schematics/angular -S'
import { parseName } from '@schematics/angular/utility/parse-name';
import { buildDefaultPath } from '@schematics/angular/utility/project';

export function helloWorld(_options: HelloWorldSchema): Rule {
  return (_tree: Tree, _context: SchematicContext) => {
    
    // 讀取 angular.json ,如果沒有這個檔案表示該專案不是 Angular 專案
    const workspaceConfigBuffer = _tree.read('angular.json');
    if ( !workspaceConfigBuffer ) {
      throw new SchematicsException('Not an Angular CLI workspace');
    }

    // 解析出專案的正確路徑與檔名
    const workspaceConfig = JSON.parse(workspaceConfigBuffer.toString());
    const projectName = _options.project || workspaceConfig.defaultProject;
    const project = workspaceConfig.projects[projectName];
    const defaultProjectPath = buildDefaultPath(project);
    const parsePath = parseName(defaultProjectPath, _options.name);
    const { name, path } = parsePath;
    
    const sourceTemplates = url('./files');
    const sourceParametrizedTemplates = apply(sourceTemplates, [
      template({
        ..._options,
        ...strings,
        name // 蓋過原本的 _options.name,避免使用錯誤的檔名
      }),
      move(path) // 將產生出來的檔案移到正確的目錄下
    ]);

    return mergeWith(sourceParametrizedTemplates);
  };
}

在 Angular 專案中使用

存檔並編譯完之後,就可以打開自己現有或新建的專案,輸入以下指令:

ng generate {自己客製的_Schematics_的專案路徑}/src/collection.json:hello-world 路徑/檔案名稱

例如像是:

ng generate ../hello-word/src/collection.json:hello-world feature/leo-chen

結果:

Imgur

本日結語

今天的原始碼在這:https://github.com/leochen0818/angular-schematics-30days-challenge/tree/day08

希望大家看了今天的文章之後會更想要試著自己寫寫看,不過要想寫出更好的 Schematics ,就絕對必須要學會如何寫 Schematics 的測試,因此也希望大家都能開始試著學寫測試並且逐漸習慣去寫測試。

明天又是撰寫測試的一天,敬請期待。

參考資料


上一篇
[高效 Coding 術:Angular Schematics 實戰三十天] Day07 - 如何測試使用範本的 Schematic
下一篇
[高效 Coding 術:Angular Schematics 實戰三十天] Day09 - 撰寫支援 Angular 專案的 Schematics 的測試程式
系列文
高效 Coding 術:Angular Schematics 實戰三十天32

尚未有邦友留言

立即登入留言