Nuxt.jsへのStorybookの導入と、Sassの変数や共通CSSを読めるようにする設定
かなり疲弊した。バージョンは次のとおり。
"nuxt": "2.4.0"
"@storybook/vue": "5.0.11"
Nuxt.jsにStorybookを追加
Storybookの公式ドキュメントを参考にした。手動で入れる方法もあるみたいだけど、CLIの方が簡単そうなので任せることに。
npx -p @storybook/cli sb init --type vue
Storybookを起動する
設定ファイルやデモ用のコンポーネントの生成、npm scriptへの追加などはCLIがすべて用意してくれるので、とりあえずもうStorybookの起動はできる。ここまではとても簡単。
npm run storybook
アドオンの追加
アドオンは、Storybookの拡張機能みたいなもので、これを使ってStorybookをカスタマイズできる。CLIを実行すると、デフォルトでActionsとLinksが最初から入ってたけど、それ以外にも、よさげなアドオンをいくつか入れてみることに。
でも、紹介されているアドオンすべてがVue.jsに対応しているわけじゃないので、Addon / Framework Support Tableで確認してどれを入れるか検討する。
アドオンを追加する場合、だいたい以下のような手順で入れられる。
npm i --save-dev {ADDON}
でインストールする/.storybook/addons.js
でインポートする- 全体の設定は
/.storybook/config.js
に記述 - 個別のストーリーの設定が必要なら
/stories/*.stories.js
に記述
Viewport
Viewportは、ChromeのDevToolsみたいに、Viewportをポチポチ切り替えて表示を確認できる。
インストール
npm i --save-dev @storybook/addon-viewport
/.storybook/addons.js
import '@storybook/addon-viewport/register'
/.storybook/config.js
import { addParameters } from '@storybook/vue' addParameters({ viewport: { defaultViewport: 'iphonex' } })
ここでは、デフォルトのVuewportのサイズをiPhoneXに設定した。
a11y
a11yは、アクセシビリティ的にNGな箇所をエラーで教えてくれる。
インストール
npm i --save-dev @storybook/addon-a11y --dev
/.storybook/addons.js
import '@storybook/addon-a11y/register'
/.storybook/config.js
import { withA11y } from '@storybook/addon-a11y' addDecorator(withA11y)
storybook-addon-vue-info
storybook-addon-vue-infoは、コードのプレビューやpropsの情報などを、自動で生成してくれるので、簡易的なドキュメントの代わりになりそう。Storybookの公式サイトにあるInfoはVue.jsに対応していなかったので、同じようなことができるstorybook-addon-vue-infoを入れた。
インストール
npm install --save-dev storybook-addon-vue-info
/.storybook/addons.js
import 'storybook-addon-vue-info/lib/register'
/.storybook/webpack.config.js
.storybook
以下にwebpack.config.js
を新規作成し、以下の設定を記述する。
module.exports = ({ config }) => { config.module.rules.push({ test: /\.vue$/, loader: 'storybook-addon-vue-info/loader', enforce: 'post' }) return config }
/stories/index.stories.js
import { withInfo } from 'storybook-addon-vue-info' storiesOf('MyComponent', module) .addDecorator(withInfo) .add( 'foo', () => ({ components: { MyAwesomeComponent }, template: '<my-awesome-component/>' }), { info: { summary: 'Summary for MyComponent' } } )
ストーリーごとにaddDecorator(withInfo)
で個別に指定しないと動かなかった。あと、info
もあわせて指定しないと動かなかった。
Moduleが見つからないエラーを解消
@
や~
を使ってパスを指定すると、Error: Can’t resolve ‘@/components/*’
のようなエラーとなるので、次の設定で解消する。
/.storybook/.babelrc
.storybook
以下に.babelrc
を新規作成し、以下の設定を記述する。
{ "presets": [ "@babel/preset-env", "babel-preset-vue" ] }
/.storybook/webpack.config.js
storybook-addon-vue-infoの設定で作成したwebpack.config.js
にaliasの設定を追記する。
const path = require('path') const rootPath = path.resolve(__dirname, '../') module.exports = ({ config }) => { config.resolve.alias['@'] = rootPath config.resolve.alias['~'] = rootPath config.module.rules.push({ test: /\.vue$/, loader: 'storybook-addon-vue-info/loader', enforce: 'post' }) return config }
Sassの変数とmixinをStorybook上で読み込みできるようにする
/components/*.vue
のファイルを/stories/*.stories.js
で読み込むと、変数やmixinを使っていたVueコンポーネントがエラーになってしまう。これは、StorybookはNuxt.jsのレールから外れることになるので、Nuxt.jsで共通のSCSSを読めるように設定していたとしても、Storybookで別途設定しないといけないから。
/.storybook/webpack.config.js
webpack.config.js
に以下の設定を追記する。
これまでの設定も含めた最終的なコードは以下のとおり。
const path = require('path') const rootPath = path.resolve(__dirname, '../') module.exports = ({ config }) => { config.resolve.alias['@'] = rootPath config.resolve.alias['~'] = rootPath config.module.rules.push({ test: /\.s?css$/, loaders: [ 'style-loader', 'css-loader', 'sass-loader', { loader: 'sass-resources-loader', options: { resources: ['./assets/stylesheets/_variables.scss', './assets/stylesheets/_mixins.scss'], include: path.resolve(__dirname, '../') } } ] }) config.module.rules.push({ test: /\.vue$/, loader: 'storybook-addon-vue-info/loader', enforce: 'post' }) return config }
共通のスタイルを適用できるようにする
Decoratorという機能を使うとStorybook上で共通のスタイルを読み込むことができるので、リセット用のCSSや、サイト共通で使うCSSコンポーネントのスタイルを読み込んでおくとよさそう。
/.storybook/Decorator.vue
.storybook
以下にDecorator.vue
を新規作成して、以下のコードを記載し、読み込みたい共通CSSを<style lang="scss">
内でインポートする。
<template> <div class="decoarator"> <slot name="story"></slot> </div> </template> <script> export default { name: 'Decorator' } </script> <style lang="scss"> @import "@/assets/stylesheets/_normalize.scss"; @import "@/assets/stylesheets/_base.scss"; @import "@/assets/stylesheets/_components.scss"; </style>
/.storybook/config.js
config.js
にDecoratorを追加して、Storybook全体で共通CSSが読み込まれるようにする。アドオン等の設定も含めた最終的なコードは以下のとおり。
import { configure, addParameters, addDecorator } from '@storybook/vue' import { withA11y } from '@storybook/addon-a11y' import Decorator from './Decorator.vue' addParameters({ viewport: { defaultViewport: 'iphonex' } }) addDecorator(withA11y) addDecorator(story => ({ components: { Decorator }, render(h) { return ( <decorator> <story slot="story" /> </decorator> ) } })) // automatically import all files ending in *.stories.js const req = require.context('../stories', true, /\.stories\.js$/) function loadStories() { req.keys().forEach(filename => req(filename)) } configure(loadStories, module)
まとめ
こんなにがんばったのに、まだVuexをStorybookから読めるようにはなってないけど、つかれたので今日はここまで。