tyankatsu’s blog

カレーと炭酸が苦手なほうれん草好きマンの技術ブログとか

Hygenでファイル作成を簡単にする

Hygenとはコマンドラインからファイルを生成する事が可能なパッケージです。
バージョンは現在1.6.2です。

以下ざっくりとした特徴です。

  • ファイル生成の雛形となるテンプレートをejs形式で書く
  • 自分でオプションを足して、それをテンプレート内の値として使用できる
  • inquirerを内包しており、質問を自分でカスタマイズして対話的にファイルを作成することが可能

本記事ではHygenの使い方を紹介します。

著者の環境です。

  • node...10.13.0
  • npm...6.4.1
  • yarn...1.12.3
  • nodeバージョン管理...ndenv

基本的な使い方

インストールします。

yarn add hygen -D

最初に試すのであれば以下のコマンドでhygenが自動でテンプレートを生成してくれます。

yarn hygen init self

すると以下のフォルダが作成されます。

_templates
└── generator
    ├── help
    │   └── index.ejs.t
    ├── new
    │   └── hello.ejs.t
    └── with-prompt
        ├── hello.ejs.t
        └── prompt.ejs.t

これらはhygenのチュートリアル的なファイルたちです。
これらを使ってHygenの使い方を探っていきます。

ファイル構成

_template/generator/new/hello.ejs.t

---
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
---
---
to: app/hello.js
---
const hello = `
Hello!
This is your first hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
`

console.log(hello)

まず、このtファイルは2つのセクションに分けられています。

---
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
---
---
to: app/hello.js
---

ここはhead部分で、ファイルに関するメタ情報を記述する場所です。
yaml形式で記述します。
front-matterを使用しているようです。

const hello = `
Hello!
This is your first hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
`

console.log(hello)

次にbody部分はファイルの内容を記述します。
ejs形式で記述します。
ejsはテンプレートエンジンです。
書き方がわからない場合はこちらの記事を参照してください。
テンプレートエンジンEJSで使える便利な構文まとめ - Qiita

これらがhygenを使う場合のテンプレートファイルの基本になります。

generator new

yarn hygen generator new --name Card
_templates
├── Card
│   └── new
│       └── hello.ejs.t
└── generator
    ├── help
    │   └── index.ejs.t
    ├── new
    │   └── hello.ejs.t
    └── with-prompt
        ├── hello.ejs.t
        └── prompt.ejs.t

_template/Card/new/hello.ejs.t

---
to: app/hello.js
---
const hello = `
Hello!
This is your first hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
`

console.log(hello)

もう一度コマンドを実行します。

yarn hygen Card new
.
├── _templates
│   ├── Card
│   └── generator
└── app
    └── hello.js

app/hello.jsができました。

機能分解

まず先程のコマンドを分解すると、

hygen generator new

hygenを使ってgeneratorという名のジェネレータでnewアクションを使用しファイルを作成する。
という意味になります。
それぞれの用語はこちらを参照してください。
Templates | Hygen

次にオプションですが、

--name Card

これはnameにCardという値を入れる。
という意味です。 yargs-parserで実現しています。

_template/generator/new/hello.ejs.t

---
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
---
---
to: app/hello.js
---

一回目のコマンドでhello.ejs.tの上段のto:が消費され、
<%= name %>Cardが入ったことで、
_template/Card/new/hello.ejs.tが作成され、
二回目のコマンドで、
app/hello.jsが作成されました。

generator help

yarn hygen generator help

_templates/generator/help/index.ejs.t

---
message: |
  hygen {bold generator new} --name [NAME] --action [ACTION]
  hygen {bold generator with-prompt} --name [NAME] --action [ACTION]
---

機能分解

messageプロパティはコマンド上にメッセージを表示させるために使います。
toプロパティと違ってファイルが作成されることはありません。 |yamlで改行を意味します。
YAMLで改行する方法 - このブログは証明できない。

こう書くことも可能です。

---
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
message: |
  --nameには<%= name %>が入りました。
---
---
to: app/hello.js
---
const hello = `
Hello!
This is your first hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
`

console.log(hello)

これを実行するとコマンド上ではこう出力されます。

Loaded templates: _templates
       added: _templates/Card/new/hello.ejs.t
new:
--nameにはCardが入りました。

generator with-prompt

yarn hygen generator with-prompt --name hoge
_templates
├── generator
│   ├── help
│   │   └── index.ejs.t
│   ├── new
│   │   └── hello.ejs.t
│   └── with-prompt
│       ├── hello.ejs.t
│       └── prompt.ejs.t
└── hoge
    └── with-prompt
        ├── hello.ejs.t
        └── prompt.js

もう一度コマンドを実行します

yarn hygen hoge with-prompt
? What's your message?
...
...

inquirer.jsが実行されました。

機能分解

propmpt.jsを作成し、その中にmodule.exportsで配列にinquirerのフォーマットを書いていくと、inquirerが作動します。
いろいろ書式が存在し、文字入力を受け付けるinput、リストから一つ選択するlistなどがあります。
Inquirer.js こちらが参考になります。
Inquirer.js/packages/inquirer/examples

{
    type: 'input',
    name: 'message',
    message: "What's your message?"
}

namevalueと同じものを~~~~~.ejs.tの中に<%= <value> %>と書けばそこに入ります。 例えば以下のとおりです。

{
    type: 'input',
    name: 'dir',
    message: "ディレクトリ名は?"
},
{
    type: 'input',
    name: 'name',
    message: "ファイル名は?"
},
{
    type: 'input',
    name: 'type',
    message: "拡張子は?"
},
---
to: <%= dir %>/<%= name %>.<%= type %>
---
body...

promptを実行すると

? ディレクトリ名は? src
? ファイル名は? hoge
? 拡張子は? html

Loaded templates: _templates
       added: src/hoge.html
// src/hoge.html

body...

.hygen.js

configファイルです。

module.exports = {
  templates: `${__dirname}/_templates`,
  helpers: {
    img: name => `src/assets/img/${name}`
  }
}

templatesはHygenのテンプレートディレクトリの場所を示します。
上記の例だとhygenコマンドを実行するとプロジェクト直下の_templatesを見ます。 helpersオブジェクトにはejs.t内でhでアクセス可能です。
上記の例だと<%= h.img('test.svg ') %>と記述すると、src/assets/img/test.svgと出力されます。

実際に使ってみての感想

著者はVueを使っており、jestを使用してtestを書くことが多いのですが、 vueファイルを書いて同じ構造でtestファイルを作るのが面倒だと悩んでいました。

src/components/VIcon.vue を作ったら tests/unit/components/VIcon.spec.jsを作るのが面倒だという話です。

hygenを使用するとファイルの作成が簡単であり、初期値も入れられるのでとても効率的だと思います。
著者はまだstorybookを使用したことがないのですが、storyファイルを作るのも簡単だと思います。
自分のカスタマイズ次第でなんとでもできそうな可能性を秘めていると思うので、ぜひ皆さんにも使っていただきたいです。