活動の様子

scaffdogのすゝめ

scaffdogのすゝめ

始めに

皆さんこんにちは。 モンハンワイルズライフをエンジョイ中の比嘉華です!

今回は私たちのプロダクトであるGroup-Manager-2(以下、GM2とします。)のユーザ画面のデザイン改修に伴い、Vue.js→Next.jsに移行しました。その際に個人的に導入して見たかったscaffdogとstorybookを導入して開発効率の向上を図ってみました。

Group-Manager-2とは、技大祭に参加する団体の申請から、その参加団体の情報管理までを担うアプリケーションです。参加団体側と実行委員側の負担を減らし、技大祭が円滑に進むよう開発しています。NUTMEG内の最古のWebアプリケーションになっています。

scaffdogとは

scaffdogは、Markdownを利用してプロジェクトの初期設定やコードの雛形を自動生成するツールです。Markdown形式でテンプレートを定義できるため書きやすく、scaffdog initコマンドでセットアップが爆速にできることが特徴です。

Storybookとは

Storybookは、UIを個別に構築するためのワークショップを提供します。アプリ全体を実行することなく、到達が困難な状態やエッジケースを開発するのに役立ちます。

まずはStorybookの概要について簡単に説明します。

StorybookとはUIコンポーネント開発環境を提供するオープンソースのツールです。

各componentのUIやpropsに応じた挙動の確認、component単位でドキュメントの用意が可能です。

React、Vue、Angularなどの主要なJSフレームワークで導入でき、利用範囲も広くなっています。

scaffdogによるテンプレート作成

ディレクトリ構成としては以下のようになります。

📁app
    📁.scaffdog
        📄config.js
        📄template.md
    📁.storybook
        📄main.js
        📄preview.ts
    📁src
        📁components
            📁[generate]
                📄[generate].stories.tsx
                📄[generate].tsx
                📄index.ts

1. storybookをインストールする。

GM2ではpnpmを使用しているため、pnpmでのコマンドを掲示します。必要であればnpmなどに変えて実行すると同様に実装できると思います。

npx storybook init

こちらのコマンドを実行することで、.storybook配下が自動的に作成されます。また、src/stories配下にサンプルが生成されていますが使う予定がない場合は削除して大丈夫です!

2. storybookの環境を作る。

生成したものに加えて設定を追加していきます。

追加するものとしては

  • テーマカラー設定
  • autodocsの導入

まずテーマカラー設定をします。個人的にダークテーマが大好きなので実装しまました。そのため、読み飛ばしても大丈夫です。 storybookが提供しているThemingを使います。

Theming | Storybook docs

pnpm add --save-dev @storybook/manager-api @storybook/theming

インストール後、preview.tsを以下のように書き換えてください。

import type { Preview } from '@storybook/react';
import { themes } from '@storybook/theming';

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      theme: themes.dark,
    },
  },
};

export default preview;

次に、autodocsを追加します。autodocsを追加するとshow codeでコードを見ることができて便利!と思ったので導入していきます。

pnpm add @storybook/addon-docs

でインストールし、main.tsのaddonsに追記します。

  addons: [
		~~
    '@storybook/addon-docs',
  ],

その後、preview.tsにtagsを設定します。

const preview: Preview = {
  tags: ['autodocs'],
  parameters: ~~

3. scaffdogをインストールする

pnpm install scaffdog

pnpm run scaffdog init

> [email protected] scaffdog /app
> scaffdog "init"

? Please enter a document name. template


Setup of scaffdog 🐶 is complete!                                                                                                                                                              

  ✔ .scaffdog/config.js
  ✔ .scaffdog/template.md

Now you can do scaffold by running $ scaffdog generate.

Please refer to the following documents and customize it.
https://scaff.dog/docs/templates

pnpm run scaffdog init コマンドで.scaffdogフォルダを作成し、テンプレートとなるmdファイルの名称を決めることができます。

今回はtemplateとしています。

4. scaffdogの環境を作る。

template.mdが作成されたら中身を更新していきます。

---
name: "template"
root: "."
output: "src/components"
ignore: []
questions:
  name: "Please enter components name."
---

# `{{ inputs.name | pascal }}/index.ts`

```typescript
export { default } from "./{{ inputs.name | pascal }}";
```

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

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

export default {
title: 'Components/{{ inputs.name | pascal }}',
tags: ["autodocs"],
component: {{ inputs.name | pascal }},
parameters: {
    docs: {
      source: {
        type: "auto",
      },
    },
  },
} as Meta<typeof {{ inputs.name | pascal }}>;

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

export const Default: Story = {
  args: {

  },
};
```

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

```typescript
import { FC } from 'react';

type {{ inputs.name | pascal }}Props = {};

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

export default {{ inputs.name | pascal}};
```

ファイル自体は三つ作成します。

  • index.tsx
  • {generate}.stroies.tsx
  • {generate}.tsx

です!

ここでは、出力先を設定します。

---
name: "template"
root: "."
output: "src/components"
ignore: []
questions:
  name: "Please enter components name."
---

ここでindex.tsxを作成し、importが簡略されるようにしています。

# `{{ inputs.name | pascal }}/index.ts`

```typescript
export { default } from "./{{ inputs.name | pascal }}";
```

ここでstroies.tsxの設定を記述しています。コンポーネントを確認する際はargsにpropsを入れてください。

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

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

export default {
title: 'Components/{{ inputs.name | pascal }}',
tags: ["autodocs"],
component: {{ inputs.name | pascal }},
parameters: {
    docs: {
      source: {
        type: "auto",
      },
    },
  },
} as Meta<typeof {{ inputs.name | pascal }}>;

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

export const Default: Story = {
  args: {

  },
};
```

ここでは、コンポーネントの雛形を作成しています。

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

```typescript
import { FC } from 'react';

type {{ inputs.name | pascal }}Props = {};

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

export default {{ inputs.name | pascal}};
```

5. 実際に触ってみる。

ここまで出来たら完成です!

実際に使ってみましょう。

pnpm run scaffdog generate

? Please select the output destination directory. src/components
? Please enter components name. test


🐶 Generated 3 files!                                                                                                                                                                          

     ✔ src/components/Test/index.ts                                                                                                                                                           
     ✔ src/components/Test/Test.stories.tsx                                                                                                                                                   
     ✔ src/components/Test/Test.tsx                                                                                                                                                           

このようにgenerateコマンドを実行すると、出力先の選択と名前を要求されます。上手くいけば雛形が自動生成されます!失敗していたらtemplate.md周りが悪さをしていると思います。 また、コマンドだけでなくvscodeの拡張機能を追加することでvscodeからテンプレートを作成することができます。 https://marketplace.visualstudio.com/items?itemName=scaffdog.scaffdog-vscode

最後にStorybookを起動し、確認しましょう!

pnpm run storybook dev -p 6006

終わりに

今回はscaffdogを用いて、コンポーネントの雛形を作成しました。

これを使うことでコンポーネント作成時にかかるストレスが軽減されると思うので作成する必要のあるコンポーネントが多いやmkdir,touchコマンドでの作成が面倒と考えているなら導入してみてはいかがでしょうか。

参考にした記事一覧

https://zenn.dev/katsumanarisawa/articles/2aeced911e5a0c

https://zenn.dev/mikakane/articles/react_storybook

https://qiita.com/80andco_tech_pr/items/a3f1c4334521825cb465

https://zenn.dev/miyaken0805/articles/d95921b135d117

https://qiita.com/y-natani/items/b8034b2d7c7fbafe63bf

https://scaff.dog/docs

https://zenn.dev/rehabforjapan/articles/045a3d4c0d3bc6