LoginSignup
1

StoryBook for html でデザインガイドライン開発

Posted at

最初に

私の作業の備忘録として記載されています。
StoryBookは色々なフレームワークに対応していますが、
htmlで使用する際の情報が少ないので試行錯誤しながら知り得た情報を記載していきます。

今回作成したいもの

StoryBook for htmlで実際に触れるComponentを作成し、
デザインガイドラインとして運用したいです。

使用する技術

  • フレームワーク
  • Component開発言語
    • html
    • scriptが必要な時は、Vanillajsで記載
    • storyの開発にはTypeScriptを使用
  • スタイル
  • デプロイ環境
  • CI/CD
    • github Action

開発環境構築

以下のような手順を考えています。

  1. StoryBook for htmlプロジェクトの作成
  2. StoryBookをTypeScriptで記載できるように修正
  3. StoryBookでSassを使用できるようする
  4. StoryBookでVanillajsを実行できるようにする
    • VanillajsはTypeScriptで開発できるようにしたい。
  5. Chromaticにdeploy
  6. githubのPRが作成された際にChromaticにdeployできるようにgithub Action作成

StoryBook for htmlプロジェクトの作成

公式のページを参照
https://storybook.js.org/docs/html/get-started/install

mkdir <project名>
cd <project名>
npx storybook init --type html

StoryBookをTypeScriptで記載できるように修正

現在のままでは、storyなどがjavascriptで記載されています。
javascriptでは開発したくないので、TypeScriptで開発できるように修正します。
(StoryBookはデフォルトでTypeScriptをサポートしてますので、tsconfig.jsonなど用意しなくても良いです。)

デフォルトのButtonComponentを例にしますが、変更点は以下です。

stories/Button.jsstories/Button.tsに変更し、以下の内容に書き換える。

import "./button.css";

export enum ButtonSize {
  small = "small",
  medium = "medium",
  large = "large",
}

export type ButtonProps = {
  primary?: boolean;
  size?: ButtonSize;
  label: string;
  backgroundColor?: string;
  onClick: () => void;
};

export const createButton = ({
  primary = false,
  size = ButtonSize.medium,
  backgroundColor,
  label,
  onClick,
}: ButtonProps) => {
  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(
    " "
  );

  if (backgroundColor) btn.style.backgroundColor = backgroundColor;

  return btn;
};

あまり特出して補足するところはないですが、
ButtonPropsを作成して、createButtonの引数を定義すると使いやすくなります。

次にstoryもTypeScript化します。

stories/Button.stories.jsstories/Button.stories.tsに変更し、以下の内容に書き換えます。

import { ButtonProps, ButtonSize, createButton } from "./Button";
import { Meta, StoryFn } from "@storybook/html";
export default {
  title: "Example/Button",
  argTypes: {
    backgroundColor: { control: "color" },
    label: { control: "text" },
    onClick: { action: "onClick" },
    primary: { control: "boolean" },
    size: {
      control: { type: "select" },
      options: ButtonSize,
    },
  },
} as Meta<ButtonProps>;

const Template: StoryFn<ButtonProps> = ({ label, ...args }) => {
  return createButton({ label, ...args });
};

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: "Button",
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: "Button",
};

export const Large = Template.bind({});
Large.args = {
  size: ButtonSize.large,
  label: "Button",
};

export const Small = Template.bind({});
Small.args = {
  size: ButtonSize.small,
  label: "Button",
};

補足としては2点あります。

  1. argTypesに型を当てるために、Metaという型を当てています。
  2. Templateの型はStoryFnでTemplateの型を定義することができます。

また、Template.bind({})がanyになってしまう方で、修正したいという方は
tsconfig.jsonを別途用意して、"strictBindCallApply": trueを追記すると型が指定されます。

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Node",
    "target": "ES2020",
    "jsx": "react",
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "sourceMap": true,
    "strictBindCallApply": true
  },
  "exclude": ["node_modules", "**/node_modules/*"]
}

StoryBookでSassを使用できるようにする

StoryBookでSassを使用してスタイルを記述したいと考えています。
Sassの最新版を使用するためには、StoryBookの中で使用されているwebpack5にしないといけません。

※StoryBookがデフォルトで使用しているのはwebpack4なので、webpack4でsassを使用するためには、この後インストールするライブラリのversionを色々と調整しないといけないのでめんどくさくなります。

webpack5の導入

npm uninstall @storybook/builder-webpack4 @storybook/manager-webpack4
npm i -D @storybook/builder-webpack5 @storybook/manager-webpack5

webpack5のbuilderをinstallします。
uninstallは必要ないですが、ゴミは削除しておきます。

.storybook/main.jsに設定を追加します。

module.exports = {
  stories: [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  core: {
    builder: "webpack5", // ここにwebpack5を使うよ!という内容を記述
  },
  framework: "@storybook/html",
};

coreのbuilderに"webpack5"と記載します。

sassの導入(必要なライブラリも追加)

各種必要なライブラリの追加

npm i -D sass css-loader sass-loader style-loader @storybook/preset-scss

.storybook/main.jsのaddonsに@storybook/preset-scssを追加

addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/preset-scss", // 追加
  ],

sassの適用

これは好みですが、一つ一つのファイルにcssを当てるのめんどくさいので、
大元のファイルのcssを反映させたいと思います。

