MENU

Vue.js環境で、Storybookをつかってみる。

Vue.js環境で、Storybookをつかってみる

最近、システム開発のフロント側を担当することが増えてきて、毎回コンポーネント設計に悩まされます。
また、チームで開発するときに、どのように運用していくのがいいのか探していると、Storybookの導入をしている記事を見つけて、今回試してみることにしました。
まだまだ手探り状態ですが、自分自身でさえ時間がたつとどうやって設計したっけ?となるので、自分のためにもよいツールだと思いました!

導入の備忘録として、残しているので、参考になればうれしいです。

CONTENTS

開発環境

それぞれのバージョンはこちらです。

  • Vue.js 3.5
  • Storybook 8.4

下記でgitを上げているので、よければ参考にしてください。

GitHub
GitHub - eddymafin/vue-storybook Contribute to eddymafin/vue-storybook development by creating an account on GitHub.

Storybookをインストール

今回、Vueを使用した環境で、Storybookを導入しました。vueのプロジェクト作成は割愛します。

下記が、vueのプロジェクト作成から、Storybookの導入まで記述しているので、今回参考にさせていただきました!

株式会社ライトコード
Vue.js開発におけるStorybookの導入 - 株式会社ライトコード Storybookとは?「Storybook」とは、UIコンポーネントの開発を手助けするオープンソースツー

公式サイトでは、下記のコマンドで導入とあります。サンプル用のコードも導入されるので、ありがたいです。

proceedしますか?と聞かれるので、yで進める。関連ファイルがインストールされ、同時に立ち上げもしてくれます。

npx storybook@latest init
Storybook
Docs | Storybook Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It...

いろいろと案内が進行したあと、このような画面になります。最初は使い勝手がよくわからなかったので、サンプルのコードを見ながらいろいろと調整していきました。

ちなみにstorybook立ち上げたいときのコマンドは、こちら。

npm run storybook

Vueのプロジェクトファイル構成、コンポーネントの構成

今回、管理者、ユーザー、編集者というような、3パターンのroleがあり、それぞれ構成は似ているが、色や一部ナビなどの構成が異なるというような構成のシステムでした。

そのため、コンポーネントの構成をどうしようか悩み、いろいろな方の記事を参考にして、独自の構成にすることにしました。

今回はモックの作成のため、バックサイドの処理を気にせず構築しました。そのため、見た目だけの構築をメインにしたコンポーネント設計です。

そのときに参考にした記事はこちら

MicroAd Developers Blog
Vue.jsでのコンポーネント設計を社内標準化してみた話 - MicroAd Developers Blog はじめに システム開発部フロントエンドエンジニアの工藤です。 マイクロアドの WEB アプリケーションのフロントエンドは、大半を Vue.js を用いて開発しています。 以前、...
Component構成

components
ーicons
ーparts(ボタンなど最小のコンポーネント)
ーtemplates(partsを組み合わせて作りたいもの)
ーviews(viewごとで固有のコンポーネント)

さらにviewの構成は下記で、vue-routerを使用して、viewのディレクトリごとに表示させるようにしました。

vue-routerは、初期インストール時にvue-routerのインストールをするか聞かれるので、手軽に導入できます。

Viteのimport.meta.glob関数というのを使用して、vueのパスが動的に出力されるようにしました。

vitejs
特徴 次世代フロントエンドツール

下記のように記述しました。

import { createRouter, createWebHistory } from 'vue-router'
const adminRoutes = Object.entries(import.meta.glob('../views/admin/*.vue')).map(
  ([path, component]) => {
    const name = path.match(/\/admin\/(.+)\.vue$/)[1]
    return {
      path: `/admin/${name.toLowerCase()}`,
      name: `Admin${name}`,
      component,
    }
  },
)
const userRoutes = Object.entries(import.meta.glob('../views/user/*.vue')).map(
  ([path, component]) => {
    const name = path.match(/\/user\/(.+)\.vue$/)[1]
    return {
      path: `/user/${name.toLowerCase()}`,
      name: `user${name}`,
      component,
    }
  },
)
const editorRoutes = Object.entries(import.meta.glob('../views/editor/*.vue')).map(
  ([path, component]) => {
    const name = path.match(/\/editor\/(.+)\.vue$/)[1]
    return {
      path: `/editor/${name.toLowerCase()}`,
      name: `editor${name}`,
      component,
    }
  },
)

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [...adminRoutes, ...userRoutes, ...editorRoutes],
})

