Vue.jsで開発を始める前に決めておきたい事


ここ1年ほど実務でVue.jsを利用してWebアプリケーションを開発しています。
今回はVue.jsを使ってチームあるいは個人で開発を始める上で予め考慮しておくと良さそうな事をいくつか書きたいと思います。

コンポーネントルール

Vue.jsは単一ファイルコンポーネントによって、とてもシンプルな記述でコンポーネントを作る事ができます。しかし、開発者同士でコンポーネントの認識を揃えておかないと同じようなコンポーネントが作られてしまい、保守性を低下させる要因になってしまいます。
そのため、昨今ではAtomic Designなどの考え方をベースにコンポーネントを管理する方法が用いられています。Atomic Designを用いたコンポーネント設計方法については、以下の記事が参考になるかと思います。

Vue.js × Atomic Design - it's an endless world.

いずれにしても以下の点を事前に認識合わせしておくだけでも、よりスムーズに開発を始める事ができます。

Storeに依存するコンポーネント、依存しないコンポーネント

Storeはアプリケーションの状態を管理しているモデルです。コンポーネントはStoreから情報を受け取る事で動的に情報を表示する事ができます。しかし、安易にコンポーネントからStoreを参照してしまうと、特定の状況下でしか利用できないコンポーネントとなってしまい、再利用性が低下します。

コンポーネントを定義する上で、最もシンプルなルールは以下の2種類に分類する方法です。

  1. Pagesコンポーネント
  2. Partsコンポーネント

PagesコンポーネントはStoreからデータを取得したり、Storeの情報を更新する事ができるコンポーネントです。Pagesコンポーネントは基本的に再利用する事が無いため、Storeと密結合させても問題ありません。

PartsコンポーネントはPagesコンポーネントの子コンポーネントとして使用する各コンポーネントです。基本的にStoreとは紐づかないようにします。
Storeから分離する事でパーツとしての再利用性を高める事ができます。

プロパティを明確にする

コンポーネントを作る際にはプロパティを明確に定義しておく事で他の人が再利用する際の手助けになります。
以下のようにプロパティ検証を通して、コンポーネントが受け取る情報を定義する事ができます。

Vue.component('example', {
  props: {
    // 基本な型チェック (`null` はどんな型でも受け付ける)
    propA: Number,
    // 複数の受け入れ可能な型
    propB: [String, Number],
    // 必須な文字列
    propC: {
      type: String,
      required: true
    },
    // デフォルト値
    propD: {
      type: Number,
      default: 100
    },
    // オブジェクトと配列のデフォルトはファクトリ関数から返すようにしています
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // カスタムバリデータ関数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

参考: コンポーネント — Vue.js

最近だとFlowやTypeScriptを使って型定義を行う事も出来ますが、アプリケーションの規模や性質に応じて取捨選択すれば良いかと思います。

CSSの命名ルール

コンポーネントのスタイルを定義する場合には、CSSの命名ルールとしてコンポーネント名を含めるとHTML上からコンポーネントを見つけやすくなりますし、コンポーネント内のHTMLとCSSの関係性が分かりやすくなります。ただし、コンポーネント名を変更した時にはclass名も変更が必要になるので、保守性が若干低くなります。

例えば、UserIcon.vueの場合は以下のように定義できます。

<template>
  <div class="useIcon">
    <img class="useIcon-image" src="">
  </div>
</template>

<style lang="scss" scoped>
.useIcon {
  ...
  &-image {
    ...
  }
}
</style>

昨今のCSS設計ではBEMなどの設計手法が取り上げられますが、Vue.jsのコンポーネントシステムを利用する上でBEMなどの複雑なルールを併用する事は個人的には過度な気がしています。(そもそもBEMはコンポーネント指向から生まれた設計手法なので…)

共通コンポーネントを共有する

コンポーネントの数が増えてくると、既存のコンポーネントを把握するのが難しくなってきます。そんな時のためにStorybookなどを利用すると開発者同士で共有しやすくなります。
Storybookはコンポーネントを読み込んで、Webページとしてコンポーネントリストを見れるようにしてくれるツールです。

以下の記事で詳しく書かれているので参考になるかと思います。
Storybook for Vue 入門

状態管理のルール

アプリケーションの規模が大きくなる場合はデータフローが複雑になりやすいので、Vuexを導入して単方向のデータフローにする事で状態管理を行いやすくしてくれます。

参考: Vuexとは何か?

Vuexの場合、ComponentからActionを通さずに直接Mutationを実行できるようになっています。Componentから直接Mutation実行しちゃっていいのかという事は以下で議論されてました。

Should a component commit a mutation directly?

私の場合、アプリケーションの規模が一定大きくなっていく事が想定されたので、一貫性を重視してComponentからMutationを実行しないようにしました。
もし、規模が小さめのアプリケーションであれば、柔軟性を得るためにComponentからMutationを実行するのもアリかもしれません。

もし、アプリケーションの規模がそこまで大きくなければ、Vuexを導入せずともStoreパターンで十分かもしれません。

参考: シンプルな状態管理をゼロから作る

終わりに

上記のルールたちは開発メンバーのスキルや状況によって変わると思いますので、あくまで参考程度に留めていただければ幸いです。
個人的にはVue.jsの単一ファイルコンポーネントシステムやシンプルな命名などコードが読みやすい点がとても気に入っています。あと、公式ドキュメントが日本語化されているのもチーム開発に大きく役立ちますね!