自分的Storybook + Vue環境の作成方法(CLIなし)

2021/02/10 2021/02/10 #Vue #storybook

自分的Storybook + Vue環境の作成方法

こんにちは。Nonです。
今回は

でTipsだけまとめているStorybookの環境構築や設定について自分なりに試行錯誤したものを書こうと思います。

弊社

では、デザイナーとフロントの協業というのがまだまだ弱く、フロント開発におけるテンプレートといいますか、明確なフローというのが確立していません。私はバックエンドの人間なので、デザイナーとどのように仕事をしていくかなどもわからなかったので、色々調べていった結果Storybookというものを発見しました。

なのでここでの目標は

  • デザイナーとコンポーネント単位のデザインレビューや、コードレビューを行うこと
  • Nuxtのようなフレームワークに依存せず、コンポーネント単位での開発ができること
  • 同様にNuxtのようなフレームワークに依存せず、コンポーネントをinstall or importできること

としています。

Storybook導入

storybookを使用するので、当然インストールしなければなりません。他のサイトやブログなどではNuxt + storybook のような構成を取っていますが、Nuxtに依存したくないと思いましたので、このようなフレームワークの導入は検討していません。

しかし、Vue.jsには依存しています。

また、storybook-cliも利用していません。使った方が簡単ですが、最小構成にしたい and cliのinstallしたくない などの理由があります。そのうちCLI版の記事も書くかも。

storybook インストール

npm i @storybook/vue --save-dev

コマンドでstorybookを起動できるようにpackage.jsonに下記を追加。
この時点ではstorybookの設定をしていないので起動できません。

"scripts": {
  "storybook": "start-storybook",
  "build-storybook": "build-storybook",
},

Vue インストール

npm i vue --save-dev

eslint インストール

npm i eslint eslint-loader eslint-plugin-vue --save-dev

linterの設定はプロダクトに合わせて設定してください。

コマンドでlinterを起動できるように、package.jsonに下記を追加

"scripts": {
  "eslint": "eslint --ext .js,.vue ./",
  "eslint-fix": "eslint --fix --ext .js,.vue ./"
},

Storybook設定

{project_root}/.storybook/main.js に下記を追加

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
};

Storybook用のjsの場所はプロジェクト毎に決めていいと思います。

コンポーネント追加

{project_root}/src/components/atoms/Button/BaseButton.vue を配置。

<template>
  <button>button</button>
</template>

<script>
export default {
  name: 'BaseButton'
};
</script>

<style scoped>

</style>

{project_root}/src/components/atoms/Button/Button.stories.js を配置。

import {storiesOf} from '@storybook/vue';
import BaseButton from './BaseButton';

storiesOf('Button', module)
  .add('buttons', () => ({
    components: {BaseButton},
    template: '<div>' +
        '<base-button></base-button>' +
        '</div>',
  }));

起動確認

Storybookが起動すればここまではOK。

スクリーンショット 2021-02-17 12.59.43.png

外部でパッケージ利用できるように設定する

npm i でパッケージインストールしたときに使用できるようにコンポーネントを登録するスクリプトを記載。

これに関しては色々なリリース方法があるので、用途に応じて変更して下さい。(CDNとかplane jsとか)

詳細はこちら。

import BaseButton from './src/components/atoms/Button/BaseButton';

const Components = {
  BaseButton,
};

export function install(Vue) {
  if (install.installed) return;
  install.installed = true;
  Object.keys(Components).forEach((component) => {
    Vue.component(component, Components[component]);
  });
}

const plugin = {
  install,
};

let GlobalVue = null;
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}

export default Components;

css / scss / sass 関連

2021/02現在、最新のwebpackでsass-loaderを動かすとバージョンの整合性チェックでエラーが発生するので、10系 の最新バージョンを指定してインストールする。

npm i style-loader css-loader sass-loader@10.1.1 --save-dev

{project_root}/.storybook/main.js に下記を追加

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
        '@storybook/addon-storysource',
        '@storybook/addon-viewport',
        'storybook-readme',
    ],
    webpackFinal: (config) => {
        config.module.rules.push({
            test: /\.scss$/,
            use: ['style-loader', 'css-loader', 'sass-loader']
        });
        return config;
    }
};
npm run storybook

※↓エラーが発生する場合あり。

Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (88)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v4.13.1

storybookを起動しようとしてエラーが出た場合、node-sassをインストールしてビルドしておくこと。

npm i node-sass --save-dev

npm rebuild node-sass

npm run storybook

試しにscssファイルなどを作成してimportしてみる。

