Nuxt(Vuetify/TypeScript)で開発する際のコーディング規約について

# はじめに
社内でNuxtでのプロジェクト生成〜リリースまで担当した中で、
自分なりに考えてきたコーディング規約についてまとめました。
これからNuxtで開発をされる方の参考に少しでもなれば幸いです。

前提として、今回は`npx create-nuxt-app`でプロジェクト生成する際に、
TypeScript、Vuetifyを組み込んでます。
※Vuetifyを組み込むとscssファイルも読み込めるようになります。

# クラスの命名ルール
BEM記法を今回は採用しましたが、それに加えて以下のルールを追加しました。

- Nuxtのディレクトリ構成に則ってプレフィックスをつける
- 各ファイルで共通するスタイルの場合は`assets/scss/base.scss`に定義する。

具体的には、コンポーネント内で`scoped`属性をつけて定義されたスタイルのクラス名はこのようになります。

```md
pages -> p-xxx
layout -> l-xxx
components -> c-xxx
```

また、`assets/scss/base.scss`に定義する共通スタイルはプレフィックスにglobalの「g-」を付けるようにしました。

そうすることでCSSを見る際にbase.scssで定義されたものか、
コンポーネント内で定義されたCSSか一眼で見分けることができるようになります。
また、VuetifyはデフォルトでグローバルにVuetify用のクラスがいくつか宣言されます。
このクラスとの重複を避けるためにも「g-」とプレフィックスをつけるようにすることで、
予期せぬ命名被りを防げます。

# Vue側のルール

- import 順は Library -> .vue / .ts

```ts
import { Component, Prop, Vue } from "nuxt-property-decorator"
import { authStore } from "~/store"
import { foo } from "~/types/hoge"
```

- Vueコンポーネントは自動importされるよう設定しているのでファイル名(コンポーネント名)は被らないようにする
    - 特に各コンポーネントから1度しか呼ばないようなヘッダーなどのコンポーネントには、プレフィックスとして「The」をつける。例：TheHeader.vue
- コンポーネントを呼び出す際は、パスカルケース(TheHeader)
    - Vuetifyのコンポーネントをケバブケース(v-btn)で呼び出しているので、パっと見で見分けがつくようにする。
- vueのscriptタグ内は各プロパティごとにアルファベット順で並べる。
    - 特にmethodsの中でもasync(非同期処理)は重要な処理のケースが多いので、methods内でも区別して上にまとめる。
- vuexはstate, getters, mutations, actionsに分けてアルファベット順で並べる
- store内ではpublic,privateのアクセス修飾子を必須にするが、vueコンポーネントに関してはアクセス修飾子が意味をなさないため不要とする。


Vueコンポーネントの`<script>`タグ内には全ファイルに以下のようなコメントを加えておくことで、
複数人での開発でもソースの書き方にばらつきが生じないよう工夫しました。

```vue:login.vue
<script lang="ts">
import { Component, Vue } from "nuxt-property-decorator"
import { authStore } from "~/store"

@Component
export default class TheHeader extends Vue {
  /* ===============================
   * props
   * =============================== */
  /* ===============================
   * data ※ABC順に記載すること
   * =============================== */
  accountId = ""
  accountIdMaxLength = 14
  password = ""
  /* ===============================
   * computed
   * =============================== */
  get errorMessage(): string {
    return authStore.errorMessage
  }
  /* ===============================
   * lifecycle
   * =============================== */
  mounted () {
    // 
  }
  /* ===============================
   * methods ※ asyncは重要な処理のケースが多いので上にまとめる
   * =============================== */
  async login() {
    //
  }

  required (value: string) {
    //
  }
}
</script>
```

storeも同様です。
ついでに開発中によくハマるような部分もコメントに追記したりしてました。

```ts:AuthStore.ts
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators"
import { LoginRequest } from "~/types/api"

@Module({
  name: "AuthStore",
  stateFactory: true,
  namespaced: true,
})
export default class AuthStore extends VuexModule {
  /* ===============================
   * state
   * =============================== */
  private isAuth: boolean = false

  /* ===============================
   * getters
   * =============================== */
  public get getIsAuth() {
    //
  }

  /* ===============================
   * Mutation
   *  ※ mutationは引数を1つしか持てない。
   * =============================== */
  @Mutation
  private updateAuth() {
    //
  }

  /* ===============================
   * Action
   *  ※ actionは引数を1つしか持てない。
   * =============================== */
  @Action({ rawError: true })
  public async fetchLogin(data: LoginRequest): Promise<boolean> {
    //
  }
}

```

# プロジェクトの設定

最後に、上記のルールを適用するにあたって、
プロジェクト生成後に手を加えた設定をまとめておきます。

まずはCSS側です。
以下で`assets/scss/index.scss`を読み込むようにします。

```js:nuxt.config.js
vuetify: {
  customVariables: ["~/assets/scss"],
```

`assets/scss/index.scss`の中身はこんな感じです。

```scss:assets/index.scss
@import "./foundation/mixin.scss";
@import "./foundation/variables.scss";
@import "./foundation/base.scss";
```

グローバルに使う汎用的なスタイルはこれらに定義していく感じになります。
ちなみに`base.scss`が最後にimportされているのは`mixin`や`variables`で定義されたスタイルも使えるようにするためです。

次にVue側です。

componentsフォルダのVueコンポーネントに関しては自動でimportできるように設定します。

```js:nuxt.config.js
components: [
  {
    path: "@/components/",
    pathPrefix: false,
  },
],
```

そして、Vuexは`vuex-module-decorators`をインストールして、TypeScriptで書けるようにしました。
以下の記事が非常に参考になりました。
[Nuxt.js + TypeScript + Vuexをvuex-module-decoratorsでがっちりインテリセンスを効かせる](https://qiita.com/azukiazusa/items/a50b1ffe05d9937a4db0)

# おわりに
今回、初めてリーダーとしてフロントエンドの開発を担当しましたが、
規約を作っておくことの重要性を身を持って実感しました。
他の方が実装したソースに変更を加える際やコードレビュー時の工数を大幅に減らすことができます。
引き続きコーディング規約は日々ブラッシュアップしていきたいと思います。

# 参考にさせていただいたサイト
[[CSS設計] 私のためのFLOCSSまとめ](https://qiita.com/super-mana-chan/items/644c6827be954c8db2c0)
[BEM記法におけるElement/Modifierの付け方メモ](https://qiita.com/usagi-f/items/b4e56e765384c49d5d04)
[Nuxt.js + TypeScript + Vuexをvuex-module-decoratorsでがっちりインテリセンスを効かせる](https://qiita.com/azukiazusa/items/a50b1ffe05d9937a4db0)