Nuxt.jsにおけるAtomic Designを考える

みなさま、こんばんみ。ブロックチェーン事業部の城市と申します。
フロントエンドエンジニアとして、主にNuxt.js/TypeScript/Atomic Designを用いて開発を行っています。

Atomic Designを導入することになった経緯については【去年のAdventCalendar】で書きました。そして、Atomic Designを用いたComponent設計については現在でも手探りでやっている状況です。
そこで今回はNuxt.jsにおけるAtomic Designについて、向き合った結果をまとめたいと思います。


Atomic Designとは

Brad Frost氏が考案・提唱したDesignの設計手法のことです。詳細は【氏のWEBサイト】に記載されています。

解説はググれば各所に記載されているので省きますが、ざっくりいうと画面を構成する要素を、Atoms、Molecules、Organisms、Templates、Pagesの5つのレイヤーに分けることで再利用可能なデザインパターンを構築するというものです。

Nuxt.jsにおけるAtomic Design

まずは適用

Atoms、Molecules、Organisms、Templates、PagesをNuxtのレイヤーに適用すると

Nuxt Atomic Design
pages Pages
layouts Templates
components Atoms / Molecules / Organisms

だいたい上記のようになるのですが、この中でcomponentsはAtoms / Molecules / Organismsを内包するため各レイヤー名でフォルダを切って運用します。

├ components
│ ├ atoms
│ ├ molecules
│ ├ organisms

というわけでNuxtにAtomic Designの考えを適用できました。
これであなたもAtomic Designマスター。フェーズでいうと完全に理解したくらい。

Componentを設計する

さてとりあえずNuxtでAtomic Designを運用できるようになったわけですが、最初にぶつかるのはなにがどのレイヤーかわからんというやつです。(まあ最後までずっとそうだと思うんですけど)
ここで、Atomic Designの定義(?)に立ち返りましょう。

  • Atoms
    原子……つまりそれ以上分解できない最小の単位です。
    分解できない最小単位ということでHTMLタグ一つ一つに当てはめるのがいいかと思います。button も input も h1 や img もAtomsです。Atomic DesignはとりあえずAtomsから始めるようにできています。

  • Molecules
    読み方がわからない。多分もらきゅるず 分子くんです。この辺まではわかりやすい。Atomsの集合体です。Atomsが複数あればほぼこれです。
    だいたい2-3個のAtoms集合体ですがそれ以上になって意味を持つとOrganismsに進化します。
    よく使うのはLabel+Inputとか検索結果プレートとかそういうのですかね。 f:id:j1-ryu:20200322192753p:plain

  • Organisms
    生体です(とは?)。ついに生命が生まれました。
    Moleculesの集合体です。Moleculesを利用しているやつはこれです。
    もしくは意味のある塊です。とくにビジネスロジックとか機能を内包しちゃったやつですね。 だいたいページを構成する要素を意味のある領域単位で分割していく感じにしています。
    f:id:j1-ryu:20200322194335p:plain

そろそろ何もわからなくなってきました。成長しています。 特にファイルが増えてくると余計わからなくなっていきます。フォルダを分けましょう。

├ components
│ ├ atoms
| | ├ buttons
| | | ├ Action.vue 
| | ├ images
| | | ├ Logo.vue
| | | ├ Thumbnail.vue
| | ├ inputs
| | | ├ Text.vue
| | | ├ Number.vue
| | ├ ︙
| | ├ ︙
│ ├ molecules
| | ├ forms
| | | ├ LabeledInputNumber.vue
| | | ├ LabeledRadioButton.vue
| | ├ images
| | | ├ Rectangle.vue
| | | ├ Swiper.vue
| | ├ menus
| | | ├ Item.vue
| | ├ ︙
| | ├ ︙
│ ├ organisms
| | ├ modals
| | | ├ Slot.vue
| | | ├ Message.vue
| | ├ mypages
| | | ├ Tab.vue
| | ├ forms
| | | ├ Search.vue
| | ├ ︙
| | ├ ︙

こんな感じ。Atomsは基本タグ名でフォルダを切るといいと思います。sつけるかはお好みで。
Atoms/Molecules/Organisms画像についてはAtomic Designテンプレートを利用して作成しました。 www.sketchappsources.com


ハマった / めんどくさいポイント

Emit/Propバケツリレーなんだけど?

そうだよ(肯定)
バケツリレーはAtomic Designの宿命です。 たぶん
Molecules/Atomsは基本イベント発火で済ませる(外部データアクセスをしない)のが一般的かと思いますのでそうなります。 EmitのEmitとかしてるとわけわかんなくなりますし、ラジオボタンの選択状態とかバケツリレーするとうまく動いてくれなくてキレそうになったりしますね。
バケツリレーを回避したければStoreに持つ事になりますが、そうなると今度はStoreの設計どうするんだってNuxtあるあるな沼に落ちます。沼はどこにでもありますね。

ビジネスロジック系のOrganismsどこまで分解してどこに置く?

今の所organisms下にページ名で切って置いていることが多いです。が、それも微妙なのでできれば種別を考えてつけたいですね。
再利用するか再利用しないかくらいの粒度でいいのかもしれません。
Atomsから始めるのがAtomic Design流らしいですが、個人的にはpagesで作ってからいい感じに分解するでも問題ないかと思います。

外部データアクセスロジックをpagesに持たせたら各pages内に似たような処理が大量発生した

organismsに持てるやつは持ってしまってもいいかと思います。それでも減らない気がしますが。

Slotの魔法

Slotは素晴らしい機能です。Atomic Designとは直接関係ないですが。
モーダルの中身を渡したり、検索結果プレートの中身を変えたりするのによく使います。
ただし、やりすぎると処理を追いかけるのが大変になるので注意してください。

処理を見るのにレイヤーを追いかけるのがめんどくさい

はい。バケツリレーの結果がどう流れてるとかButtonアクションがどこに書かれてるとかレイヤーを追いかけていく羽目になります。 Atomic Designを導入したデメリットの一つかもしれません。


終わりに

やってみた/導入してみた系の記事は数あれど、実際どうだったかの記事はそんなにない。
そんなAtomic Designですが、「で、結局どうなの?」と言われれば、個人的にはないよりは大マシという感じです。
もちろん、PJとして一貫して指針が取れていれば何でもいいとは思いますが、何もわからないまま始めるならとりあえずある程度方針が固まっているAtomic Designにするのはありではないかと思います。
各所で言われてる気がしますが、Atomic Design自体が最適解というわけでもなく、チームとしてPJとしてできる範囲での最善を探っていくしかなそうです。

参考文献

Vue.js × Atomic Design - コンポーネント分割の指針 / Vue.js and Atomic Design - Guideline for components division - Speaker Deck

Atomic Designを実践して得た学びと失敗 - コネヒト開発者ブログ

PR

tecotec.co.jp