hacomono TECH BLOG

フィットネスクラブやスクールなどの顧客管理・予約・決済を行う、業界特化型SaaS「hacomono」を提供する会社のテックブログです!

Nuxt3 向けに Atomic Design を拡張してみた

フロントエンドのテックリードのみゅーとん(@_mew_ton)です。

弊社では新しいプロジェクトを立ち上げの際に、Nuxt3を採用することにしました。
また、従来までのプロジェクトの反省点として、 Atomic Design を考慮して実装することにしました。

ただ、Atomic Design について調査していくと、Atomic Design の考え方をそのままディレクトリに落とし込んでいくのはどうやら悪手のようで、Google サジェストからも、いくつか失敗のケースが散見されました。 そこで、Nuxt3 のディレクトリ構成にマッチするような Atomic Design の構成を考えてみたので紹介します。

Atomic Design とは

Atomic Design とは、パーツ単位でUIデザインを設計する手法です。

Atomic Design 自体は 5年以上前から提唱されている設計方法であるため、今更・・となる方も多いでしょう。
概要だけ説明すると、画面を構成するパーツの最小単位を ATOMS として、最小のATOMSからデザインしていき、MOLECULES、ORGANISMS … の順番にデザインを進めていく手法です。
画面デザインが Atomic Design に則っている場合、フロントエンドでの開発でもそれに沿うように実装するケースもあります。

引用: Atomic Design by Brad Frostatomicdesign.bradfrost.com

Atomic Design を Nuxt3 に落とし込むには?

Nuxt3 では実装するコンポーネントディレクトリ構成がフレームワーク側で厳密に定まっており、Atomic Design を Nuxt3 に当てはめるなら、その構成に乗っていくのが自然かと思います。

Nuxt3 のディレクトリと Atomic Design の粒度を照らし合わせると、以下のように配置すればよさそうです。

  • ./src/template .. TEMPLATES
  • ./src/pages .. PAGES
  • ./src/components .. ATOMS, MOLECULES, OGRANISMS

ただ、ATOMS, MOLECULES, ORGANISMS の3種は ./src/components 配下にいかに配置していくかが、一番悩ましいところかと思われます。

ありがちな components 配下の構成

シンプルに考えると、 ATOMS, MOLECULES, ORGANISMS は以下のように配置したくなるでしょう

  • ./src/components/atoms .. ATOMS
  • ./src/components/molecules .. MOLECULES
  • ./src/components/organisms .. ORGANISMS

また、プロジェクトによっては、 例えば ステート管理や fetch 処理の可否をコンポーネントの粒度で定めていたりすることもしばしばあります。
例えば、 「ORGANISMS 以上のコンポーネントなら fetch, ステート管理をしてもよい」 など。

しかし、この構成だと以下の点で都合が悪いでしょう。

  • 実装しているコンポーネントの粒度がわからなくなる (MOLECULES? ORGANISMS?)
  • うっかり MOLECULES 以下の粒度で fetch する実装をしてしまった場合、これを防ぐのはコードレビューしかない。
  • 特定のドメインコンポーネントを探すのが大変

Nuxt3 向け Atomic Design 拡張構成

Atomic Design のコンポーネントの粒度ごとに、一旦以下のように記述ルールを整理しました

  • ATOMS / MOLECULES
    • 粒度を区別しない
    • Nuxt3 composable を利用しない
  • ORGANISMS / TEMPLATES / PAGES
    • Nuxt3 composable を利用できる
    • Domain データに紐付くなら粒度に関係なく ORGANISMS 以上の粒度とする

Nuxt3 composable とは component の script の実装で、import文を使わずに利用できる汎用ビジネスロジックで、Nuxt3 公式の composable (useState, useFetch, useCookie など) の他、 ./src/composables に独自に実装することも出来ます。
つまり、「Nuxt3 composable を利用できる」とは、vue-route の利用や、fetchの実行ができることを意味します。

このルールのもと、それぞれの粒度の場所を以下のように定義しました。

  • ATOMS / MOLECULES
    • Nuxt3 のプロジェクトの外側にVue3プロジェクトとして実装
  • ORGANISMS
    • ./src/components
  • TEMPLATES
    • ./src/templates
  • PAGES
    • ./src/pages

弊社が作成したプロジェクトでは、はじめから monorepo 構造で、 ATOMS/MOLECULES用の Vue3 サブプロジェクトと、 Nuxt3のサブプロジェクトの2つを内包する構成としました。
その他、2つのリポジトリとして別々に作り、 ATOMS/MOLECULESを Design System として実装する方法もあるかと思います。

Pros / Cons

実際にこの構成で開発を進め、以下のメリットがあると感じました。

  • ATOMS / MOLECULES
    • Nuxt3 の外側に実装してしまうので、Nuxt3 composable を機会的に利用できなくしている
    • 2種を区別しないので実装時に混乱しない
    • ORGANISMSに間違って変更するようなミスが発生しない
    • 後でDesign System の実装に置き換えるケースで、修正差分を最小限に抑えられる
    • Storybookをプロジェクトの成果物として管理できる
  • ORGANISMS
    • ./src/components 配下に ドメインごとにディレクトリを分け、分類するなどの整理が簡単にできる
    • Domain データに紐付くなら ORGANISMS というルールを採用しているので、粒度に基本困らない
  • 全般

逆にデメリットとしては以下が挙げられるかなと思います

  • 初見に優しくなく、キャッチアップに負荷がある
    • Storybook を覚えなければいけない点で少し大変

まとめ

Nuxt3 でのアプリ開発で取り入れている Atomic Design を拡張した形式について紹介しました。
今はこれでうまく進めることができている状態ですが、まだまだ構成や方式に改善できる点はあるかと思います。
改善次第またその方式について紹介したいと思います。