Vue 2 系で作るコンポーネント設計方針
いよいよ Vue 3 がリリースされるということで、Vue 2 系でどのような考えのもとコンポーネントを設計してきたのかをまとめておきたいと思います。
対象
- CRUD を主とした BtoB アプリケーションを想定
- 十数項目以上の登録(Form)画面、多機能な一覧画面 etc
- 管理画面
前提
- Vue CLI
- Vuex
- UIフレームワーク使用
- View UI (旧 iview) を好んで使用します。Vue 3 はサポートされるのか。。。
- @vue/composition-api (2020/07/31 時点ではベータ) の導入に踏み切れていません。
- Vue 3 では Composition API を利用します。
- Vue 3 がリリースされたら Vue 2 でも @vue/composition-api を導入します。
- 趣味では導入経験あり
- チーム開発では service などの独自パッケージ(ディレクトリ)は作りません。
- プロジェクトルートや src トップには CLI コマンドで作成されたフォルダのみ。
- コミュニケーションコストや初見殺しを避けるため
- メンテナーが総入れ替えするたびに負債化していく事が多いため
設計方針
- Store
- エンティティ相当 → state
- 永続化層 → action, mutation
- ドメインロジック・オブジェクト → getter
- 業務ロジック
- アプリケーションロジックは Composition API に移行します。
- Scoped Slots
- ドメインサービス
- アプリケーションサービス
- 個人開発の場合はサービスパッケージを切ります。
- Composition API に置き換える予定
- Vue 2 では @vue/composition-api に変更予定
- アプリケーションコンポーネント
- atoms, molecules 相当
- UIフレームワークにアプリケーション要件を載せたコンポーネント群
- UIフレームワークの CSS はできるだけ用意されている変数でカスタマイズします。
- CSS は主にアプリケーションコンポーネントにしか書きません。
- ドメイン・値コンポーネント
- atoms, molecules 相当
- アプリケーションコンポーネントにドメイン要素を載せたもの
- ユースケース(機能)コンポーネント
- organisms, template 相当
- template は省略することが多い
- コントローラーコンポーネント
- page 相当
- チーム開発ではルーティングコンポーネントと分けないことが多い
- Nuxt のルールに従うため
- 個人開発だと分けています。
- ルーティングコンポーネント
- views 以下
- 画面遷移はこのコンポーネントでのみ行います。
- ルートコンポーネント(レイアウトコンポーネント)
- app, home, login etc
課題
- 独自パッケージ禁止縛りのため、値オブジェクトを表現するのが難しい
- 個人開発の場合は値オブジェクトパッケージを切ります。
- 切れないときは Store の getter、もしくは値コンポーネントに寄せます。できるだけコンポーネントに持ちたくないのですが。。。
- 個人開発の場合は値オブジェクトパッケージを切ります。
- バリデーション
- UIフレームワークが内包している場合はそれに従います。
- 辛いことも多いが、ドキュメントが有るので低コストで運用可能
- 個人開発の場合はバリデーションパッケージを切ります。
- できるだけ水際で対処したいが、バックエンド要件にあった層で注入します。
- UIフレームワークが内包している場合はそれに従います。
- 不要なドメインロジックは書きません。サーバーサイド担当者を説得します。
- フロントエンドの寿命は短い
- Store でなくても構いませんが、代替が今のところありません。
- atoms 以下の要素に対する CSS をどう管理するか
- 基本的には各コンポーネントに閉じて「管理しない」という戦略を取ることが多い
- 外部CSSにまとめることもありますが、せいぜいクラス2〜3個までにまとめます。(tailwind より更にミニマムなものが欲しい)
- 似たドメイン問題
終わりに
現時点では上記のような戦略で、できるだけコンポーネント間の依存関係を明確にするように書いています。ユースケース、コントローラーでの仕様変更に対応しやすく、ドメイン・値コンポーネントの追加・削除が安全に行える設計を目指しています。
そろそろ Vue 3 でメモアプリでも作って、現状の戦略をどう変えていくか検討していきたいと思います。