やりたいこと
タイトルを見ろ~~~~~~!!!!!!!
前提情報
今回動作確認した環境
- Vue2.7 + Laravel
- Storybook v7.1.1
Storybookの運用をしているときに絶対にぶつかる壁
このようにstoriesファイルで読み込んでいるコンポーネントファイルがVuexの$store
にアクセスする処理を持っていた場合、$store
なんてものはないよという旨のエラーを吐かれ、Storybook上で正しくコンポーネントが表示されません。悲しいね😢
今回はどうにかこのエラーを解決してコンポーネントが表示されるようにするという話です。
なぜこんなことになるのか
当然ですがStorybook用に生成されるVueインスタンスはサービス本体のものとは別になっており、そのインスタンスにVuexが生えていないためエラーを吐かれています。
つまり、
なんとかVuexをStorybookのVueインスタンスに生やせば勝ち!!!!!!
ということになりますが、普通にやってもうまくいかなかったのでどうにかやり方を工夫する必要がありました。
具体的にどうすればいいのか
方法は主に3つあると考えています。
- Storybookに登録する用に、元のコンポーネントファイルをコピペして
$store
へのアクセス部分だけをモック化した別のコンポーネントファイルとして切り出す -
$store
にアクセスできるようモック化する - 諦める
それぞれ簡単に説明します。
コンポーネントファイルをコピペする
要は$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
などでやっているようにひとつにまとめてから代入すれば問題なく動くはずです。(多分)
最後に
もしかするともっと良い方法があるかもしれないのですが、現状僕はこの方法で解決できたので少しでも参考になれば幸いです。
僕はこれからハイラルを救いに行かなければならないので、これにて失礼します。