27
16

More than 5 years have passed since last update.

hygenで簡単につくる対話式コードジェネレータCLI

Posted at

hygen

Github: https://github.com/jondot/hygen
Docs: http://www.hygen.io/quick-start/

hygen is the simple, fast, and scalable code generator that lives in your project.

hygenはnode.jsベースに、とっても簡単にテンプレートに沿ったファイルの生成CLIをつくることができます。

今回ReactによるUIコンポーネントを新しく作るときに、決まった構造のファイル群が毎回必要なので活用してみました。

npm i hygen -D

生成したいファイル

例えば Button コンポーネントを作成する場合。今回は例としてこんな感じのファイルたちを用意したいです。

/Button
├── Button.stories.tsx
├── Button.test.tsx
├── Button.tsx
├── README.md
├── index.tsx
├── style.css
└── style.css.d.ts

生成テンプレートを用意

生成したい構造に合わせて、次のようなファイルを用意しました。(※ prompt.js は後述)
ちなみにinitコマンドも用意されてます。

./hygen
└── component
    └── add
        ├── README.md.t
        ├── component.stories.tsx.t
        ├── component.test.tsx.t
        ├── component.tsx.t
        ├── index.tsx.t
        ├── prompt.js
        ├── style.css.d.ts.t
        └── style.css.t

拡張子を含めた出力したいファイル名.t でファイルを用意します。

hygenではこのテンプレートファイルのディレクトリ構造が、そのまま実行時のコマンド構造に対応しています。そのため実行するためにnpm scriptを同時に準備できます。

package.json
"scripts": {
  "add": "hygen component add"
},
$ npm run add

そして同時に設定ファイルも用意します。
これは単純にテンプレートを置く場所を指定してるだけです。今回./hygenに作ってみたのでこうしてます。

./.hygen.js
module.exports = {
  templates: `${__dirname}/hygen`,
};

テンプレートを記述

中身はfrontmatter + ejsで書くことになり、CLIから引数を取ってテンプレート内に適用出来ます。
次の例で言うと、<%= name %> にコンポーネント名を出力することが出来ます。

index.tsx.t
---
to: src/<%= name %>/index.tsx
unless_exists: true
---
export * from './<%= name %>';
component.tsx.t
---
to: src/<%= name %>/<%= name %>.tsx
unless_exists: true
---
import * as React from 'react';

interface I<%= name %>Props {
  text?: string;
}

const <%= name %>: React.FC<I<%= name %>Props> = props => {
  const { text } = props;
  return <div>{text}</div>;
};

export { <%= name %>, I<%= name %>Props };

この中身はかなり便利に書くことができるので、是非公式DocsのTemplatesを参照してみてください。

CLIに対話式インターフェースを追加

あとはCLI実行時にコンポーネント名を入力できるようにするだけで完成です。
用意したaddフォルダの中に prompt.js を作成します。

prompt.js
module.exports = [
  {
    message: 'What is the component name?',
    name: 'name',
    type: 'input',
    validate: answer => {
      if (answer !== '') {
        return true;
      }
    },
  },
];

対話式にしたい内容に沿ったobjectを、質問の個数分の配列にして記述しておくだけです。

今回は name という名前の変数を入力したいので、こうなりました。空欄で実行できてしまうと変なファイルが出来てしまうので、validateも適当に用意してます。

実行するとこうなります。

$ npm run add

> hygen component add

? What is the component name? ›

コンポーネント名を入れると一気にファイルが出力されます。

✔ What is the component name? · Button

Loaded templates: hygen
       added: src/Button/Button.stories.tsx
       added: src/Button/Button.test.tsx
       added: src/Button/Button.tsx
       added: src/Button/index.tsx
       added: src/Button/README.md
       added: src/Button/style.css.d.ts
       added: src/Button/style.css

空欄でEnterを押すとvalidateがきいて怒られます。

? What is the component name? ›

❯ Invalid input

ちなみにファイルが被ってると(つまり既に作成済みの名前を誤って入力した時)、気を利かせてスキップしてくれます。

skipped: src/Button/Button.stories.tsx
skipped: src/Button/Button.test.tsx
skipped: src/Button/Button.tsx
skipped: src/Button/index.tsx
skipped: src/Button/README.md
skipped: src/Button/style.css.d.ts
skipped: src/Button/style.css

今回はやりたいことが超単純だったのでこれだけですが、シンプルなわりには柔軟に作れるので他にもいろいろなことに活用できそうな気がします。

公式には Redux, React Native, Express がユースケースとして紹介されてます。

おわり

27
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
16