Storybook for Vueでエンジニアとデザイナーの協業を加速させる
この記事はCAMPHOR- Advent Calendar 2017の23日目の記事です。
はじめに
アプリケーションの機能を「カプセル化」、「コンポーネント化」しようというのは、フロントエンド/バックエンド問わずに近年のWeb開発におけるトレンドのひとつです。
Web業界も5年もの、10年ものと呼ばれるシステムが増える中で「最初から完璧なシステムを作ることなんて無理なんじゃないか」と多くの人が気づきはじめました。 その流れを受けて「どうせ改修が必要なら、小さなスコープで新しいものに置き換え可能な仕組みを作ろうぜ!」というのが「カプセル化」、「コンポーネント化」の大きなモチベーションであると、個人的には理解しています。
Vue.jsとコンポーネント
JavaScriptのフレームワークであるVue.jsも、例に漏れずコンポーネントドリブンな開発に適した仕組みの1つです。
SFC(Single File Component)として知られる .vue
ファイルに template
や script
を切り離せるだけでなく、 Scoped CSS
の仕組みを用いてスタイリングでさえ1つのコンポーネントに限定して適用できるなど、非常に再利用性の高いコンポーネント設計が行えて重宝しています。
またVue.jsの大きな特徴として、既存のHTMLとさほど変わらないシンタックスでコンポーネントが記述できるという点が挙げられます(もちろんJSXで記述することもできます)。HTMLやCSSについての基本を抑えていればJSが苦手なWebデザイナーさんにも作成・改修依頼が投げられるというのは、常に人材不足に泣かされる中小Web制作会社としては非常にありがたいですね!
今回紹介するSrotybook for Vueは、そんな現場レベルでデザイナーさんとフロントエンドエンジニアの協業を加速させるためのツールです。
Storybookとは
Storybookとは、iframeを用いたサンドボックス上でコンポーネントの挙動をチェックできるUI開発環境です。ただのテストツールとしてではなく、スタイルガイドとしての利用も想定されているため、エンジニアだけでなくデザイナーさんにも役立つツールとして期待されています。
StorybookはもともとReactユーザー向けのツールでしたが、 v3.2.0
からVueもサポートされ、現在はReact Native Webにも対応しました。
事例諸々
公式ページより様々な企業の導入事例を見ることができます。
https://storybook.js.org/examples/
各社ユニークなStorybookを用意していて眺めているだけで面白いです。会社の顔にもなるようなスタイルガイドを簡単に作れるなんてワクワクしますね。
今回はこのStorybookの導入 → Storyと呼ばれるStorybook内のページにVueコンポーネントを追加するまで、の流れを追っていきたいと思います。
本記事の対象
- ES6分かるマン/ウーマン
- Vue.jsなんとなく分かるマン/ウーマン
- Storybookにとりあえず興味あるマン/ウーマン
本記事のゴール
いつも前置きが長く申し訳ないですが、本記事は以下のことを目的として書かれています
- Storybookの概要を知ってもらう
- 「Storybook、意外とカンタンやん!」と思ってもらう
- 社内で投入する前に個人的に試した内容の作業ログを残したい
まぁ、ほとんど3つ目がメインです。それでは上記を踏まえた上で早速Storybookを動かしてみましょう。
Storybookを導入する
まずはvue-cliでアプリを作成
$ vue init webpack sample // console上で対話しながらアプリケーションを作成 $ cd sample $ yarn $ yarn run dev
Storyobookの公式ページにはQuick start guideの他に、Slow start guideというページが用意されているので今回はそちらを参考にします。
$ yarn add -D @storybook/vue // devDependenciesにstorybookを追加
Yarn scriptに起動コマンドを記述
{ "scripts": { "storybook": "start-storybook -p 9001 -c .storybook" } }
.storybook/config.js
に設定を記述
import { configure } from '@storybook/vue' // ストーリーの読み込み function loadStories() { require('../src/stories') } configure(loadStories, module)
読み込むStoryを作成する前に、ボタンを表示するコンポーネントを雑に用意します
<template> <button>Hello Vue</button> </template> <style scoped> button { color: green; border-radius: 5px; font-size: 18px; line-height: 1.5; padding: 0 10px; } </style>
// src/stories/index.js import { storiesOf } from '@storybook/vue' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .add('simple', () => ({ components: { MyButton }, template: '<MyButton/>' }))
Yarn scriptで Storybook
を起動
yarn storybook
ブラウザで localhost:9001
にアクセスしてStorybookが表示されていることを確認します
無事にコンポーネントがiframe上に描画されました。
またWebpackのHMR(Hot Module Replacement)が有効になっているので、コンポーネントファイルを編集すると変更が動的に反映されることが確認できます。
Addonsを使う
このままでは少し寂しいのでStorybookにAddonsを追加して機能や見た目を拡張していきましょう
Storybook Addon Actions
Storybook Addon Actions
はイベントハンドラから渡ってきたデータの確認やロギングができるAddonです。
Yarnでインストール
$ yarn add -D @storybook/addon-actions
新しくAddonsを追加する際は .storybook/addons.js
に追記する必要があります
// .storybook/addons.js import '@storybook/addon-actions/register'
Addonから action
関数をimportして、ボタンの onClick
イベントと紐づけてみます
import { storiesOf } from '@storybook/vue' import { action } from '@storybook/addon-actions' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .add('simple', () => ({ components: { MyButton }, template: '<MyButton @click.native="action"/>', methods: { action: action('button-clicked') }, }))
コンポーネントの @click
に対して .native
修飾子をつけると、root要素のイベントを監視できるんですね。初めて知りました。
上記のコードを確認してみます
Storybook内に「ACTION LOGGER」というパネルが表示され、コンポーネントのイベントにフックしたログが表示されるようになりました。これを活用すると、より細かくコンポーネントの挙動を確認することができますね!
storybook-addon-vue-info
storybook-addon-vue-info
は、コンポーネント情報の表示を改善してくれるAddonです
Yarnでインストール
$ yarn add -D storybook-addon-vue-info
Exampleを参考に decorator
として実装
import { storiesOf } from '@storybook/vue' import { action } from '@storybook/addon-actions' import VueInfoAddon from 'storybook-addon-vue-info' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .addDecorator(VueInfoAddon) .add('simple', () => ({ components: { MyButton }, template: '<MyButton @click.native="action"/>', methods: { action: action('button-clicked') }, }))
ついでに MyButton.vue
も少し改修
<template> <button>{{ text }}</button> </template> <script> export default { props: { text: { type: String, default: 'Hello Vue' } } } </script>
props
でボタンに表示するテキストを受け取るようにしました。デフォルトは "Hello Vue"にしています。この状態で表示チェック
このように、 decorator
をつけたStory内のコンポーネントについての使用例とコンポーネントの持つことができるprops等が体系的に表示されました!
お手軽便利系のAddonです。
Knobs
GUIからコンポーネントの持つプロパティの情報を更新できるAddonです。
Yarnでインストール
$ yarn add -D @storybook/addon-knobs
addons.js
に追記
import '@storybook/addon-knobs/register'
decolator
としてStoryに追加します。今回は props
として label
と backgroundColor
を受け取る ButtonWarning
コンポーネントを用意しました
import { storiesOf } from '@storybook/react' import { withKnobs, text, color } from '@storybook/addon-knobs' import ButtonWarning from '@/js/components/ButtonWarning' ... storiesOf('Buttons', module) .addDecorator(withKnobs) .add('warning', () => { const label = text('Label', 'Warning') const backgroundColor = color('Color', '#ffffff') return { components: { ButtonWarning }, template: `<ButtonWarning label="${label}" backgroundColor="${backgroundColor}" />` } })
text()
, color()
という関数を利用することで、それぞれの値に対する input
フォームのようなUIが表示されるようになります
色の調整や文字列の変更が誰でもできるようになって最高 :clap::clap:
Links
Story内から別のStoryを表示する(遷移する)ためのAddon。
詳細は割愛
その他のAddon
基本的にUIをスッキリさせる系のAddonsが多い印象ですが、今回は全て試せませんでした。公式にGalleryが用意されているので、興味のある方は以下のリンクからご確認ください。痒いところに手がとどくAddonが見つかるかもしれません
https://storybook.js.org/addons/addon-gallery/
実際に使ってみた
手元にあったコンポーネントを突っ込んで作成したStorybookがこちらになります
デザイナーはすぐに見た目のレビューができるし、エンジニアはデザインの変更を差分で管理できるしで、なかなか幸せな世界に近づいたのではないでしょうか
まとめ
Storybook本体のVue.js対応が行われたばかりということもありまだVue.jsに対応していないAddonsが多いようですが、スタイルガイドとしては必要十分な仕組みが備わっているように感じました。
最初の設定はクセがありますが、一度導入してしまえば機械的にコンポーネントを追加していくだけなので中規模以上のSaasを運用するケース、受託案件を小さく大量に回すケース、どちらでも活用できるのではと思います。
社内での本格的な実践投入はこれからですが、再利用可能なコード資産が1つでも多く残せるよう時間をかけて育てていきたいです。
明日はohmurakenの記事です。お楽しみに!