export default router

こうすると、トップは何も表示されなくなります。。
App.vueは、下記のように<RouterView />でviews以下ファイルで作成していくようにします。

<script setup>
import { RouterView } from 'vue-router'
</script>

<template>
  <div>
    <RouterView />
  </div>
</template>

スタイルを適応する

今回は、tailwindではなく、cssを記述して運用する方式を検討していました。

なので、共通のスタイルはcssを、コンポーネント単位で、スタイルを記述していくという方法にしました。

Qiita
Vue.js ✕ CSS Modules のコンポーネントのつくり方 - Qiita さいきん流行りのコンポーネント化をすすめるにあたり、弊社(ビザスク)では Vue.js ✕ CSS Modules を採用しています。これをマークアップするのがちょっと難しかったので...

また、storybookでもcssの適応が必要なのですが、importする場所は、.storybookディレクトリ以下のpreview.jsに記述が必要です。

/** @type { import('@storybook/vue3').Preview } */
import '../src/assets/main.css'
const preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
}

export default preview

Story作成してみる

storyディレクトリ以下に、.stories.jsの拡張子のファイルを作成します。

サンプルのコードは、vueのファイルもstoriesディレクトリ以下に入れているんですが、vueのcomponentsディレクトリ以下に配置して、imoprtをして、使用しています。

こんな感じです。

onClickの箇所は、まだ検証中でまだどんなことができるか、とりあえずおいています。

// import { fn } from '@storybook/test'
import Button from '@/components/parts/Button.vue'

export default {
  title: 'Parts/Button',
  component: Button,
  // args: { onClick: fn() },
  tags: ['autodocs'],
}

export const Default = {
  args: {
    border: false,
    label: 'ボタン',
  },
}

export const Border = {
  args: {
    border: true,
    label: 'ボタン',
  },
}

下記のように、表示されるようになります。

まず、Vueのファイルをimportして、componentに指定をします。
titleにいれた構造で、表示されます。

また、tags:[‘autodocs’]と設定することで、Docsというページが生成されます。

import Button from '@/components/parts/Button.vue'

export default {
  title: 'Parts/Button',
  component: Button,
  // args: { onClick: fn() },
  tags: ['autodocs'],
}

下記が、Buttonの記述なんですが、propsなどを検知して、Docsに出力してくれます。便利ですね!

<script setup>
const props = defineProps({
  label: {
    type: String,
    required: true,
  },
  border: {
    type: Boolean,
    default: false,
  },
})
</script>
<template>
  <button type="button" :class="['c-button', props.border ? `is-border` : '']" @click="onClick">
    {{ props.label }}
  </button>
</template>
<style lang="scss">
.c-button {
  color: #fff;
  background: #4b4b4b;
  border-radius: 6px;
  padding: 14px;
  font-size: 18px;
  font-weight: bold;
  min-width: 218px;

  &.is-border {
    color: #000;
    border: 1px solid #000;
    background: #fff;
  }
}
</style>

また、下記で設定することで、どんなpropsを渡したら、どんな表示になるか、表示させておくことができます。詳しくは実際に触ってみたほうがわかりやすいと思います。

export const Default = {
  args: {
    border: false,
    label: 'ボタン',
  },
}

export const Border = {
  args: {
    border: true,
    label: 'ボタン',
  },
}

gitにファイルをアップしているので、よければ参考にしてください。

GitHub
GitHub - eddymafin/vue-storybook Contribute to eddymafin/vue-storybook development by creating an account on GitHub.

まとめ

システム構築をしていると、propsが何でわたってきているのか、このコンポーネントはどんな構成になっているのか、構築してしばらく立つと忘れたりとかするので、Storybookでまとめておくと、とても便利だと思いました!

またチームで開発の際も、コンポーネントを再利用をして構築できると思うので、次の案件で導入したいと思いました。

Vue.js環境で、Storybookをつかってみる

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
CONTENTS