こんにちは。ノーコードCMSのBiNDupのフロントエンドエンジニアのオオクボです。
前回の記事では、Dress以降の新機能開発で利用しているUIコンポーネントライブラリ「MUI」についてお話させて頂きました。 BiNDupのフロントエンド開発を支える技術に関連し、今回はMUIと同時期から採用している「Storybook」を紹介したいと思います。
Storybookとは
Storybook はコンポーネント(Webパーツ)をカタログ管理する事ができる開発補助ツールです。
「React入門 ~その1」で解説されている通り、昨今はWebアプリやサイトのUIをコンポーネント単位で開発し、組み合わせる事で画面を構築する方法が主流となっています。
これは React と並べて語られることの多いJavaScriptフレームワーク「Angular」や「Vue.js」、最近勢いをつけてきている「Svelte」でも同様です。
実装が進むにつれコンポーネントはどんどん増え、管理が難しくなっていきます。 似通った名前の物が生じてしまったり、また久々に改修するともなれば一体どのコンポーネントがどのような見た目であったのかすぐには判別がつかない…なんて事もままあります。
そんな問題を解決してくれるのがこのStorybookです。わざわざサイトの画面を見ながらソースコードを紐解かずとも、コンポーネントの見た目と振る舞いが一目瞭然となります。デザイナーとエンジニアの間で共有する事でデザインの齟齬を無くすことにも役立ちますね。
もちろんStorybookは先で連ねた各種JavaScriptフレームワークに対応しており、いわゆるモダンな開発環境であれば基本的に活躍の場を問いません。
Storybookを採用しているサービス
2022年3月現在ベータ版となっていますが、一部の採用実績をまとめたサイトがStorybook公式から提供されています。
イギリスのメディア「BBC」やドイツの高級車メーカー「Audi」のほか、「Microsoft」、「Adobe」などなど、生活の中で目にした事があるものも多いのではないでしょうか。
国内サービスの事例では、株式会社サイバーエージェントが提供するAmebaのデザインシステム「Spindle」が昨年リリースされ開発者の間で話題となったのですが、SpindleのStorybookもあわせて公開されています。
Storybookを一般公開する目的は各社によって様々でしょうが、製品・企業ブランディングが主なねらいのようです。
対象のサービスがどういったデザインを基調としているのか、またどういった単位でコンポーネントを分割して取り扱っているのか等、Web開発の参考になるので非常にありがたいですね。
尚、BiNDupにおいては Dress・SHiFT、新ブロックエディタの開発に利用されています。
イメージは新ブロックエディタのもの。
リストからコンポーネント名を選択する事で、そのUIがキャンバスに表示されます。
Storybookの始め方(Reactアプリ)
Storybookのインストール
既存のReactアプリ(本稿ではTypeScript環境を想定)にStorybookをインストールします。
npx -p @storybook/cli sb init
インストールが終わったら早速Storybookを起動してみましょう。
npm run storybook
起動が完了すると自動的にブラウザが立ち上がり、Storybookが表示されます。
コンポーネントの準備
ここまでの手順を実行したのちプロジェクトのsrcフォルダを見ると、新たに「stories」フォルダが作成されている事が確認できると思います。
中にはアセット(assets)、イントロダクション用のページ(Introduction.stories.mdx)、コンポーネント(Button.tsx, button.css …)、コンポーネントに対応するストーリー(Button.stories.tsx …)が入っているので、「assets」を除きすべて削除します。
コンポーネントをStorybook上で表示させるために用意するファイルをストーリーと呼び、コンポーネント一つに対しストーリーもまた一つ原則必要となります。
それではまず自作のコンポーネントを用意してみましょう。
テーマのキーワードとボタン内テキストを受け取り、デザインに反映するボタンコンポーネントを作成します。
// MyButton.tsx import React, { VFC } from 'react'; type Props = { theme: 'primary' | 'secondary'; text: string; }; const MyButton: VFC<Props> = props => { return ( <button style={{ backgroundColor: props.theme === 'primary' ? 'coral' : 'lightsteelblue' }}> {props.text} </button> ) }; export default MyButton;
ストーリーの作成
前の手順で作成したボタンコンポーネント「MyButton.tsx」に対応するストーリーを「stories」フォルダ内に作成します。
デフォルトの設定ではstoriesフォルダ内に置かれた「.stories.(tsxもしくはts, jsx, js, mdx)」の拡張子を持つファイルがストーリーとして読み込まれるので、これに寄せて命名します。
// MyButton.stories.tsx import React from 'react'; import MyButton from "../components/MyButton"; import { ComponentStory, ComponentMeta } from "@storybook/react"; export default { // コンポーネントとStorybook左側のリストにおけるディレクトリ名(title)を登録する。 // titleを 'components/MyButton' のようにすると階層を実現できる。 title: 'MyButton', component: MyButton, } as ComponentMeta<typeof MyButton>; // テーマに「primary」、テキストに「Primary Button」を適用したマイボタン「Primary」を登録。 export const Primary: ComponentStory<typeof MyButton> = () => <MyButton theme="primary" text="Primary Button" />; // テーマに「secondary」、テキストに「Secondary Button」を適用したマイボタン「Secondary」を登録。 export const Secondary: ComponentStory<typeof MyButton> = () => <MyButton theme="secondary" text="Secondary Button" />;
するとStorybookが更新され、画面左側のリストからPrimaryもしくはSecondaryを選択する事でストーリーで登録したボタンコンポーネントがキャンバスに描画されます。
※もしもエラーが発生してStorybookが表示されない場合はキャッシュによる影響が考えられるので、プロジェクトの「node_modules\ .cache\storybook」を削除した上でStorybookの再起動をお試しください。
まとめ
今回は割愛しますが、アドオンの追加で更に機能を強化することも可能。
便利なものについてはまたの機会にまとめて紹介できればと思います。
カタログとしての用途以外にも、Storybookを起点にコンポーネントの実装が行えたり、UIテストを盛り込めたりとポテンシャルの高いツールです。
Web開発を行われる際には是非取り入れてみてはいかがでしょうか。
弊社のStorybookは組織内部での活用にとどまっており一般公開するにはまだまだ至りませんが、皆様のお目にかかっても恥じ入る事のないような作り込みをしていきたい所です。