hygenでフロントエンド開発を楽にする

Next.jsで開発中によく思うんですが、毎度コンポーネントを新しく作るたびに`.test.tsx`と`.stories.tsx`を作るのとても面倒ですよね。
css moduleを採用していると、さらにそこに追加で`.module.css`をドンです。もう手間でしかありません。

これまで、この辺りので楽をするためにはvscodeのユーザースニペットを活用して居たんですが、それよりももっと便利なものを最近知ったので紹介します。それが`hygen`です。

## hygen とはなんぞや

hygenとは、ざっくり言うとテンプレートエンジンです。
事前に作成しておいたテンプレートとなるファイルと、生成時に入力した文字列を用いて任意のファイルを作成します。

https://www.hygen.io

具体的にどんなことができるかと言うとこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532032/b3e21f6e-0183-a69b-c850-b3ede4ea5c37.png)

任意の文字列入力だけではなく、選択肢の中から選ばせることもできます。
例えば、上記のatomsは以下のように選択肢の中から選択させています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532032/f31af939-ed32-5356-4ccc-9f3f82fa9bfd.png)

以前はこの辺りの操作をするために、該当のディレクトリにcdしてtouchしてcodeで開いてスニペット開いてなんてやっていたので、それらがコマンド一発でできるようになり非常に便利になりました。

では、実際に手を動かしてhygenを使えるようにしていきます。

## hygenを動かしてみる

環境

node: v18.12.1

### インストール

npm等のnodejsパッケージマネージャかhomebrewからインストールできます。
今回記事はmacで書いているのでhomebrewからインストールできるのですが、npmから落とせるならそちらが良いので今回は`pnpm`を使用します。
npmでも落とせますがpnpmを使います。pnpmはいいぞ。

```
pnpm i -D hygen
```

インストールできたらinitの実行
実行すると、`_template`ディレクトリが作成されます。
今後、テンプレートとなるファイルなどはこちらに配置します。

```
pnpm hygen init self
```

作成されたディレクトリの中身はこんな感じです。

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

### コマンドを作る

それでは次に、先に紹介したコマンド`hygen component new` を作っていきましょう。
hygenは、`hygen 任意の文字列 new` といった形で自由にコマンドを設定できます。

コマンドを生成するためには、generatorコマンドを使用すると楽です。
以下のコマンドを実行して、hygen componentコマンドの下地を作ります。


```
pnpm hygen generator new component
```

実行後、`_template`の中身は以下のように変わります。


```
_templates/
├── component
│   └── new
│       └── hello.ejs.t
├── generator
│   ├── help
│   │   └── index.ejs.t
│   ├── new
│   │   └── hello.ejs.t
│   └── with-prompt
│       ├── hello.ejs.t
│       └── prompt.ejs.t
└── init
    └── repo
        └── new-repo.ejs.t
```

先と比較すると、`_template/component/new/hello.ejs.t`が増えていることがわかります。
それでは、試しに作成した`hygen component`コマンドを実行してみましょう。

```
pnpm hygen component new
```

実行すると、以下のファイルが作成されました。

```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)

```
コードブロックが壊れるので、8行目に\s一個入れましたがそれ以外は生成物そのままのコードです。
`hygen component new`コマンドから、無事にファイルが生成されました。

これをみた上で、一度`_template/component/new`にある`hello.ejs.t`を見てみたいと思います。

```_templates/component/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)
```

このファイル、何か見覚えがあるような気がしますね。

さらに、今度は`_template/generator/new`にある`hello.ejs.t`を見てみましょう。
ちなみに、上記のファイルを生成するために使用したコマンドは、`hygen generator new`です。

```_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)
```

