はじめに
初めまして。
WELLNESONE JAPAN株式会社(株式準備中)代表取締役CTOの@yusuke_1011です。
自社で一からサービス開発を行う際に実践した構成をここに記しておきます。
こちらの記事は、「Nuxt + Docker + CIrcleCI + Storybookという構成でAtomic Designにて開発していく」の第2章となります。
一般的な内容も多くありますが、説明用のサンプルではなく、実際にプロジェクトで導入した内容にはなるので、オリジナルな部分もある程度含んでしまいます。その点ご了承くださいませ。
全体構成
「Nuxt + Docker + CIrcleCI + Storybookという構成でAtomic Designにて開発していく」
- Nuxtの開発環境をDockerで構築
- NuxtでAtomic Designを実践(←今ここ)
- Nuxt + Storybookでコンポーネントを管理
- Storybookを用いたテスト(ストラクチャルリグレッションテスト編)
- Storybookを用いたテスト(ビジュアルリグレッションテスト編)
前提
- Atomic Designの概念を理解できている
- Nuxtで開発環境の構築ができている
- Nuxtのプロジェクト構成、各ディレクトリの意味が理解できている
NuxtとAtomic Design
Atomic Designではコンポーネントを以下のように分割します。
- Atoms
- Molecules
- Organisms
- Templates
- Pages
皆さんご存知の通り、Nuxtにもデフォルトでpagesディレクトリが存在します。
ただ、Atomic DesignのpagesとNuxtのpagesは同じ意味にはなりません。
Nuxtのlayouts + pagesがAtomic Designのpagesのような感覚になります。
(これも厳密には違いますが。。)
ですので、後述の通り、本プロジェクトではディレクトリ構成を純粋なAtomic Designとは少し変更することにしてあります。
VuexとAtomic Design
では、どのコンポーネントがVuexを意識するのが良いのでしょうか。
基本的にはpagesのみがVuexを意識し、他はすべてpropsで値を受け渡すという意見が多いかと思います。
ただ、そうすると、かなり記述が冗長になってしまうことが難点だと思います。
ディレクトリ構成
以上を踏まえ、本プロジェクトでは以下のようなディレクトリ構成にしました。
src
└── components
└── atoms
└── molecules
└── organisms
└── layouts
└── pages
賛否両論あるかとは思いますが、templatesを廃止しています。
components内のコンポーネントは
- vuexやrouterなどの存在を知らないし、依存もしない
- propsで受け取った値を表示させる
- emitで親要素にコールバック関数を受け渡す
という運用になります。
例えば、atomsであれば、button.vueのような最小単位のコンポーネントを格納しますが、コード例としては以下です。
<template>
<button
:shadow="shadow"
:lighten="lighten"
:disabled="disabled"
:class="[
'btn',
'btn-size-' + size,
'btn-type-' + type,
'btn-color-' + color,
'btn-align-' + align
]"
@click="clickHandler"
>
<span :class="['btn-text', 'btn-font-' + font]">
<slot>
<span v-if="iconLeft">
<font-awesome-icon :icon="iconLeft" class="fa-fw" />
</span>
<span v-if="btnText">{{ btnText }}</span>
<span v-if="iconRight">
<font-awesome-icon :icon="iconRight" class="fa-fw"/>
</span>
</slot>
</span>
</button>
</template>
<script>
export default {
props: {
shadow: Boolean,
lighten: Boolean,
disabled: Boolean,
size: String,
type: String,
color: String,
align: String,
font: String,
iconLeft: Array,
iconRight: Array,
btnText: String
},
methods: {
clickHandler(e) {
if (this.disabled) {
return;
}
this.$emit("click", e);
}
}
}
</script>
(styleの部分は省略しています)
Storybookによるコンポーネント管理
Atomic Designを実践する上では、コンポーネントのカタログを作りたくなってきます。
これにStorybookを使用します。
storybookは
- React
- Vue
- Anguler
で幅広く使用できるコンポーネント開発環境です。
元々はスリランカのスタートアップがReact用に開発したらしいです。
Storybookを使用することで、プロダクトと切り離した環境でコンポーネントを開発できるので非常に便利です。
また、コンポーネントのテストにも活躍します。
こちらの導入に関しては、また次節でご説明します。