LoginSignup
7
3

scaffdogを導入してStorybookを使ったコンポーネント作成を幸せにしてみた

Posted at

クライアントワークという業態で日々様々なプロジェクトに携わっているのですが、その中で一定数のコンポーネントをStorybookを使いながら一心不乱に作成するというフェーズがよく発生します。

新規ファイルを作成してexport constから書き始めてtype Props書いて、ストーリーファイルも作成して…という作業は地味に手間がかかる+既存のファイルをコピペするにもファイル名を変更したり不要な部分を確認しながら削除したりが地味に手間…ということで、いい感じに自動化+テンプレート化できないかと模索していたところscaffdogにたどり着きました。何度かプロジェクトに導入してみて、無事幸せになれたので備忘録を残します。

喜びポイント

  • セットアップがめっちゃ簡単(準備から使用開始までコマンドは2つだけ)
  • マークダウンでテンプレートの記述が可能なので、とっつきやすい
  • とはいえJSのような感覚で条件分岐もできるので、難易度と便利性のバランスがとって私にとってはちょうど良かった
  • 複数のテンプレートが登録可能&管理も簡単なので、幅広いユースケースに対応できる

テンプレートを基にファイルを作成している様子

$ npx scaffdog generate

上記のコマンドを叩くと、自分で作成したテンプレートの質問事項が順番に表示されるので、↓ のようにそれぞれ答えていくだけです!
 
Screenshot 2024-04-10 at 23.38.08.png

↓ 完成! :dog: :tada:

Screenshot 2024-04-10 at 23.39.32.png

実際に作成したテンプレート

コンポーネントの格納先

ざっくりイメージはこんな構造の想定です。

  • 共通するコンポーネントを格納するディレクトリ
  • 管理画面に関する色々を格納するディレクトリ
  • エンドユーザーが閲覧する画面に関する色々を格納するディレクトリ
- app
    - _components
        - CommonButton
            - CommonButton.tsx
            - CommonButton.stories.tsx
    - a
        - _components
            - ComponentA
                - ComponentA.tsx
                - ComponentA.stories.tsx
    - b
        - _components
            - ComponentB
                - ComponentB.tsx
                - ComponentB.stories.tsx

テンプレートファイルの中身

---
name: "component"
root: "."
output: ["./app/_components", "./app/*/_components"]
questions:
  name: "コンポーネント名をパスカルケースで入力してください (ex. CommonButton)"
  story:
    confirm: "ストーリーファイルも一緒に作成しますか?"
---

# `{{ inputs.name | pascal }}/{{ inputs.name | pascal }}.tsx`

```typescript
export type Props = {}

export const {{ inputs.name | pascal }}: React.FC<Props> = ({ }) => {
  return <div></div>;
};
```

# `{{ inputs.name | pascal }}/{{ inputs.name | pascal }}.stories.tsx`

```typescript
import type { Meta, StoryObj } from "@storybook/react";
import { {{ inputs.name | pascal }} } from '{{ "./" + inputs.name  }}';

const meta: Meta<typeof {{ inputs.name | pascal }}> = {
  component: {{ inputs.name | pascal }},
  title: "{{ inputs.name | pascal }}",
};

export default meta;
type Story = StoryObj<typeof {{ inputs.name | pascal }}>;

export const Default: Story = {
  args: {
  },
};

```

まとめ

コンポーネントファイルとストーリーファイルを違う場所に格納したい場合にももちろん少し調整すれば可能なので、scaffdogすばら〜!臨機応変力〜!となりました。学び!

コンポーネントファイルだけを作成する、ストーリーファイルだけを作成する、両方作成するなどのパターンも準備したことで、今のところ発生し得るほとんどのケースを網羅できている気がします。

もっとこういう良いやり方あるよ!などあればぜひ教えていただけると嬉しいです\(^o^)/

7
3
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
7
3