この記事はTechCommit Advent Calendar 2023の13日目の記事です。
前置き
- vueプロジェクトはすでに作成済みという前提で話を進めます
- storybookはすでにインストール済み、初期設定済みという前提で話を進めます
- 関係なさそうな箇所はほとんど省略しております。
- この記事が100%正しいという保証はありません。「おかしいな?」と思ったら別サイトを見ることを推奨します。
環境
各バージョン
バージョン | |
---|---|
vite | 7.6.3 |
vue | 3.3.4 |
vuetify | 3.4.4 |
storybook | 7.6.3 |
ディレクトリ構造
今回の説明に関係なさそうなやつは全て省略
./storybook
├ main.js
├ preview.js
├ StoryWrapper.vue
└ withVeutifyTheme.decorator.js
./src
├ plugins
├ vuetify.js
1. vuetifyをインストール
npm i vuetify
2. srcフォルダの中にpluginフォルダを作り、その中にvutify.jsファイルを作る
目的
-
main.js
のコード量を減らすため - 1つのファイルに書いて置くことによって二度手間を防ぐ
(というか、storybook関係なしにvuetifyにしろ、vuexにしろ、routerにしろこのようにするのが主流らしい)
vuetify公式のコードをちょっとだけいじるだけでok
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
export default createVuetify({
components,
directives,
})
3. srcフォルダの中にあるvueのmain.jsを編集
目的
vueでvuetifyを使えるようにするため
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
+ import vuetify from './plugins/vuetify'
- createApp(App).mount('#app')
+ createApp(App).use(vuetify).mount('#app')
4. ラッパーを作る
ここからstorybookの話になります。
目的
vuetifyはv-app
タグで囲まないと正しく動かないので(公式でも言ってる)
storyのコンポーネントをv-app
タグで囲む
<template>
<v-app>
<v-main><slot name="story"></slot></v-main>
</v-app>
</template>
<style>
.v-application__wrap {
min-height: auto !important;
/* これをしないと大きな余白が作られる */
/* !importantしないと設定が上書きされるもよう */
}
</style>
5. withVuetifyTheme.decorator.jsを作る
目的
ストーリーブックのストーリーコンポーネントにVuetifyのテーマを適用するため
import { h } from 'vue';
import StoryWrapper from './StoryWrapper.vue';
export const withVuetifyTheme = (storyFn, context) => {
const story = storyFn();
return () => {
return h(
StoryWrapper,
{},
{
story: () => h(story, { ...context.args }),
}
);
};
};
何やってるかわからないのでchatgptに聞いてみた。
h()
について知りたい人は以下のサイトもどうぞ
6. 仕上げにpreview.jsに今まで作ったパーツを全部つなげる
/** @type { import('@storybook/vue3').Preview } */
+ import { setup } from '@storybook/vue3';
+ import { withVuetifyTheme } from './withVeutifyTheme.decorator';
+ import vuetify from '@/plugins/vuetify'
+ setup((app) => {
+ app.use(vuetify)
+ });
const preview = {
parameters: {
+ decorators : {withVuetifyTheme},
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;
これで連携ができたはずです!
お疲れ様でした!
別の書き方について
一部の方々は上記の書き方に対して
「あれ?デコレーターは以下のように書くんじゃないの?」という疑問を持っているかもしれません。
export const decorators = [withVuetifyTheme];
この書き方でも問題なく動きました。
chatgptに質問したところ
この書き方は古いバージョンの書き方らしいです。
Storybook 6.0以降では、previewオブジェクトを使うことが推奨されていて、このオブジェクトのparametersプロパティにdecoratorsを指定します。
どちらの書き方でも問題ないようです。
次の記事紹介
14日目はやっしさんによるLeetCodeでアルゴリズム力を鍛えよう!です。
駄文のコーナー(ここから先は編集後記みたいなものなので飛ばしても大丈夫です。)
以下のサイトを参考にに作業していました。
ただこのサイトのpreview.js
で以下のようなことが出てきたんです。
import { registerPlugins } from '../src/plugins';
setup((app) => {
// Registers your app's plugins into Storybook
registerPlugins(app);
});
registerPlugins
ってなに!?
../src/plugins
ってなんのこと!?
ってなって。これらが分からず色々調べてました。
どうやら
src
フォルダの中plugin
フォルダの中にindex.js
ファイルを作成し、そのファイルの中に
registerPlugins
関数を作成して、引数で渡されたVue
のアプリケーションに対して、フォントやプラグインを適用するというやりかたがあるようです。
例えばとしてこんな感じ
import vuetify from './vuetify'
import pinia from './store'
import router from './router'
export function registerPlugins(app) {
app.use(vuetify)
.use(router)
.use(pinia)
}
今まで私は、preview.js
にも、main.js
にもvuetifyの設定は直接書き込んでました。
あと、私が作ったvueプロジェクトは、
storybookになれるために
storybookの公式サイトのvueチュートリアル以外のアプリを作ってstorybookを連携させて、
その後にvuetifyとの連携の仕方を勉強するためにvuetifyを当てただけなので。router
もpinia
やvuex
も使わずvuetify
しか使わないので今回はregisterPlugins
を使わない方法を取りました。