まず、すべてのcssを取りまとめるcssファイルを作成します。
私の場合だと、stories/styles/main.scssを作成し、以下のように記述

@import "./components/button.scss";
@import "./components/header.scss";
@import "./components/page.scss";

この例ではstories/styles/components/のディレクトリを作成し、そこに各のComponentのcssを記述し、importさせています。

そして、.storybook/preview.jsmain.scssを適用します。

import "../stories/styles/main.scss";

これで、すべてのstoriesに対してmain.scssに記載されたcssが適用されます。

この作業でディレクトリ構成は以下になります。
※不要そうなものは削除してます。

./
├── package-lock.json
├── package.json
├── stories
│   ├── Button.stories.ts
│   ├── Button.ts
│   ├── Header.stories.ts
│   ├── Header.ts
│   ├── Introduction.stories.mdx
│   ├── Page.stories.ts
│   ├── Page.ts
│   └── styles
│       ├── components
│       │   ├── button.scss
│       │   ├── header.scss
│       │   └── page.scss
│       └── main.scss
└── tsconfig.json

StoryBookでVanillajsを実行できるようにする

StoryBookでVanillajsを実行したいのですが、一々scriptタグで囲んで文字列で入れるのめんどくさいです。
文字列だと、editorの補完が効かないので開発効率も落ちるでしょう。
どんな内容がいいのかは開発したい内容によると思いますが、
以下のstorybook-addon-run-scriptを使用して、scriptを適用させます。

必要なものをインストール

npm i -D storybook-addon-run-script raw-loader
  • storybook-addon-run-script
    • StoryBookの実行前にscriptを埋め込みを行なってくれる
  • raw-loader
    • jsファイルをスクリプトとしてではなく、文字列として読み取ることができます。
    • scriptはStringでないと読み込めないので、特定のファイル(.runscript.js)をStringとして読み込みます。

scriptの用意

適当にstories/scripts/page.runscript.jsを作成します。

setTimeout(() => {
  const title = document.getElementById("title");
  if (title) {
    title.innerText = "チェンジタイトル";
  }
}, 5000);

function alertTest() {
  alert("アラートです。");
}

storiesにscriptを読み込ませる

stories/Page.stories.tsに先ほど作成したスクリプトを読み込ませます。

import { within, userEvent } from "@storybook/testing-library";
import { createPage } from "./Page";
import { StoryFn, Meta } from "@storybook/html";
import { withRunScript } from "storybook-addon-run-script/html";

import runScript from "!!raw-loader!./scripts/page.runscript.js"; // !!raw-loader!を追記

export default {
  title: "Example/Page",
  parameters: {
    layout: "fullscreen",
  },
  decorators: [withRunScript(runScript)], // decoratorsにwithRunScript(runScript)を追記
} as Meta;

const Template: StoryFn<any> = () => createPage();

export const LoggedOut = Template.bind({});

export const LoggedIn = Template.bind({});

LoggedIn.play = async ({ canvasElement }) => {
  const canvas = within(canvasElement);
  const loginButton = await canvas.getByRole("button", { name: /Log in/i });
  await userEvent.click(loginButton);
};

注意点としてスクリプトファイルを読み込む際には、!!raw-loader!を追記してください。
これを行うことで、runScriptはStringとして扱われます。

これで、StoryBookを読み込み直すと、5秒後にtitleが変更されます。
また、Pageに<button onclick=alertTest();>alertTest</button>みたいなhtmlを埋め込むと
scriptで定義したalertTest関数が実行され、alertが表示されます。

typescriptでscriptを開発したい人

scriptをtypescriptで開発したい人には、.runstories.tsでスクリプトを記載して、
tsc コマンドでjsに変換することで実現できます。
ただのts -> jsへのコンパイルなので詳細は省略します。

Chromaticにdeploy

ChromaticとはStoryBookを簡単にdeployして、
公開したり、特定のユーザに見せて開発状況を共有したりできます。

Chromaticへのログインおよびプロジェクト作成

とりあえず、Chromaticのドキュメント通りにSignUpして、プロジェクト作成してください。

ログインする際は、私の場合はgithubと連携する必要があったので
githubアカウントを使用しています。

Chromaticをインストール

ドキュメント通りにChromaticをインストール

npm install --save-dev chromatic

ChromaticにStoryBookをデプロイ

npx chromatic --project-token <your-project-token>

project-tokenはプロジェクトを作成した際に出てくるtokenを使用してください。

※この時gitを使用してないとエラーになるみたいなので、プロジェクトをgit管理してください。
もちろんやってるよね??
あと、今の作業ブランチにCommitが一つもないのもエラーになるみたい??

Chromaticにログインして、以下のようにbuildが確認できればdeploy完了です。

image.png

最後に、chromaticコマンドを実行するとpackage.jsonに以下のコマンドが追加されます。

  "scripts": {
    "chromatic": "npx chromatic --project-token=<your-project-token>"
  },

ptoject-tokenが下手書きされていて、危ないかつ、後々githubAcrtionで使用するため
以下のように変更してます。

  "scripts": {
    "chromatic": "npx chromatic --project-token=${CHROMATIC_PROJECT_TOKEN}"
  },

上記のため、今後ローカルからChromaticにdeployする場合は、

export CHROMATIC_PROJECT_TOKEN=<your-project-token>
npm run chromatic

となります。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1