皆さんこんにちは。 モンハンワイルズライフをエンジョイ中の比嘉華です!
今回は私たちのプロダクトであるGroup-Manager-2(以下、GM2とします。)のユーザ画面のデザイン改修に伴い、Vue.js→Next.jsに移行しました。その際に個人的に導入して見たかったscaffdogとstorybookを導入して開発効率の向上を図ってみました。
Group-Manager-2とは、技大祭に参加する団体の申請から、その参加団体の情報管理までを担うアプリケーションです。参加団体側と実行委員側の負担を減らし、技大祭が円滑に進むよう開発しています。NUTMEG内の最古のWebアプリケーションになっています。
scaffdogは、Markdownを利用してプロジェクトの初期設定やコードの雛形を自動生成するツールです。Markdown形式でテンプレートを定義できるため書きやすく、scaffdog init
コマンドでセットアップが爆速にできることが特徴です。
Storybookは、UIを個別に構築するためのワークショップを提供します。アプリ全体を実行することなく、到達が困難な状態やエッジケースを開発するのに役立ちます。
まずはStorybookの概要について簡単に説明します。
StorybookとはUIコンポーネント開発環境を提供するオープンソースのツールです。
各componentのUIやpropsに応じた挙動の確認、component単位でドキュメントの用意が可能です。
React、Vue、Angularなどの主要なJSフレームワークで導入でき、利用範囲も広くなっています。
ディレクトリ構成としては以下のようになります。
📁app
📁.scaffdog
📄config.js
📄template.md
📁.storybook
📄main.js
📄preview.ts
📁src
📁components
📁[generate]
📄[generate].stories.tsx
📄[generate].tsx
📄index.ts
GM2ではpnpmを使用しているため、pnpmでのコマンドを掲示します。必要であればnpmなどに変えて実行すると同様に実装できると思います。
npx storybook init
こちらのコマンドを実行することで、.storybook配下が自動的に作成されます。また、src/stories配下にサンプルが生成されていますが使う予定がない場合は削除して大丈夫です!
生成したものに加えて設定を追加していきます。
追加するものとしては
まずテーマカラー設定をします。個人的にダークテーマが大好きなので実装しまました。そのため、読み飛ばしても大丈夫です。 storybookが提供しているThemingを使います。
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: ~略~
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としています。
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}};
```
ファイル自体は三つ作成します。
です!
ここでは、出力先を設定します。
---
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}};
```
ここまで出来たら完成です!
実際に使ってみましょう。
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