VueのScoped CSSで試しても大丈夫です。

{project_root}/src/sass/atoms/_button.scss

.btn {
  color: red;
}

{project_root}/src/sass/app.scss

// My atom's scss.
@import 'atoms/button';

{project_root}/.storybook/preview.js でscssファイルをimportする

import {addDecorator, addParameters} from "@storybook/vue";
import {INITIAL_VIEWPORTS} from "@storybook/addon-viewport";
import {addReadme} from 'storybook-readme/vue';
import '../src/sass/app.scss';

addParameters({
    viewport: {
        viewports: INITIAL_VIEWPORTS
    }
});

addDecorator(addReadme);

動作確認

スクリーンショット 2021-02-17 17.27.20.png

アドオンを追加

storybookを使うにあたって便利なアドオンを追加します。これも各プロダクトによって導入するかどうかを決めて大丈夫です。

@storybook/addon-actions

npm i --save-dev @storybook/addon-actions

{project_root}/.storybook/main.js にアドオン登録

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
    ]
};

{project_root}/src/components/atoms/Button/BaseButton.vue にクリックイベント設置。

<template>
  <button @click="$emit('click')">
    button
  </button>
</template>

{project_root}/src/components/atoms/Button/Button.stories.js を書き換え。

import {storiesOf} from '@storybook/vue';
import BaseButton from './BaseButton';
import {action} from '@storybook/addon-actions';

storiesOf('Button', module)
  .add('buttons', () => ({
    components: {BaseButton},
    template: '<div>' +
        '<base-button @click="action"></base-button>' +
        '</div>',
    methods: {
      action: action('clicked')
    }
  }));

動作確認

スクリーンショット 2021-02-17 14.50.10.png

@storybook/addon-knobs

npm i @storybook/addon-knobs --save-dev

{project_root}/.storybook/main.js にアドオン登録

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
    ]
};

{project_root}/src/components/atoms/Button/Button.stories.js を書き換え。

import {storiesOf} from '@storybook/vue';
import BaseButton from './BaseButton';
import {action} from '@storybook/addon-actions';
import {text} from '@storybook/addon-knobs';

storiesOf('Button', module)
  .add('buttons', () => ({
    components: {BaseButton},
    props: {
      buttonLabel: {
        default: text('label', 'button')
      },
    },
    template: '<div>' +
        '<base-button @click="action">{{ buttonLabel }}</base-button>' +
        '</div>',
    methods: {
      action: action('clicked')
    }
  }));

{project_root}/src/components/atoms/Button/BaseButton.vue を書き換え。

<template>
  <button>button</button>
</template>

<script>
export default {
  name: 'BaseButton'
};
</script>

<style scoped>

</style>

動作確認

スクリーンショット 2021-02-17 15.33.48.png

@storybook/addon-storysource

npm i @storybook/addon-storysource --save-dev

{project_root}/.storybook/main.js にアドオン登録

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
        '@storybook/addon-storysource',
    ]
};

動作確認

スクリーンショット 2021-02-17 15.46.56.png

@storybook/addon-viewport

npm i @storybook/addon-viewport --save-dev

{project_root}/.storybook/main.js にアドオン登録

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
        '@storybook/addon-storysource',
        '@storybook/addon-viewport',
    ]
};

{project_root}/.storybook/preview.js にviewport(iPhoneなどの画面情報)情報を追加。デフォルトでも使用可能。

import {addParameters} from "@storybook/vue";
import {INITIAL_VIEWPORTS} from "@storybook/addon-viewport";

addParameters({
    viewport: {
        viewports: INITIAL_VIEWPORTS
    }
});

動作確認

FireShot Capture 120 - Button - buttons ⋅ Storybook - localhost.png

storybook-readme

npm i storybook-readme --save-dev

{project_root}/.storybook/main.js にアドオン登録

module.exports = {
    stories: ['../src/**/*.stories.[tj]s'],
    addons: [
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
        '@storybook/addon-storysource',
        '@storybook/addon-viewport',
        'storybook-readme',
    ]
};

{project_root}/.storybook/preview.js に設定を追加。

import {addDecorator, addParameters} from "@storybook/vue";
import {INITIAL_VIEWPORTS} from "@storybook/addon-viewport";
import {addReadme} from 'storybook-readme/vue';

addParameters({
    viewport: {
        viewports: INITIAL_VIEWPORTS
    }
});

addDecorator(addReadme);

{project_root}/src/components/atoms/Button/Button.stories.js を書き換え。

