プロジェクト開発において、高品質なモックアップを作成することは非常に重要です。しかし、モックアップ作成プロセスはしばしば面倒で、費用がかかります。ReactなどのUIフレームワークのデザインガイドライン作成ツールとしてよく知られているStorybookを使うことで、手軽にモックアップを作成できます。この記事では、どのようにStorybookがモックアップ作成に役立つかについて紹介します。
Storybookのモックアッププロジェクトを作成する
Storybookを使ったモックアッププロジェクトを作成します。
今回は、UIフレームワークを選定していない状況で、とりあえずBootstrapとjQueryを使ってモックアップを作成する状況を想定していますので、--type
オプションでhtml
を指定します。
$ storybook-mockup
$ cd storybook-mockup
$ npm init -y
$ npx storybook@latest init --type html
本記事では、storybook-mockup
というプロジェクト名で進めますが、実際に試す際はプロジェクトに合わせて命名してください。
最後のコマンドを実行すると、Storybookが自動的に起動します。
Storybookを停止したい場合はターミナルでCtrl+C
を入力して停止してください。これ以降、Storybookを実行したい場合は、package.json
があるディレクトリで以下のコマンドを実行してください。
$ npm run storybook
storiesディレクトリを整理する
この手順は必ずしも必要ではありませんが、モックアップ作成作業がやりやすくなるようにstories
ディレクトリを整理しておきます。
どのように整理するのかはプロジェクトの方針やメンバーの好みによって変わりますが、物理ディレクトリの構造とStorybookのサイドメニューの構造が一致している方が探しやすくなると思います。
作成直後の状態では、EXAMPLEというサイドメニュー表示されていますが、ボタンやドロップダウンリストなどのパーツを「コンポーネント(components)」、モックアップを「ページ(pages)」に分けてファイルを整理し、サイドメニューも同様に分けるようにします。
また、Storybookでは1コンポーネント1ファイルにはなりません。このまま、複数のコンポーネントやページを同じディレクトリに並べておくと見にくくなるので、コンポーネント名でディレクトリを作成して、ファイルをまとめることにしておきます。
ご使用のIDEやエディタの機能によって、ファイル移動に伴ってimport
文が自動的に修正されますが、操作によっては適切に修正されない場合があります。その場合はimport
文を直接修正してください。
Storybookのサイドメニューはstories
ディレクトリの構造に合わせて作成しているわけではなく、.Stories.js
ファイル内に定義されているtitle
属性の値で構造が決まります。
Button.stories.js
とHeader.stories.js
のtitle
属性のExample
はComponents
に、Page.stories.js
のtitle
属性のExample
はPages
に修正しておきます。
すべてのコードを示すとかなりの量になるので、修正した箇所だけ説明します。コード全体を確認したい場合は、https://github.com/t0k0sh1/storybook-mockupを参照してください。
import { createButton } from "./Button";
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
export default {
title: "Components/Button",
tags: ["autodocs"],
render: ({ label, ...args }) => {
title
属性を"Example/Button"
から"Components/Button"
に修正しています。
import "./header.css";
import { createButton } from "../Button/Button";
Header.js
からButton.js
を参照していますが、そのimport
文のパスをディレクトリ構造に合わせて修正しています。
import { createHeader } from "./Header";
export default {
title: "Components/Header",
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ["autodocs"],
render: (args) => createHeader(args),
title
属性を"Example/Header"
から"Components/Header"
に修正しています。
import "./page.css";
import { createHeader } from "../../components/Header/Header";
Page.js
からHeader.js
を参照していますが、そのimport
文のパスをディレクトリ構造に合わせて修正しています。
import { expect, userEvent, within } from "@storybook/test";
import { createPage } from "./Page";
export default {
title: "Pages/Page",
render: () => createPage(),
title
属性を"Example/Page"
から"Pages/Page"
に修正しています。
StorybookにBootstrapとjQueryを導入する
StorybookにBootstrapとjQueryを導入していきます。導入方法にはいくつかの方法がありますが、ここではCDNを使って手軽に導入する方法を解説します。
Bootstrapを使用できるようにする
StorybookでCDNを使用する場合、.storybook/preview-head.html
を新規作成し、そこにCDNにアクセスlink
タグを記述します。
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
crossorigin="anonymous"
/>
jQueryを使用できるようにする
こちらも同様に.storybook/preview-head.html
にCDNにアクセスするscript
タグを記述します。
<script
src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
crossorigin="anonymous"
></script>
これでモックアップ作成の準備が整いました。
ButtonコンポーネントをBootstrapベースに書き換える
最後にすでに存在するButtonコンポーネントをBootstrapベースに書き換えてみましょう。
まずは、現在の実装を確認してみます。
import { createButton } from "./Button";
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
export default {
title: "Components/Button",
tags: ["autodocs"],
render: ({ label, ...args }) => {
// You can either use a function to create DOM elements or use a plain html string!
// return `<div>${label}</div>`;
return createButton({ label, ...args });
},
argTypes: {
backgroundColor: { control: "color" },
label: { control: "text" },
onClick: { action: "onClick" },
primary: { control: "boolean" },
size: {
control: { type: "select" },
options: ["small", "medium", "large"],
},
},
};
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary = {
args: {
primary: true,
label: "Button",
},
};
export const Secondary = {
args: {
label: "Button",
},
};
export const Large = {
args: {
size: "large",
label: "Button",
},
};
export const Small = {
args: {
size: "small",
label: "Button",
},
};
今回注目するのは、primary
属性とsize
属性です。他の属性もありますが、Button.stories.js
は修正せずにいきます。
import './button.css';
export const createButton = ({
primary = false,
size = 'medium',
backgroundColor,
label,
onClick,
}) => {
const btn = document.createElement('button');
btn.type = 'button';
btn.innerText = label;
btn.addEventListener('click', onClick);
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');
btn.style.backgroundColor = backgroundColor;
return btn;
};
属性に応じてclassNameに設定する値を制御します。方針は以下です。
primary
が指定されたらbtn-primary
を指定し、指定されなかったらbtn-secondary
を指定するsize
がsmall
ならbtn-sm
を指定し、large
ならbtn-lg
を指定し、それ以外は何も指定しない
修正後のコードは以下になります。storybook-buttonクラスをbtnに修正してあります。
import "./button.css";
export const createButton = ({
primary = false,
size = "medium",
backgroundColor,
label,
onClick,
}) => {
const btn = document.createElement("button");
btn.type = "button";
btn.innerText = label;
btn.addEventListener("click", onClick);
const mode = primary ? "btn-primary" : "btn-secondary";
let btnSize = size === "small" ? "btn-sm" : size === "large" ? "btn-lg" : "";
btn.className = ["btn", btnSize, mode].join(" ");
btn.style.backgroundColor = backgroundColor;
return btn;
表示した結果は以下のようになります。
まとめ
以上のように、Storybookはプロジェクト開発において、手軽かつ効果的なモックアップ作成ツールであることが分かりました。Storybookを使用すると、コンポーネント化やパーツ化が手軽に推進できるので、デザインガイドラインを作成しながらモックアップを作成できます。Storybookを使うことで、モックアップ作成の開発プロセスを改善し、開発者のストレスを軽減することができます。皆さんにも一度、Storybookを使用して、モックアップ作成をスムーズに進めてみてはいかがでしょうか?