この記事はアドベントカレンダー2022の11日目の記事です。
こんにちは。mehm8128です。
traPではSysAd班に所属してJomonとtraPortfolioの開発に関わっています。
3Q最後の期末試験の2時間前に書いています。
今回はtraPに関する開発の話ではないですが、個人開発でStorybookを使ってみた話を書いていきます。
前にちょっと使ってみてよく分からんってなって1回諦めたのですが、最近参加させてもらっているインターン先で使ってなんとなく理解したので個人開発でも使ってみました。
Storybookとは
https://storybook.js.org/
これです。
Storybook is a frontend workshop for building UI components and pages in isolation.
UIコンポーネントやページを他から独立した状態で管理して開発を進めていくことができるツールです。
まだ使い始めたばかりで便利さを完全に理解しているわけではないですが、導入に当たって色々と苦労したのでメモ程度に書き残していきたいと思います。
環境はNext.js&TypeScriptです。Vue.jsとかでも使えるらしいです。
ちなみにtraPでは以下のtraP Collectionのプロジェクトで使われているらしいです。SysAd班集会の進捗報告でStorybookが良いって話を聞いて、初めてStorybookの存在を知りました。
https://github.com/traPtitech/trap-collection-launcher
https://github.com/traPtitech/trap-collection-admin
使い方
npx storybook init
npm run storybook
これだけで起動できます。
そうするとstories
というディレクトリができていると思うのですが、そこにはexamplesが入っています。Button.tsx
がコンポーネントで、Button.stories.tsx
がそのコンポーネントに対するstorybookの設定ファイルです。このファイルに色々と書き込むことでnpm run storybook
したときに起動するGUIでコンポーネントを見ることができたり、コンポーネントの状態を変えたりすることができるようになります。
試しにButton.stories.tsx
を見てみます。
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' }
}
} as ComponentMeta<typeof Button>
title
ではGUIで表示される名前を設定できます。スラッシュでディレクトリ構造にできます。
component
は使うコンポーネントを指定します。
argTypes
ではコンポーネントのpropsに渡す値を指定できます。
controlを使うとGUI上で値を設定できます。今回はcolor
なのでカラーパレットを使えますが、select
にして値の配列を指定すると選択肢の中から選択できるような表示にすることもできます。
const Template: ComponentStory<typeof Button> = args => <Button {...args} />
export const Primary = Template.bind({})
Primary.args = {
primary: true,
label: 'Button'
}
実際にGUIで表示するコンポーネントの設定です。この一つ一つをStoryと呼ぶらしいです。
Template
で基本となる設定をして、後ろのPrimary
やSecondary
などで、propsを設定していくつかの種類のボタンを作っています。
諸々の設定
既存のプロジェクトにStorybookを導入するにあたって、導入した設定たちは以下の通りです。
- importで絶対パスを使えるように
- Windi CSSを使えるように
- Ant Designを使えるように
- Recoilを使えるように
- next/routerを使えるように
- next/imageを使えるように
- MSWを使えるように
- Chromaticを使う
これらを今から説明していきます。
(ここから先は期末試験後に書いています)
importで絶対パスを使えるように
Module not found: Error: Can't resolve なんたら in なんたら
みたいなエラーが大量に出てたのでなんだこれって調べたらこの記事にたどり着きました。
https://zenn.dev/enish/articles/cde07d3d22f95b
記事の通りに.storybook/main.js
をいじったら直りました。
Windi CSSを使えるように
スタイルが当たっていなくてWindi CSSが適用できていなさそうだったので調べたら公式のこのページにたどり着きました。
https://windicss.org/integrations/webpack.html#storybook
この通りにしたら直りました。
Ant Designを使えるように
Ant DesignというのはUIライブラリなのですが、これもWindi CSS同様、スタイルが当たってなさそうだったので調べてみたところ、どの記事が参考になったか覚えてないのですが、.storybook/preview.js
でスタイルをimportすればよさそうということが判明しました。
ただし、Ant Designの場合はglobal.css
で@import "antd/dist/antd.css";
として読み込んでいるので、Ant Designのスタイルもimportしてさらにglobal.css
に書いてあるスタイルもimportしようとすると表示がおかしくなってしまったので、importするのはglobal.cssだけ十分でした(styleディレクトリに他にCSSファイルがあるなら同様にしてimportするといいと思います)。
.storybook/preview
はNext.jsでいう_app.tsx
みたいなもので、Storybookでは各コンポーネントを独立して表示していて_app.tsx
は読み込まれないので、代わりに.storybook/preview
で全体に適用させたいスタイルなどを設定するんですね。
Recoilを使えるように
上記補足のように、_app.tsx
が読み込まれないので<RecoilRoot></RecoilRoot>
も適用されず、Recoilが使えていない状態です。
ここではStorybookのDecoratorという機能を使うとよさそうということが分かりました。
https://storybook.js.org/docs/react/writing-stories/decorators
僕は.storybook/preview.js
でこんな感じ↓でdecoratorを定義して、
export const decorators = [
(Story) => (
<StoryWrapper>
<Story />
</StoryWrapper>
),
]
<StoryWrapper></StoryWrapper>
は
<RecoilRoot>
{children}
</RecoilRoot>
みたいになっているコンポーネントにしています(実際には/GET me
のリクエストを飛ばす処理を書いたり、Reactの比較的新しい機能であるSuspenseを入れたりしています)。
atomの初期値を設定したい場合は<RecoilRoot>
にinitializeState
を渡せばよいのですが、.storybook/preview.js
でdecoratorの設定をしてる場合はストーリーごとに設定できなくなってしまうので、それが嫌なときはストーリーごと(もしくはコンポーネントごと)に<RecoilRoot>
のdecoratorを設定することになりそうです。
next/routerを使えるように
これも設定する必要がありました。調べると色んなやり方が出てきてどれにするか悩んだのですが、これにしました。
https://storybook.js.org/addons/storybook-addon-next-router
書いてある通りにやればできました。
next/imageを使えるように
これも設定する必要がありました。
https://xenox.dev/next-image-with-storybookjs/
MSWを使えるように
MSWという、モックサーバーを使えるようになるライブラリがあります。
https://mswjs.io/
これをStorybookで使いたかったので調べました。
https://zenn.dev/rabbit/articles/dd9b04940b93fe
書いてある通りにすればできました。
MSWはJomonでも導入していて、かなり便利なのでおすすめです。
Chromaticを使う
StorybookにはChromaticという、公式推奨のテスト用ツールがあります。
ビジュアルレグレッションテストってやつですね。
ビジュアルレグレッションテストはサイバーエージェントさんのWeb Speed Hackathonでも使われていましたね。
https://storybook.js.org/docs/react/writing-tests/visual-testing
https://zenn.dev/keitakn/articles/storybook-deploy-to-chromatic
https://moneyforward.com/engineers_blog/2022/04/04/improved-design-reviews/
小規模な個人開発で使うメリットは少なそうですが、面白そう&便利そうということでやってみました。
Github Actionsでpush時に自動でテストを回してくれるようにも設定できます。
https://www.chromatic.com/docs/github-actions
が、環境変数が上手く読み込めてなくてaxiosのエラーが出てしまうので、いつか直したいと思っています。
最後に
色々導入してるプロジェクトだと色々設定が必要でちょっと大変でしたが、使いこなせればとても便利だと思うので積極的に使っていきたいと思います。
明日の担当はs9くんです!お楽しみに~