はじめに
システム開発部フロントエンドエンジニアの工藤です。
マイクロアドの WEB アプリケーションのフロントエンドは、大半を Vue.js を用いて開発しています。
以前、社内標準化の取り組みについて取り上げましたが、今回は、そこでの策定内容でもあるVue.jsでのコンポーネント設計についてお話していきます。
Vue.jsによる設計
まずは、フロントエンドのコンポーネント設計でよく見かける「Atomic Design」をお試し採用しました。結論としては、pagesとtemplates, moleculesとatomsの区別が難しいのに対して恩恵が少ないなどの問題もあり、Atomic Designを元に改良することになりました。
新設計
Atomic Designを参考に下記の3階層に分けています。
階層 | 責務・要件 | Atomic Designで言うところの役割 |
---|---|---|
pages |
※特定の文脈・コンテンツとは、例えば弊社であれば広告を指す。 |
pages, templates |
components |
|
organisms |
commons |
|
molecules, atoms |
また、全体の構成は 原則3階層 という規約も設けています。
つまり、1画面がpage, components, commonsの各階層に配置された3つのVueファイルによって構成されることが基本になります。
<!-- pages/Parent.vue --> <template> <div> <Frame> <!-- slotを持つcommonsコンポーネント --> <Fuga /> </Frame> <div> </template>
<!-- components/ChildHasSlot.vue --> <template> <div class="wrapper"> <slot /> </div> <template> <!-- components/Child.vue --> <template> <div> <h2>このページ独自の内容</h2> <Button /> <!-- commonsコンポーネント--> <div> </template>
<!-- commons/button.vue --> <template> <div class="button", @click="onClick"> ボタンです。 <div> </template>
懸念としては、1ファイルの責務が多くなってしまうことがあげられましたが、下記によって解決を図ることとしました。
- slotを活用する
- 描画に直接関係ない処理はtsファイルに切り出す
- そもそも扱う情報が多い画面では、例外的にcomponentsが2階層も許容する
描画に直接関係ない処理はtsファイルに切り出す
以前取り上げたグローバル定数管理だけでなく、Composition APIの採用を行なっているため機能単位での管理もここに含まれます。
Vuex, Piniaの利用方針
フロントエンドの設計を考える上で状態管理の話は避けて通れません。
VuexやPiniaを導入するだけで解決としている記事をよく見かけますが、中・大規模のプロジェクトではstoreの肥大化や参照・格納場所の不明確さが複雑化を招くので、使用方法を限定しています。 (最近よく見かけるようになったprovide/injectパターンも同様の問題があるという結論です。)
その主な用途は、複数画面で使用するデータの取得回数をできるだけ
減らし1箇所のみで管理することです。(あくまでSPAが前提の方針です。)
格納データの種類・規則
- 複数画面を跨いで利用される情報
- 単数画面だがページ遷移してもデータ保持が必要な情報
複数画面を跨いで利用される情報
例えば、ユーザー情報がこれに当たります。
単数画面だがページ遷移してもデータ保持が必要な情報
例えば、一覧表示されたものに対する一時的な検索条件の保持がこれにあたります。
Store モジュール分割粒度・方法
- 複数画面で跨いで利用するデータ
- グローバル
- 特定の文脈・コンテンツ単位
- ページ毎(使用するのは単数画面だがページ遷移してもデータ保持が必要な場合)
終わりに
このコンポーネント設計を導入して、チーム内での開発における微妙な差異が解消され、開発効率が向上したように感じています。
少しでも参考になれば幸いです、ご覧いただきありがとうございました。