Help us understand the problem. What is going on with this article?

Vue.js のコンポーネント用 Storybook を Single File Component (SFC) で書く

More than 1 year has passed since last update.

はじめに

はじめまして。Motivation Cloud 開発メンバーの新参者 @navy-field です。
この開発現場では、フロントエンジニアとデザイナー間、あるいはフロントエンジニア同士の円滑なコミュニケーションのために Storybook を活用しています(参考:デザイナーとStorybookをS3上で共有)。
本記事では、そんな中で発見した、VueコンポーネントのStorybookを書く上でちょっと便利な小技を紹介いたします。

よくあるVueコンポーネントのStoryの書き方

Vue.jsコンポーネントのStoryの書き方として、以下のようなパターンをよく見かけます。

test.story.js
import { storiesOf } from "@storybook/vue";
import Test from "./Test.vue";

storiesOf('Test', module)
  .add('story as a component', () => ({
    components: { Test },
    data () {
        return {
            message: "Hello!"
        };
    },
    template: `<test :msg="message"></test>`
  }));

オフィシャルのドキュメントにもこのような形で書かれていますが、この書き方には次のような不便な点があります。

  • templateが文字列としてJS内に書かれるのでエディタのハイライトや補完が効かない
  • StoryにCSSを当てたいときに別ファイルに定義したりテンプレート内にインラインで書く必要があり、たちまち複雑化する

Vue.jsのオフィシャルガイドに書かれているSFCのメリットの裏返しですね。

これら問題は、Story を Single File Component (以下 SFC) で書くことで解消できます。

Storybook の設定ファイル

SFCでStoryを書く前に、Storybookの設定ファイルを変更して.vueファイルで書かれたStoryを読み込むようにましょう。

config.js
import { configure } from '@storybook/vue';

const req = require.context('../../src/components', true, /.story.(vue|js)$/)

function loadStories () {
  req.keys().forEach(req)
}

configure(loadStories, module);

このようにrequire.contextをつかうことで、componentsディレクトリ以下にあるファイルのうち、名前が.story.vueまたは .story.js で終わるファイルを全てStorybookで読み込むことができます。

SFCで書き直したStory

上記 test.story.js をSFCで書き直したサンプルは以下の通りです。

test.story.vue
<template>
    <test :msg="message"></test>
</template>

<script>
import Vue from "vue";
import { storiesOf } from "@storybook/vue";
import Test from "./Test.vue";

const testStory = {
    components: {
        Test
    },
    data () {
        return {
            message: "Hello!"
        }
    }
};
export default testStory;

storiesOf("Test", module)
  .add("story as a single file component", () => testStory);
</script>

<template> 内の export default testStory; によって、 vue-loadertestStoryにtemplateを組み込んでくれます。
またその下の add() の第2引数の関数の戻り値にtestStoryを指定することで、このStoryをtemplateを含むコンポーネントとしてStorybookに渡すことができます。

これでめでたくStoryをSFCで書くことができました。

おわりに

Storybookで自前のコンポーネントカタログを作ってそのクオリティを徐々に上げていくと能率がアップするし、とても楽しいです。
他にもTypeScriptでStory書いたり、Storyの整理術とかもあるので追々書いていこうと思います。

今後もStorybookを使っていきたいと思っていますが、最近Storybookのコミッター界隈で色々な動きがあったようですね。
これ とか これ
今後、宗派が別れて揉めたり、営利企業の介入によって廃れたりしなければ良いなと思うこの頃です。

We are hiring!

モチベーションクラウドは
「すべての組織を変える」
「世界の経営指標を変える」
事を本気で考え、心からそれを実現したいチームが開発しています。

組織に課題を感じたことのあるエンジニアのかたは少なくないと思います。
もし、少しでもこれらミッションやビジョンに共感したり興味があるというかたは
こちら から是非ご連絡ください!

おまけ

Storybook はフレームワークやアドオンのバージョン違いで動かなくなることがよくあるので、
今回のサンプルを動かした環境の package.json を記しておきます。

package.json
{
  "name": "sfc-story-sample",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "storybook": "start-storybook -p 9001 -c config/storybook"
  },
  "dependencies": {
    "@vue/cli": "^3.2.1",
    "vue": "^2.5.17",
    "vue-class-component": "^6.0.0",
    "vue-property-decorator": "^7.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@storybook/vue": "^4.1.1",
    "@vue/cli-plugin-babel": "^3.2.0",
    "@vue/cli-plugin-typescript": "^3.2.0",
    "@vue/cli-service": "^3.2.0",
    "awesome-typescript-loader": "^5.2.1",
    "babel-loader": "^8.0.4",
    "babel-preset-vue": "^2.0.2",
    "node-sass": "^4.9.0",
    "sass-loader": "^7.0.1",
    "typescript": "^3.0.0",
    "vue-loader": "^15.4.2",
    "vue-template-compiler": "^2.5.21"
  }
}
navy-field
ちょっとフロント寄りだけど何でも首を突っ込みたい器用貧乏エンジニ屋です
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした