echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

【Vue.js】Storybookでコンポーネント開発を便利にする

はじめに

今回もVue.jsネタを。(本当はもっとAWSやServerless Frameworkなどバックエンド的なネタを書きたい。てか仕事でもそうしたい...)

最近、フロント側を触る機会があるのですが、コンポーネントベースでの開発(いわゆる「コンポーネント駆動開発(CDD)」)を行う事が多いです。(特にReactでは多いのかも)
ただその際、コンポーネントを実際にアプリに組み込まないと確認ができないので(あくまで「コンポーネント」なので)、どうしたものかなあ...と思ってました。

しかし「Storybook」というツールを使えば、コンポーネント単体での動作確認が可能になります。
今回はその「Storybook」についての記事です。

おことわり

storybookに関するブログはほとんどがReactなので、私はVue.jsを使おうと思います。(Reactは他の方の記事がいっぱいありますし)

Storybookについての詳細は、Storybook公式サイト(下記)を参照してください。
https://storybook.js.org/

インストール&初期設定

インストール
ルートフォルダで下記コマンドを指定すればOKです。

※Vue.js3のサポートは現在も実装中とのことなので、動かない機能があるかも。
参照: Install Storybook (「troubleshooting」を参照)

# storybookのインストール(言語(=Vue.js)を自動で判別する)
> npx sb init  
  
# 明示的にVue2であることを指定してインストールする
> npx sb init --type vue  
   
# 明示的にVue3であることを指定してインストールする  
> npx sb init --type vue

その後、下記コマンドを実行して正常に起動すればOK。

※私の環境(Windows10 + WSL2 Ubuntu)では、一度PCを再起動しないとダメでしたので、うまく起動しないという場合、一度PC再起動した方が良いかも。

# もちろんnpm run → yarnでもOK 
> npm run storybook  

初期設定
「.storybook/main.js」ファイルを編集して「stories」に開発フォルダを追加する。
こうしないと、開発フォルダ内のストーリーファイル(後述)を認識してくれない。

※「.storybook/main.js」ファイルは、Storybookインストール時に自動で作成される

module.exports = {
  "stories": [  
    // デフォルトはこの2つのみ
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",  
      
    // 自分の開発環境をお好みで追加すると便利 
    "../makky12/src/components/**/*.stories.mdx",
    "../makky12/src/components/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials"
  ],
  "framework": "@storybook/vue"
}

ストーリーコードを書く

Storybookでの動作確認は、「ストーリー」(=テストパターンのようなもの)をストーリーファイルに定義することで行えます。(ストーリーについての詳細は、下記公式サイトを参照)

上記サイトにもある通り、ストーリーの基本の流れは以下の通りです。

  • 対象コンポーネントをimportする
  • 対象コンポーネントを使用したテンプレートを作成する
  • 上記テンプレートをbindする
  • 必要に応じて、argsに各種propsの値を設定する

百聞は一見に如かずということで、サンプルを作成しました。(Sample.jsが対象のコンポーネント、Sample.stories.jsがそのストーリー定義ファイルです)

※ストーリーファイル名が先述の「.storybook/main.js」ファイルの「stories」に記載のパターンとマッチしていないと、Storybookの画面に表示されないので注意です。

// Sample.js
<template>
  <div>
    <input type="text" :placeholder="placeHolder" :value="defaultValue" @change="onChange" />
  </div>
</template>
  
<script>
export default {
  name:"Sample",
  props: {
    placeHolder: {
      type: String,
      required: false,
      default: ""
    },
    defaultValue: {
      type: String,
      required: false,
      default: ""
    },
  },
  
  data: function () {
    return {}
  },
  
  methods: {
    onChange(e) {
      this.$emit('onChange', e.target.value);
    },
  },
}
</script>
  
<style>
</style>
// Sample.stories.vue
import Sample from './Sample.vue';
  
const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Sample },
  template:
    '<Sample @onChange="onChange" v-bind="$props" />',
});
  
export const noProps = Template.bind({});
export const withplaceHolder = Template.bind({});
withplaceHolder.args = {
  placeHolder: 'I am placeholder.'
};
  
export const withBoth = Template.bind({});
withBoth.args = {
  placeHolder: 'I am placeholder.',
  defaultValue: 'I am default value.'
};
  
export default {
  title: 'Example/Sample',
  component: Sample,
};

上記ストーリーファイルを定義してStorybookを起動すると、下記画面が表示されます。

左側の「Example」内に「Stories」(=export defaultのtitle)が表示され、その下に定義した各ストーリーの変数名が表示されています。(単語単位で区切られるみたいですね)

※Sample以外は、デフォルトでインストールされるストーリーです。

各ストーリーの変数名をクリックすると、ちゃんとargsに応じたpropsの値が反映されていることが分かります。(With Bothは初期値を設定しているので、placeholderは表示されませんが)

f:id:Makky12:20211226190147p:plain
f:id:Makky12:20211226190526p:plain
f:id:Makky12:20211226190538p:plain

また、画面下部の「Controls」タブ内の「Props」に各ストーリーで渡したpropsが表示されており、ここの値を変更することでpropsの値を直接変更することができます。

f:id:Makky12:20211230203555p:plain

Actionsについて

またStorybookには「Actions」というものがあり、これを用いることで、emitしたイベントの確認ができます。

emitを確認する場合、特別なことは必要なく、先述のサンプルソースのようにテンプレートに通常のVue.jsのemitと同じように定義することで、イベントの発火を確認できます。

その場合、画面下部の「Actions」タブにemit関数に渡された値が表示されます。(テンプレートの「@emit変数名="XXX"」のXXXの箇所が、「Actions」タブのキーとして表示されます)

※詳細は、デフォルトでインストールされるストーリーの「Button」のソースを見るとわかります。
f:id:Makky12:20211226191452p:plain

ちなみに、こちらのページに記載のやり方でも、emitを確認できます。(こちらはReactなどでも行うやり方)
ただしこちらの場合でも、通常のVue.jsのemitと同じ定義は必要です。

Actions

こちらの方法の場合、下記が必要になります。(ただしsb initコマンドでインストールすれば、最初から下記が完了した状態になっています。)

  • 「@storybook/addon-essentials」のインストール
  • 「.storybook/main.js」ファイルのaddonsに「@storybook/addon-essentials」を追加する
    • 先述の「.storybook/main.js」ソースを参照

参照:https://storybook.js.org/docs/vue/essentials/introduction

// export defaultのargTypesで指定する方法(全ストーリーに適用)  
export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    onChange: { action: 'changed' }
  },
};  
  
// actionを@storybook/addon-essentialsからインポートする方法  
// (ストーリー個別に適用可能)  
import { action } from '@storybook/addon-actions';  
  
export const withBoth = Template.bind({});
withBoth.args = {
  placeHolder: 'I am placeholder.',
  defaultValue: 'I am default value.',
  methods: {
    onChange: action('change'),
  },
};

まとめ

以上、急ぎ足でしたが、Storybookの使い方でした。

自分も最近Storybookのことを知った...というかあまりフロント側のテストや確認については知らなかったので、便利だなあと思いました。

てか、かつて関わったVue.jsの業務をやった時にこれを知っていればなあ...と思ったりします。

でもやっぱり、本当はもっとAWSやServerless Frameworkなどの技術に携わりたいなあ...

それでは、良いお年を!