16
Help us understand the problem. What are the problem?

posted at

updated at

Schematicsを作ってみよう

この記事は Angular Advent Calendar 2018 の 3 日目の記事です。

みなさん今日もAngular CLI使っていますか?

Angular CLIは、ビルド周りや開発サーバの面倒を見てくれるだけでなく、ng generateng addといったコマンドを実行するだけで必要なファイルの生成はもちろん、モジュールの追加や設定の変更も行ってくれるので非常に便利ですよね。

これらの処理はAngular Schematicsによって定義されており、自分で作ることもできます。また、既存のSchematicsを拡張することも可能です。

どうでしょう?試してみたくありませんか?
それでは、早速やってみましょう!

はじめよう

まずはschematics-cliをインストールしましょう。

$ npm install -g @angular-devkit/schematics-cli

新規プロジェクトを作成します。

$ schematics blank my-schematics
$ cd my-schematics

blankの他にschematicを指定すると実装サンプル付きのプロジェクトが作られます

生成されたファイルを見てみましょう。

package.json
{
  "name": "my-schematics",
  "schematics": "./src/collection.json",
  "dependencies": {
  }
}

package.jsonschematicsに指定されているcollection.jsonに実行対象となるSchematicsが入っています。

src/collection.json
{
  "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
  "schematics": {
    "my-schematics": {
      "description": "A blank schematic.",
      "factory": "./my-schematics/index#mySchematics"
    }
  }
}

my-schematicsが呼ばれたときに実行されるメソッドが./my-schematics/index.tsmySchematicsという事がわかります。

$schemaはIDEでの補完等に使われるものなので必須ではありません。

Schematicsの中身はRules(= Treeを返す関数)を返す関数です。Treeはファイルシステムやファイルの変更が含まれています。

src/my-schematics/index.ts
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';

export function mySchematics(_options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    return tree;
  };
}

作ってみよう

基本となるのはTreeの操作です。

src/my-schematics/index.ts
export function mySchematics(_options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    tree.create(_options.path + '/hi', 'Hello world!');
    return tree;
  };
}

ビルドして実行すると、Schematicsの出力を見ることができます。

$ npm run build
$ schematics .:my-schematics --path=./
CREATE /hi (12 bytes)

デフォルトではプレビューだけですが、--dry-run=falseを指定することで実際にファイルが生成されるようになります。

$ schematics .:my-schematics --path=./ --dry-run=false
CREATE /hi (12 bytes)
$ cat hi
Hello world!

.:my-schematicsの部分は:より前がcollection.jsonへのパス、後がcollection.jsonにおける定義名となります。そのため、他のディレクトリで呼び出す場合はschematics ./path/to/collection.json:my-schematicsのようになります。

ログ出力

進捗やエラー表示などにはloggerを用います。用途に応じて、

  • debug
  • info
  • warn
  • error

などがあります。

export function mySchematics(_options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    _context.logger.info('🎉 Hello, schematics!');
    return tree;
  };
}

テンプレート

コンポーネント等に使うファイル一式を生成する際はテンプレートを利用しましょう。

src/my-schematics/index.ts
import { strings } from '@angular-devkit/core';
import {
  Rule,
  SchematicContext,
  applyTemplates,
  mergeWith,
  apply,
  url,
} from '@angular-devkit/schematics';

export function mySchematics(_options: any): Rule {
  return (_, _context: SchematicContext) => {
    return mergeWith(apply(url('./files'), [
      applyTemplates({
        ...strings,
        name: _options.name,
      }),
    ]));
  };
}

url()でテンプレートのパスを指定し、applyTemplates()を実行しましょう。

ファイル名は__name__のようにアンダースコアで囲まれた部分が置換されます。

src/my-schematics/files/__name__.component.css.template
/* styles */

テンプレートはEJSのような構文で、 <% %>で囲んだ部分に条件式を書いたり、<%= %>で囲んだ部分に文字列を代入することができます。

src/my-schematics/files/__name__.component.ts.template
<% if (name) { %>
  Hello <%= name %>, I'm a schematic.
<% } else { %>
  Why don't you give me your name with --name?
<% } %>

@angular-devkit/coreには、セレクタ→クラス名の変換(classify)やケバブケースへの変換(dasherize)といった処理のための便利なユーティリティもあるので是非活用しましょう。

src/my-schematics/files/__name__.component.ts.template
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-<%= name %>',
  templateUrl: './<%= name %>.component.html',
  styleUrls: ['./<%= name %>.component.css'] }
})
export class <%= classify(name) %>Component implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

それでは、実行してみましょう。

$ schematics .:my-schematics --name=sample --dry-run=false
CREATE /sample.component.css (12 bytes)
CREATE /sample.component.html (35 bytes)
CREATE /sample.component.ts (270 bytes)

コンポーネントが生成されました :tada:

公開する

いい感じのSchematicsができたら是非公開してみましょう!

$ npm run build
$ npm publish

おわりに

今回は単純なサンプルの紹介でしたが、ng addなど他のSchematicsの実装例は以下のリポジトリを参考にすると良いと思います。

https://github.com/angular/material2/tree/master/src/lib/schematics
https://github.com/ng-bootstrap/schematics
https://github.com/ionic-team/ionic/tree/master/angular/src/schematics

Onsen UIのSchematicsも開発中です!(宣伝)
https://github.com/OnsenUI/OnsenUI/pull/2591

ちなみにschematics-cliのヘルプは↓で表示できます。

$ schematics --help

利用可能なAPIについてはGitHubのドキュメントを読みましょう。
https://github.com/angular/angular-cli/tree/master/packages/angular_devkit/schematics

明日は@MasanobuAkibaさんです!

参考文献

https://medium.com/@michael.warneke/merging-custom-angular-schematics-c14a303f63b6
https://github.com/angular/angular-cli/tree/master/packages/schematics/angular
https://blog.angular.io/schematics-an-introduction-dc1dfbc2a2b2

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
16
Help us understand the problem. What are the problem?