import {storiesOf} from '@storybook/vue';
import ButtonReadme from './README.md';
import BaseButton from './BaseButton';
import {action} from '@storybook/addon-actions';
import {text} from '@storybook/addon-knobs';

storiesOf('Button', module)
  .addParameters({
    readme: {
      sidebar: ButtonReadme
    }
  })
  .add('buttons', () => ({
    components: {BaseButton},
    props: {
      buttonLabel: {
        default: text('label', 'button')
      },
    },
    template: '<div>' +
        '<base-button @click="action">{{ buttonLabel }}</base-button>' +
        '</div>',
    methods: {
      action: action('clicked')
    }
  }));

{project_root}/src/components/atoms/Button/README.md を追加。

# Usage🛠

動作確認

スクリーンショット 2021-02-17 16.25.38.png

その他設定はご自由に

  • @babel/core
  • vue-svg-loader
  • @fortawesome/fontawesome-free
  • bootstrap

のようなプロジェクトの要件などに関わるパッケージなどはご自由にインストールして下さい。

最後に

ほぼ、私のメモの用に書いてみました。

「こうしたほうがいいよ」とか、「ここ間違ってるくない?」とかあるかもしれませんが、その辺は自身の環境に合わせて設定を変えていただければと思います。

特にコンポーネントのパッケージ化についてはインストールする側がVueを利用していることを前提にしているので、使いにくいところがあるかもしれません。
CDN化やpure jsの対応はそのうちしておきたいなとは思っています。

個人的にはフレームワーク依存したくない(Vue / ReactのようなFWを除く)ので、それ単体で動く環境をCLIなどなしで構築できるようになっているはずです。

みなさんの役に立てれば幸いです。

React記事書こうとしていましたが、Storybookのまとめしてなかったなぁと思ったのでこちらを優先しました。Nuxtの案件も近いのでついでに...といった感じ。

Nuxtについてもそのうち書きたい。

そのときはよしなに。

.

のん

所属 : 株式会社スマレジ 開発部

YouTube : のんラボ

Twitter : @nonz250

Github : nonz250

Qiita : @nonz250

My Qiita posts My Qiita contributions My Qiita followers

主にPHPを使用し、サーバーサイドを担当。最近はフロントにも興味津々。

なにかを作ったりいじったりするのが好きで、個人開発なども行っている。

趣味はバイクアイコン画像は大抵愛車の「Z250」である。友達にアイコン描いてもらえて嬉しい。

PHP / Laravel / CakePHP2 / CakePHP3 / Vue / Nuxt / C# / etc...

Tags

#のんラボ #Laravel #Vue #個人開発 #ブログ #プログラミング #javascript #Html5 #WEBサービス #Twitter #今年の抱負メーカー #勉強方法 #PWA #モバイルアプリ #Android #ツーリング #バイクに乗るエンジニア #Z250 #秋吉台 #能登半島 #バイク #冒険 #東尋坊 #Squid #リバースプロキシ #hosts #axios #cropper #AdSense #Bootstrap #MySQL #高速化 #トドTask #Telescope #デバッグ #composer #テスト #セキュリティ #POSレジ #スマレジ #本部機能 #バリデーション #入力チェック #Mac #Chrome #テスト駆動開発 #開発手法 #UI #デザイン #WEBサイト #機能美 #PHP #Laravel 6 #コメント #バージョンアップ #vue-cli #localhost #BIツール #売上分析 #TANAX #MFK250 #ツアーシェルケース2 #RESTful #API #REST API #実務的 #PHP Tech Tutor #Smaregi Tech Talk #勉強会 # ブログ #CakePHP3 #CSRF #VSCode #開発環境 #CakePHP3.0 #さくらのレンタルサーバー #モジュールモード #シェル #メール #Gmail #relay #OGP #エラーページ #抱負 #家庭教師 #ドメイン駆動設計 #DDD #読書会 #那智の滝 #伊勢志摩 #伊勢志摩スカイライン #フロント #三方五湖 #レインボーライン #ボーイスカウト・ルール #プログラマが知るべき97のこと #リファクタリング #ユビキタス言語 #車輪の再発明 #マイクロサービス #デプロイ #QA #laravel-mix #Tips #storybook #@storybook/addon-actions #昇降デスク #コードレス #書斎 #オフィス #リモートワーク #働き方 #エラーハンドリング #スマレジ4 #pixel 5 #レビュー #スマレコ #TDD #RSS #404 #高山ダム #ラーツー #React #Nuxt #node_modules #エラー #インポート #設定方法 #環境構築 #Docker #フォレストパーク神野山