Hygenでコンポーネントとstorybook作成を楽しよう

## はじめに
### 背景
web開発中、コンポーネントとstorybookを作成するのがめんどくさいなーと感じていました。
同じような記述部分が多すぎるんじゃ...

そんな悩みを解決するものはないかと探していると、**Hygenという神ツール**を見つけました。
汎用的なファイルのテンプレートを一回作れば、あとはコマンド一発で雛形が作れちゃうんです。

あまりに感動したのでHygenの使い方をまとめます。

### 開発環境
- m1 macOS 12.6
- yarn 1.22.19
- hygen 6.2.11
- (Next.js 13.11)
- (storybook 6.5.15)

## Hygenとは
テンプレートからファイルを生成することができるコードジェネレーターです。
公式サイトでは以下のように説明されています。
> The scalable code generator that saves you time.

ドキュメント：https://www.hygen.io/

## 0. 概要
今回作成するものの説明です。

ルート直下で、`yarn hygen generator component`と叩くと、
```
? What is the name of component? › 
```
コンポーネント名を聞かれるので、`InputText`と入力。

結果、`src/components/`配下に`InputText`というコンポーネントファイルとstorybookファイルが格納されたディレクトリが生成される。
```
InputText/
├ InputText.tsx
└ InputText.stories.tsx
```

素晴らしいですね。
早速作っていきましょう。

## 1. インストール
以下のコマンドを実行します
```
yarn add hygen
```
npm, npxもサポートされています。詳しくは[公式](https://www.hygen.io/docs/quick-start)を参考にしてください。

## 2. テンプレート作成

### コマンド設定ファイル作成

ルート直下に`_templates/generators/components/`を作成し、その中に書いていきます。

`prompt.js`を作成し、コマンド実行時にコンポーネント名を指定するようにします。

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

### テンプレートファイル作成
こちらも`_templates/generators/components/`配下に作成します。

まずコンポーネントのテンプレートファイルを以下のように作成します。
```components.tsx.ejs.t
---
to: src/components/parts/<%= name %>/<%= name %>.tsx
---

import React from 'react';

interface <%= name %>Props {}

export const <%= name %>: React.FC<<%= name %>Props> = (props) => {
  const {} = props;

  return (
    <div>hello component!</div>
  );
};
```
作成の注意点
- ファイル名

    `components.tsx.ejs.t`と複雑なファイル名となっています。
    `(作成するファイルの拡張子).ejs.t`と考えればいいと思います。

- ファイル生成先を指定する

    初めのコードでファイル生成先を指定しています。
    `<%= name %>`には指定したコンポーネント名が入ります。

- 生成したいコードを続けて記述


storybookについても同様にテンプレートファイルを作りましょう。
```components.stories.tsx.ejs.t
---
to: src/components/parts/<%= name %>/<%= name %>.stories.tsx
---

import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { <%= name %> } from './<%= name %>';

export default {
    title: '<%= name %>',
    component: <%= name %>,
} as ComponentMeta<typeof <%= name %>>

const Template: ComponentStory<typeof <%= name %>> = (args) => <<%= name %> {...args} />;

export const Default: ComponentStory<typeof <%= name %>> = Template.bind({});

Default.args = {};
Default.storyName = 'デフォルト';
```

## 試す

以上でHygenの設定は完了です。正しく生成できるか試して見ましょう

ルート直下で以下を叩く。
```
yarn hygen generator component
```
コンポーネント名を聞かれる。InputTextと入力
```
? What is the name of component? › InputText
```

すると...

![スクリーンショット 2023-03-03 22.22.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2050411/f4e7e84a-7f07-558f-afda-573dabc0d335.png)

うおー。生成されてますね。

中身も確認してみましょう。

```tsx:InputText.tsx
import React from 'react';

interface InputTextProps {}

export const InputText: React.FC<InputTextProps> = (props) => {
  const {} = props;

  return (
    <div>hello component!</div>
  );
};
```
```InputText.sories.tsx
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { InputText } from './InputText';

export default {
    title: 'InputText',
    component: InputText,
} as ComponentMeta<typeof InputText>

const Template: ComponentStory<typeof InputText> = (args) => <InputText {...args} />;

export const Default: ComponentStory<typeof InputText> = Template.bind({});

Default.args = {};
Default.storyName = 'デフォルト';
```

ちゃんと生成できてますね。すごい。

これで面倒なお決まりコードを脳死で書くのとはおさらばです。

## 参考
https://www.gaji.jp/blog/2022/04/14/9556/
https://zenn.dev/sum0/articles/d40ab2a23c7e2a