はいもうわかりましたね。**hygenはこういったコマンドです**。
わからなかったら[コマンドを作る](#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%9C%E3%82%8B)まで戻って再度読み直してください。わからなかった場合は、コードを一度一切読まないで説明文だけ読んでみるとわかりやすいと思います。

### ユーザーに入力をさせる 

ただ、これだけではちょっと便利だけど使い道に困るコマンド以上に価値はないです。
ここに、任意の文字列を入力させて生成場所や生成内容を操作していきたいと思います。

一度以下のコマンドを実行して`hygen component`コマンドを削除して、新規に`hygen component`コマンドを以下のコマンドで作り直しましょう。

```
rm -rf _template/component
pnpm hygen generator with-prompt component
```

なぜ new ではなく with-prompt を使用したのかというと、with-promptで生成される`prompt.js`が欲しかったからです。これがある以外には特にnewと差はありません。
ではこれがあるとどう異なるのか、試しにhygen componentを実行してみましょう。

```
pnpm hygen component with-prompt
```

すると、先とは違って今度は`What's your message?`と文字列の入力を求められたかと思います。

これで文字列入力が可能になりました。
なぜできるようになったかと言うと、hygenはコマンド実行時に対象のディレクトリ内に`prompt.js`があるとその内容に応じて設問を設けてくれるためです。
では、`prompt.js`の中身を見てみましょう。

```_template/component/with-prompt/prompt.js
// see types of prompts:
// https://github.com/enquirer/enquirer/tree/master/examples
//
module.exports = [
  {
    type: 'input',
    name: 'message',
    message: "What's your message?"
  }
]
```

フロント書いてる人ならなんとなく察したと思いますので、試しにmessageの中身を"What's your message?"から`What's your name?`に変えて実行してみたいと思います。

```
$ rm -rf app/
$ pnpm hygen component with-prompt
✔ What's your name? · ikea_shark

Loaded templates: _templates
       added: app/hello.js
```

設問が変わりましたね。
こうして質問内容はいくらでも変更ができます。

では、今度は入力させた文字列を使用して生成内容に変化を加えていきましょう。
hello.ejs.tの内容を以下のように書き換えてください。

```
---
to: app/hello.js
---
const hello = "I'm <%= message %>."

console.log(hello)
```

phpとかでテンプレートエンジン触ってた人には見覚えのある形式だと思います。

ついでに、with-promptと入力するの面倒なのでnewとかに変更しておきましょう。（横着したいだけなのでしなくてもいいです）

```bash
mv _templates/component/with-prompt _templates/component/new
```

それでは実行してみます。

```
$ rm -rf app/
$ pnpm hygen component new
✔ What's your name? · ikea_shark

Loaded templates: _templates
       added: app/hello.js
```

```app/hello.js
const hello = "I'm ikea_shark."

console.log(hello)
```

このように、入力値`ikea_shark`を生成するファイルに生かすことができました。
この`<%= message %>`の`message`ですが、この値はprompt.jsの連想配列のうち`name`のvalueが該当します。なので別の文字列を使用したい場合はこの値を任意のものに変えてあげてください。

なお、`type`の値を他の値に変えることで、質問形式を変更できます。
そのあたりドキュメントに書かれて居ないので察する必要があるのですが、例えば`select`にして連想配列に`choices`をstring[]のvalueを持つ形で追加してみると、こんな形になります。

```
$ pnpm hygen component new
? What's your name? … 
❯ foo
  bar
  baz
  ikea_shark
```

## 終わりに

今回は、prompt.jsの紹介までで終了しましたが、より柔軟な質問などを設けたい場合は`index.js`を追加することでできるようになります。最初に紹介した例で、入力値が`atom`なのに生成先のディレクトリ名が`01-atoms`なのは、この辺りを色々色々弄っている為です。
詳しくは、以下の公式ドキュメントを見てください。

https://www.hygen.io/docs/generators/#advanced-interactive-prompt

失礼ながら、色々不足がちなドキュメントではあるので、より知見を深めたい場合はissueを覗いてみるといいかもしれません。
ただ、多くの方が解決したい課題は`prompt.js`までで解決できると思うので、興味が向かなければ無理に見に行かなくても良いとは思います。

個人的に、hygenで嬉しいところはチーム開発時にテストファイルの記載やstorybookの記載を強制できるところだと思っています。テストはまだしも、空気感によってはstorybookの作成って忘れられることがある項目だと思うんですよね。
特に初めて導入した際などは、この辺の矯正は重要で効果的じゃないかな、という認識です。

今回はフロントで楽になるツールとして紹介しましたが、このhygenが生きる環境は必ずしもフロントエンドに限った話ではないと思いますので、是非色々なシーンで試してみてください。