Next.jsで開発中によく思うんですが、毎度コンポーネントを新しく作るたびに.test.tsx
と.stories.tsx
を作るのとても面倒ですよね。
css moduleを採用していると、さらにそこに追加で.module.css
をドンです。もう手間でしかありません。
これまで、この辺りので楽をするためにはvscodeのユーザースニペットを活用して居たんですが、それよりももっと便利なものを最近知ったので紹介します。それがhygen
です。
hygen とはなんぞや
hygenとは、ざっくり言うとテンプレートエンジンです。
事前に作成しておいたテンプレートとなるファイルと、生成時に入力した文字列を用いて任意のファイルを作成します。
具体的にどんなことができるかと言うとこんな感じです。
任意の文字列入力だけではなく、選択肢の中から選ばせることもできます。
例えば、上記のatomsは以下のように選択肢の中から選択させています。
以前はこの辺りの操作をするために、該当のディレクトリに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
実行すると、以下のファイルが作成されました。
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
を見てみたいと思います。
---
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
です。
---
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はこういったコマンドです。
わからなかったらコマンドを作るまで戻って再度読み直してください。わからなかった場合は、コードを一度一切読まないで説明文だけ読んでみるとわかりやすいと思います。
ユーザーに入力をさせる
ただ、これだけではちょっと便利だけど使い道に困るコマンド以上に価値はないです。
ここに、任意の文字列を入力させて生成場所や生成内容を操作していきたいと思います。
一度以下のコマンドを実行して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
の中身を見てみましょう。
// 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とかに変更しておきましょう。(横着したいだけなのでしなくてもいいです)
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
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
なのは、この辺りを色々色々弄っている為です。
詳しくは、以下の公式ドキュメントを見てください。
失礼ながら、色々不足がちなドキュメントではあるので、より知見を深めたい場合はissueを覗いてみるといいかもしれません。
ただ、多くの方が解決したい課題はprompt.js
までで解決できると思うので、興味が向かなければ無理に見に行かなくても良いとは思います。
個人的に、hygenで嬉しいところはチーム開発時にテストファイルの記載やstorybookの記載を強制できるところだと思っています。テストはまだしも、空気感によってはstorybookの作成って忘れられることがある項目だと思うんですよね。
特に初めて導入した際などは、この辺の矯正は重要で効果的じゃないかな、という認識です。
今回はフロントで楽になるツールとして紹介しましたが、このhygenが生きる環境は必ずしもフロントエンドに限った話ではないと思いますので、是非色々なシーンで試してみてください。