株式会社スマレジの開発部でスマレジのサーバサイドを作っています

LaradockにStoryBookを入れてみた(Vue.js)

こんにちは!株式会社スマレジ、エンジニアのmasaです。 今日は、以前から触っている環境にStoryBookを入れて、アプリ登録までやってみたので、 手順を残したいと思います。

StoryBookって?

公式ページ

storybook.js.org

Storybook is the most popular UI component development tool for React, Vue, and Angular. It helps you develop and design UI components outside your app in an isolated environment. Learn Storybook to create bulletproof UI components, along the way you’ll build an app UI from scratch. (公式ページIntro to Storybookより)

masa的は作成したフロントエンドアプリを登録するカタログだと思っています。 複数プロダクトだしているASPの場合だと、プロダクト間でデザインをある程度統一したかったりするわけですが、 プロダクトごとに独立して実装しちゃうと、デザインやUIの変更が発生したときの調査コストがバカにならない。 そういうときのために日ごろからStoryBookに登録しておけば、アプリを一覧で見ることができる、大体そんな認識です。

あと、フロントエンジニアとデザイナーとのコミュニケーションツールにもなるのかな。その辺の意見は↓を見て思いました。

qiita.com

masaはバックエンド中心の開発なので、フロントメンバーとデザイナーとのコミュニケーションはそこまで詳しくないです。 ただ、スマレジの場合、新しいUIを作成するときはデザイナーさんがワイヤーフレームを作成してくれるので、フロントアプリのレビュー時に ↑のStoryBookがなぜ必要かで書かれているような、「ワイヤーフレームとデザインちがうやん」みたいな突っ込みは 作った当人以外なら誰でも突っ込めます(実際突っ込む)。だから、UI部品作成毎に登録だけでもしてくれると、すぐにフィードバック返せて 手戻り防止にもなる(かも?)とは思います。

バックエンドが関係する話だと、APIのインターフェースを一緒にここに書いちゃえるとこですね。 特にフロント専門の人だと、「API周りは既存資産のコピペじゃないと作れない。。。」みたいな場合もあるとかないとか。 ただ、作った時はいいですが、回収したときにStoryBook側のメンテもやらないといけないので、 そこは改修フローに入れておかないとだめですね。

まずは入れてみる

※現在の構成については過去のブログ masa2019.hatenablog.com をご参照ください。

参考にしたサイト様

qiita.com

まずは、dockerコンテナに入って、フロントエンドの作業ディレクトリまで移動。

cd <your laradock path>/laradock
docker exec -it laradock_workspace_1 bash #人によってworkspace名は違うかも。これはデフォルト
cd <your path to frontend work directory>/frontend 

でStoryBookをインストール

# Storybook for Vue のインストール
$ npm i -D @storybook/vue

StoryBookのデフォルトのポート番号は6006。違うポートにしたい場合はpackage.jsonに追記。

{
  "scripts": {
    "storybook": "start-storybook -p <利用したいポート番号> -c .storybook",
    "buid-storybook": "build-storybook -s public"
  }
}

新しいポートを解放してあげる必要があるので、laradock側のdocker-composeをちょっと変える。

### Workspace Utilities ##################################
    workspace:
    (中略)
      volumes:
        - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}${APP_CODE_CONTAINER_FLAG}
      extra_hosts:
        - "dockerhost:${DOCKER_HOST_IP}"
      ports:
        - "${WORKSPACE_SSH_PORT}:22"
        - "6006:6006"
      ...

.storybook/config.jsを作成。この時、sassやstylusを入れている場合は、パスを合わせて書いてあげる必要があります。

import { configure } from '@storybook/vue';
import Vue from 'vue';
const req = require.context('../src/stories', true, /\.stories.js$/);
configure(req, module);
//stylusの読み込み
defaultConfig.module.rules.push({
    test: /\.styl$/,
    loader: 'style-loader!css-loader!stylus-loader'
});
import HelloWorld from '../src/app1/components/HelloWorld';

Vue.component('item', HelloWorld);

function loadStories() {
//なぜかrequre()でパスが解決できなかった(フルパスにしてもだめ。webpackの設定なにかいるんかな。。。)ので、公式ドキュメントに記載されていた方法で
//    require('../src/stories');
    req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

あわせて、webpack.config.jsを作成し、stylus情報を書きこみます。この辺りは↓サイト様を参考にしました。 qrunch.net

const path = require("path");

module.exports = {
    module: {
        rules: [
            {
                test: /\.styl(us)?$/,
                use: [
                    'vue-style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 2
                        }
                    },
                    'stylus-loader'
                ],
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.vue', '.json', '.styl'],
        alias: {
            'assets': path.resolve('path/to/assets'),
            '~': path.resolve(__dirname, '../')
        }
    }
};

今回は前々回つくった、VuecliのHelloWorldページの一部のリンクをaxiosでとってきているVueを登録してみます。

import { linkTo } from '@storybook/addon-links';
import HelloWorld from './../app1/components/HelloWorld';

export default {
  title: 'HelloWorld',
};

export const toStorybook = () => ({
  components: { HelloWorld },
//ここでつくったテンプレートを呼び出す。
    template: '<HelloWorld :ecosystems="[{\'link\': \'hogehoge\',\'name\': \'welcome to StoryBook!\'}]" />',
//今は要らない(と思う)
  methods: { action: linkTo('Button') },
});

toStorybook.story = {
  name: 'to Storybook',
};

npm run storybookすると・・・

f:id:masa2019:20191201193139p:plain
こんな感じに

ちゃんと、:ecosystemsで設定した配列も反映されています。

やって感じたこと

StoryBookは、パーツを作って、それをカタログ登録して、という2段階の実装になるんですね。 カタログ登録のほかにもテスト機能もあるので、想定される入力パターンを列挙して、その時の表示を確認する・・・みたいな使い方ならありかも? 登録だけする運用なら、カタログ登録の省エネ化がいるなーと感じました。単純に手間が増えちゃうので。