NuxtにStorybookを導入する 〜環境構築から使い方、Amplifyデプロイまで〜
ハコザキです。
今回は、NuxtプロジェクトにStorybookの導入、基本的な使い方、Amplifyへの自動デプロイまでをご紹介します!
はじめに
Storybookとはコンポーネントの見た目・挙動を開発環境を立ち上げることなく確認できる コンポーネントライブラリツールです。
カタログのような見た目で共有できるのでデザイナーの方とのやりとりも容易になります。
Storybookの詳しいメリットなどについては、こちらで詳しく説明がされてました..!
今回は3つに分けて解説していきたいと思います!
- Nuxt.jsプロジェクトにStorybookを導入、共通設定
- コンポーネントごとのストーリーの定義
- Amplifyを用いての自動デプロイ、Basic認証
Nuxt.jsプロジェクトの新規作成についてはこちら
※今回のNuxt.jsのバージョンは 2.15.3
です
準備
このようなlist-itemの簡素なサンプルコンポーネントを用意しました。

~/components/MediaList.vue
<template>
<ul class="list">
<li v-for="(item, index) in list" :key="index" class="list_item">
<media :content="item" />
</li>
</ul>
</template>
<script lang="ts">
import Vue from 'vue'
import Media, { Title } from '~/components/Media.vue'
type DataType = {
list: Title[]
}
export default Vue.extend({
components: {
Media,
},
data(): DataType {
return {
list: ['テスト1', 'テスト2', 'テスト3'],
}
},
})
</script>
<style lang="scss" scoped>
.list {
&_item {
& + & {
margin-top: 24px;
}
}
}
</style>
~/components/Media.vue
<template>
<h2>{{ value }}</h2>
</template>
<script lang="ts">
import Vue, { PropType } from 'vue'
export type Title = String
export default Vue.extend({
props: {
content: {
type: String as PropType<Title>,
default: '',
required: true,
},
},
computed: {
value(): String {
return this.content !== '' ? this.content : 'タイトル'
},
},
})
</script>
Storybookの導入・共通設定
nuxt-communityからリリースされた nuxtjs/storybook
を利用して進めていきます。
Storybookのインストール後に必要だった諸々の設定をnuxt.config.jsで書くようになり、 導入の敷居が低くなりました。
インストール
# yarn
yarn add --dev @nuxtjs/storybook postcss@latest
or
# npm
npm install --save-dev @nuxtjs/storybook postcss@latest
TypeScriptを導入している場合は ts-node
もインストールします。
yarn add --dev ts-node
or
npm install --save-dev ts-node
.gitignoreに下記を追記して追跡対象から除外します。
.nuxt-storybook
storybook-static
storybookを開くポート番号の指定やサードパーティのアドオンなどのオプションを追加する場合は nuxt.config.js
に追記します。
// 追記箇所のみ記載
export default {
...
storybook: {
// 追加のアドオンなどあれば
addons: [
'@storybook/addon-controls',
'@storybook/addon-notes',
],
// ポート指定
port: 5555,
// ストーリーの親に要素など追加しcssなど設定できる
decorators: [
'<div style="max-width: 〇〇px;"><story/></div>'
],
// 背景色や表示位置、デバイスの設定など
parameters: {
// 背景色:デフォルトの色を使う場合
backgrounds: {
default: 'dark', // light or dark
},
// 背景色:カスタマイズする場合
backgrounds: {
default: 'brown',
values: [
{
name: 'brown',
value: '#56371B'
},
{
name: 'light',
value: '#fff'
},
{
name: 'dark',
value: '#333'
},
]
},
// Description, Default, Controlsカラムの表示
controls: {
expanded: true
},
// 表示位置
layout: 'centered', // centered:中央表示, padded:コンポーネントに余白付与, fullscreen:幅いっぱい
}
}
}
起動方法
下記コマンドでStorybookを起動します。
# 起動
yarn nuxt storybook
ターミナル上にこのように表示されればokです。
上は自分のPCのみ確認できるURL、下は同一ネットワークで確認できるURLとなってます。

表示されているURLアクセスし管理画面が表示されれば起動は成功です!

