2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

viviONAdvent Calendar 2023

Day 18

Storybook上からthis.$storeにアクセスした~~~~~~い!!!!!!!😡

Last updated at Posted at 2023-12-17

やりたいこと

タイトルを見ろ~~~~~~!!!!!!!

前提情報

今回動作確認した環境

  • Vue2.7 + Laravel
  • Storybook v7.1.1

Storybookの運用をしているときに絶対にぶつかる壁

image.png

このようにstoriesファイルで読み込んでいるコンポーネントファイルがVuexの$storeにアクセスする処理を持っていた場合、$storeなんてものはないよという旨のエラーを吐かれ、Storybook上で正しくコンポーネントが表示されません。悲しいね😢

今回はどうにかこのエラーを解決してコンポーネントが表示されるようにするという話です。

なぜこんなことになるのか

当然ですがStorybook用に生成されるVueインスタンスはサービス本体のものとは別になっており、そのインスタンスにVuexが生えていないためエラーを吐かれています。

つまり、

なんとかVuexをStorybookのVueインスタンスに生やせば勝ち!!!!!!

ということになりますが、普通にやってもうまくいかなかったのでどうにかやり方を工夫する必要がありました。

具体的にどうすればいいのか

方法は主に3つあると考えています。

  1. Storybookに登録する用に、元のコンポーネントファイルをコピペして$storeへのアクセス部分だけをモック化した別のコンポーネントファイルとして切り出す
  2. $storeにアクセスできるようモック化する
  3. 諦める

それぞれ簡単に説明します。

コンポーネントファイルをコピペする

要は$storeへのアクセスができずにエラーが出ているので、その部分を丸々適当なモック処理に置き換えればいいわけです。
ただし本番用のファイルでそんなことをしてしまったら明日から僕の席がなくなってしまうので、Storybookに登録する用の別のコンポーネントファイルとして切り出した後、該当部分をモック化することになります。

【メリット】
- むずかしいことを考えずに対応できる

【デメリット】
- storiesファイルだけでなくvueファイルも作成しないといけないので手間が増える
- 元のコンポーネントファイルに修正が入ったときに追従する必要があり、管理工数が増える

$storeにアクセスできるようモック化する

先ほどは処理をモック化する方法でしたが、こちらは$store自体をモック化すればいいじゃないかという方法です。

【メリット】
- 元のコンポーネントファイルをそのまま登録できるので楽
    - 作業するのはstoriesファイルのみでいい
    - 元のコンポーネントファイルの修正がそのまま反映されるので追従する必要がない

【デメリット】
- そもそもモック化が難しい

諦める

諦めます

【メリット】
- 何も考えなくていい

【デメリット】
- 何も解決していない

今回は「$storeにアクセスできるようモック化する」という方法で解決しました😊

$storeのモック化

先に結論から書いてしまいますが、Storybookを導入したときに生成されるpreview.jsに以下のように修正することで解決しました。

import Vue from 'vue';
import Vuex from 'vuex';

/** @type { import('@storybook/vue').Preview } */
const preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
};

// $storeへ疑似的にアクセスできるようにする
Vue.use(Vuex);
Vue.prototype.$store = new Vuex.Store({
  // 以下実際のサービスで使ってるstoreと同じものをコピペする
  state: {},
  mutations: {},
  getters: {},
  actions: {},
});

export default preview;

※関係ない部分は省略しています

具体的には、Vueのprototypeを使って$storeという名前のインスタンスプロパティを生やし、そこにnew Vuex.Store({})オブジェクトを代入しています。
これにより、StorybookのVueインスタンスにも$storeという変数が定義されている状態となり、コンポーネントが正常に表示されるようになります。

今回はストアが一つの場合ですが、複数ある場合もstore/index.jsなどでやっているようにひとつにまとめてから代入すれば問題なく動くはずです。(多分)

最後に

もしかするともっと良い方法があるかもしれないのですが、現状僕はこの方法で解決できたので少しでも参考になれば幸いです。

僕はこれからハイラルを救いに行かなければならないので、これにて失礼します。

2
0
0

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
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?