Nuxt.js を用いた新規事業開発を半年以上経験して得た知見

こんにちは、[@y_temp4](https://twitter.com/y_temp4) です。

自分は [ALIS](https://qiita.com/organizations/alis) という会社で主にフロントエンドまわりの実装を [Nuxt.js](https://ja.nuxtjs.org/) を用いて行ってきたのですが、今回はそこで得た知見について共有しようと思います👍

内容としては以前 [JSer.info 400回記念イベント](https://jser.connpass.com/event/100092/) にて発表した [Vue + Nuxt + Serverless の開発で得た知見 (主につらみ)](https://speakerdeck.com/y_temp4/jser-dot-info-400th-memorial-event) を元に、そこでは話しきれなかった点や、新たに得た知見などについてご紹介します。

## Nuxt を選定した理由

<img width="770" alt="スクリーンショット 2018-12-18 20.03.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/90682/442453f9-bfa1-4cad-a41f-266f62071773.png">

実際の開発の話に入る前に、Nuxt の選定理由について触れておきます。

ライブラリ・フレームワークを選定するときにはさまざまな観点がありますが、ALIS が Nuxt を選定した理由は主に以下の2つです。

### 開発速度を重視したかった

技術選定をする際に候補として React / Next なども挙げられましたが、Vue / Nuxt を用いたほうが開発速度を出せると判断しました。

Vue はその特徴として

- シンプルな記法
- 学習コストが低い
- ドキュメントが充実している

などが挙げられ、これは初期に　開発速度が求められた ALIS にとって非常に大きなメリットとなりました。

### 規約があるのが魅力的だった

Nuxt は Next と比べても、ディレクトリ構成などに規約が定められており、自分たちでフロントエンドの設計を（あまり）行う必要がないことも大きな利点となりました。

以下の記事の「ALISのフロントエンド構成について」の章でも触れていますが、現在も ALIS では Nuxt の規約をベースに構成を行っています。

[【ALISのシステム】フロントエンドアーキテクチャ：その１](https://alis.to/AB2/articles/34ZkxZ1pwylQ)

---

今回は比較対象として React / Next に触れましたが、もちろん初期の技術選定ではそのプロジェクトの状況に応じてどのライブラリ・フレームワークがベストかは変わってくるでしょう。

個人的には設計に時間がかけられたり、より堅牢な開発をしたいのであれば Angular や React の方が有利ではないかな、と思ったりもします。

## Nuxt を Lambda 上で動かす

ALIS の Nuxt は AWS Lambda 上で動いているのですが、その構成に関しては [mya-ake/nuxt-on-lambda](https://github.com/mya-ake/nuxt-on-lambda) が非常に参考になりました。

ちなみに ALIS の全体構成は以下のようになっており、詳しくは[【ALISのシステム】サーバサイドアーキテクチャ：その１ 〜ALIS サーバサイド構成〜](https://alis.to/AB2/articles/KBXeJ1VgwzNB)にもまとまっていますので、気になる方はぜひ参考にしてみてください😄

![875feccc-c812-4952-a488-c97a23d487a0.png](https://qiita-image-store.s3.amazonaws.com/0/90682/28491074-7ba4-721e-b117-3ef62346b35d.png)




## Atomic Design の所感

ALIS ではコンポーネント設計の手法として Atomic Design を採用しています。
<img width="881" alt="スクリーンショット 2018-12-16 15.43.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/90682/a5bf24ec-415b-e821-7a6c-c80f825344ee.png">
Atomic Design 自体は優れた設計手法だと思いますが、ALIS でこれをうまく扱うのは非常に難しかったです。

というのも、実際の開発では速度が求められるケースが多く、きちんと設計してコンポーネントの責務を分割しきれないことが多かったです。例えば、Atoms なのにコンポーネントの粒度が大きすぎたり、Atoms や Molecules に分割すべきところで分割できていなかったりしました。

これに関して個人的には、一旦 Atomic Design という構成は維持しつつも、ケースバイケースで今後のリファクタ観点として開発速度を重視する実装もありなんじゃないかと割り切っています。

例えば、再利用性が低そうであったり、新しく作り直す可能性の高い部分に関しては最初から Organisms などある程度大きなコンポーネントとして実装し、あとで必要に応じて Atoms や Molecules に切り分ける、という方法です。

もちろん最初から適切にコンポーネントを分けておいたほうが良いかもしれませんが、それが難しいケースもあると思うので、プロジェクトによっては使い分けも必要かと感じます。

### Nuxt と CSS Grid Layout

補足として、[CSS Grid Layout](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout) について触れます。

CSS Grid Layout は Flexbox と並んで CSS の比較的新しいレイアウト手法です。

ALIS ではこの CSS Grid Layout を用いて画面をレイアウトしてますが、これにはいくつか注意が必要だと感じています。

まず、CSS Grid Layout を使う際は Nuxt の [layouts] (https://ja.nuxtjs.org/api/pages-layout/) の仕組みが使いにくいです。

というのも、`grid-template-areas` プロパティを用いてレイアウトをすることになるので、親となる layout コンポーネントよりもその子コンポーネントからのレイアウトしたほうがコンポーネントの位置を制御しやすいからです。

ですので、ALIS ではここは割り切って Nuxt の layouts の仕組みはあまり利用せずに実装を行っています。

また、CSS Grid Layout をメインで使っているとはいえ、コンポーネントによっては Flexbox を用いたほうが簡潔に書けることもあるので、そこは使い分けが重要だと感じています。

個人的には全体的なレイアウトを CSS Grid Layout で行い、小さなコンポーネント単位では必要に応じて Flexbox を用いるという手法がしっくりきています。

## 状態管理について

ALIS では フロントエンドの状態管理に Vuex を用いています。


おそらく、ある程度の規模感のある Vue / Nuxt のプロジェクトでは、Vuex を使った状態管理が求められるケースが多いでしょう。

ALIS では以下のポイントを意識して Vuex を利用しています。

### module を分割する

Vuex には [module](https://vuex.vuejs.org/ja/guide/modules.html) という概念があり、以下のような感じで module を分割してストアを管理しています。

```js:app/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { createModule } from 'vuex-toast'
import article from './modules/article'
import user from './modules/user'
import tag from './modules/tag'
import report from './modules/report'
import presentation from './modules/presentation'

Vue.use(Vuex)

export default () =>
  new Vuex.Store({
    modules: {
      article,
      user,
      tag,
      report,
      presentation,
      toast: createModule({
        dismissInterval: 2000
      })
    }
  })
```

### axios-module を使う

Nuxt には便利なモジュールがいくつもあり、その中に axios をラップした [axios-module](https://github.com/nuxt-community/axios-module) というものがあります。

これを用いることによって、以下のように axios を呼び出すことができます。

```js
  async getLikesCount({ commit }, { articleId }) {
    const { count: likesCount } = await this.$axios.$get(`/articles/${articleId}/likes`)
    return likesCount
  }
```

また、axios-module を使うと [proxy-module](https://github.com/nuxt-community/proxy-module) が使えたり、よりシンプルが記法が可能になったりとメリットが多いため、Nuxt で非同期処理を行うならぜひ利用するべきです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">I am certain some of you already know today&#39;s 🔥 <a href="https://twitter.com/nuxt_js?ref_src=twsrc%5Etfw">@nuxt_js</a> tip but this was often a topic in the Discord recently.<br><br>The official <a href="https://twitter.com/hashtag/nuxtjs?src=hash&amp;ref_src=twsrc%5Etfw">#nuxtjs</a> axios module has shorthand methods that gives you neat the data *directly*. 🌟<br>When using the basic axios, you have to use `data` otherwise. <a href="https://t.co/ugv3TFgqCT">pic.twitter.com/ugv3TFgqCT</a></p>&mdash; Alexander Lichter (@TheAlexLichter) <a href="https://twitter.com/TheAlexLichter/status/1071040880079978496?ref_src=twsrc%5Etfw">2018年12月7日</a></blockquote>

### ミューテーションはアクションからのみ呼び出す

これは規則レベルの話ですが、ALISではアクションからミューテーションを呼び出すことにしています。

理由としてはその方がデータの流れが追いやすいのと、ミューテーションの処理の前後に非同期処理が挟まることがあっても変更が追加しやすいからです。
![vuex.png](https://qiita-image-store.s3.amazonaws.com/0/90682/db4188f6-e857-1ae4-19a4-c7e1ad05c075.png)

Redux など、他の Flux ライブラリと比較して緩く書ける Vuex だからこそ、より厳格に書いています（それでもかなり緩い書きっぷりになりますが）。

### Vuex の利用を最低限に抑える

ALIS の開発をはじめた当初は状態を意識的に Vuex で管理するようにしていたのですが、開発を続ける中で必ずしも毎回 Vuex 使う必要があるわけではないなと思い、今では最初に Vuex を使わずに、コンポーネントレベルで状態を管理できないか検討しています。

理由としては Vuex を使わないことにより状態が閉じ、状態の管理がしやすくなるからです。ここは Vue の状態管理のしやすさが効いているな、と思っています。

## Nuxt v2 へのバージョンアップ

さいごに、Nuxt を v2（2.3.4） に上げるにあたって ALIS で対応した箇所について触れておきます。

### assetsの記法

`css-loader`のバージョンアップに伴い、これまで`~/assets`と書いていた部分を`~assets`に変更しました。

### nuxt build の生成結果

`nuxt build`の生成結果が server と client で分かれるようになったため、`.nuxt/dist`ではなく`.nuxt/dist/client`をCDNの配信先に移すよう変更しました。

### gzip 圧縮の無効化

これまで、`nuxt.config.js`にて`gzip: false`としていた部分を、以下のように変更しました。

```diff:nuxt.config.js
  render: {
-    gzip: false
+    compressor: (req, res, next) => {
+      next()
+    }
  },
```

### isDev / isClient

`nuxt.config.js`の`build`部分にて、`isDev`、`isClient`の代わりに`process.server`と`process.browser`を使うようにしました。

### ライブラリの更新

ALISでは[@nuxtjs/markdownit](https://www.npmjs.com/package/@nuxtjs/markdownit)のバージョン 1.2.0 を使っていたのですが、Nuxt の2系には対応していなかったのでバージョンを 1.2.2 に上げました。

## まとめ

Nuxt を用いたフロントエンド開発ですが、全体の感想としては開発速度を保ちつつ気持ちよく実装できているかな、という印象です。

ただ一方で、例えば型がなかったり、テストがほぼ書けていなかったり、という課題感もあります。今後はこの辺も意識した開発ができればな〜と思っていますが、いつ改善に着手できるかな･･･という感じですね😅

さいごに、ALIS のソースコードはオープンソースにしているので、この記事が参考になった方はもしよろしければスターを押していただけますと嬉しいです🤩

リポジトリ：[AlisProject/frontend-application](https://github.com/AlisProject/frontend-application)