↑まだなにも登録されていないので空の状態です!
使い方
***.stories.js
を作成することで、カタログにコンポーネントを登録することができます
今回は2つのコンポーネントをサンプルで作りました。
私は storybook
内に***.stories.js
を入れて一括で管理してますが、同階層で管理する方もいると思います。ここはわかりやすい方で構いません。
components/
storybook/
Media.stories.js
MediaList.stories.js
Media.vue
MediaList.vue
先程作った2つのコンポーネントに対するストーリーの定義はこちらです。
~/components/storybook/MediaList.stories.js
export default {
title: 'Media',
component: 'MediaList',
argTypes: {},
}
// exportすることでコンポーネントを登録
export const MediaList = (arg, { argTypes }) => ({
props: Object.keys(argTypes),
template: `
<MediaList />`,
})
~/components/storybook/Media.stories.js
export default {
title: 'Media', // 左袖の分類名 Media/〇〇 のように階層化も可能
component: 'Media',
argTypes: {
content: {
description: 'テキスト<br />空の場合は`タイトル`が表示される', // Descriptionに表示するテキスト
control: {
type: 'text', // number | range | array | object などがある
},
type: {
name: 'string',
required: true, // true時、Name部分のプロパティ右側に * が表示
},
defaultValue: 'テストテキスト', // 初期値
table: {
type: {
summary: 'string', // Descriptionに表示される型注釈
},
defaultValue: {
summary: 'タイトル', // Defaultに表示
},
},
},
},
}
export const Media = (arg, { argTypes }) => ({
props: Object.keys(argTypes),
template: `
<Media :content="$props.content" />`,
})
このようにStorybook内でテキストなど色々変えてテストもできます。

この他にも、つまみ のようなコントロールバーで自由に数値を変えることができる range
やtrue/falseを切り替えることができる boolean
などがあります。
詳しくは公式を参照してみてください。
range
の例
...
argTypes: {
count: {
description: '件数',
control: {
type: 'range',
min: 0,
max: 1000,
step: 1,
},
type: {
name: 'number',
required: true,
},
defaultValue: 100,
table: {
type: {
summary: 'number',
},
defaultValue: {
summary: '',
},
},
},
},
...

補足:parametersの優先度について
上から反映の優先度が高くなるので 背景色などが反映されない方はこちらを見直してみてください。
ストーリーのパラメータ
〇〇〇.parameters= {
...
}
コンポーネントのパラメータ
export default {
parameters: {
...
}
}
グローバルパラメータ
// nuxt.config.js
export default {
...
storybook: {
parameters: {
...
}
}
...
}
Amplifyでの自動デプロイについて
自動デプロイのホスティング先にはAWSのAmplifyというサービスを使いたいと思います。
GitHubでソース管理しており、AWSのアカウントを作成 → コンソールにログインできる状態にします。
サービスの Amplify→ 右上のNew app → Host web app を選択

GitHubを選択し、Continueをクリック

GitHubと連携し、対象のリポジトリとフックとなるブランチを選択します。

アプリの名称は任意のもので大丈夫です。
ビルド設定のymlを編集するため、Editを選択します。

下記のように build
と artifacts
周りを編集します。
編集が完了したら次へを選択します。
変更前
version: 1
frontend:
phases:
preBuild:
commands:
- yarn install
build:
commands:
- yarn run build
artifacts:
# IMPORTANT - Please verify your build output directory
baseDirectory: /
files:
- '**/*'
cache:
paths:
- node_modules/**/*
変更後
version: 1
frontend:
phases:
preBuild:
commands:
- yarn install
build:
commands:
- yarn nuxt storybook build
artifacts:
# IMPORTANT - Please verify your build output directory
baseDirectory: /storybook-static
files:
- '**/*'
cache:
paths:
- node_modules/**/*
確認画面が表示されるので連携するリポジトリやアプリの名称などを確認し、 問題なさそうであれば「保存してデプロイ」を選択します。
これで基本的な設定は完了です!
しばらくするとビルド→デプロイが完了し、画像部分のドメインに記載されているURLをクリックするとStorybookがホスティングされていることが確認できると思います!!
次回以降は先程設定したブランチのソースがマージなどで変更された時点で アプリのビルド → デプロイが自動でされるのでとても便利です。

これでチーム間で共有できる状態になったのですが、追加で下記の対応を行います。
- 誰でも見れる状態にあるのでベーシック認証をかける
ベーシック認証をかける
左袖のメニュー → アクセスコントロールをクリック
Access setting を「制限 – パスワードが必須です」に変更し、username、passwordを入力 → Save でokです。

まとめ
nuxt-storybook
のおかげで導入しやすくなったStorybookですが、まだまだ拡張できると思うので公式などを参考に色々試してみてください!