Nuxt.js でバックもフロントもこれ一本

# 要約
いまさら[Nuxt.js](https://nuxtjs.org)使ってみたらすごくいい感じだったので、その導入部分をご紹介。

## あらまし
### 動機
ちょっとしたwebアプリを作りたかったんです。3Dデータファイルの変換をサーバーでやってくれて、変換結果をダウンロードできるやつ。スマホアプリとかから機能を利用できるAPI（別にパーミッションとかユーザー認証は要らない）があって、ついでに手動で簡単に操作できるSPAっぽいフロントエンドもあったらいいな。ああでも面倒クサいです。こんなちんまい機能のアプリこさえるのに時間かけたくないけど、一人でバックとフロント両方やらんといけん。どうしよ。

### 何使う
以前DjangoとVue.jsで[こんなこと](https://qiita.com/kawaMk4/items/89b18c608dc7dd2b946b)しましたけれど、正直Pythonとjs書き分けるのもダルいです。それにプロジェクト設定も多くて面倒。あー、一つの言語で両方書けてコマンド一発でいい感じに設定されたプロジェクト作ってくれるやつないかなー。…調べたらありました。フロントは[Vue.js](https://jp.vuejs.org/index.html)で、バックは[Express](http://expressjs.com)で、プロジェクトは[cli](https://github.com/nuxt/create-nuxt-app)がよしなにしてくださるらしい。[Nuxt.js](https://nuxtjs.org)キミに決めた！

## やってみよう
### 環境
[Node.js](https://nodejs.org/ja/)はもちろんですが、加えて[Yarn](https://yarnpkg.com/lang/ja/)使います。まだ入れてなかったら入れてね。Node.jsはmacOS上のv10.12.0とCentOS6のv9.11.2で問題なく動きました。

### プロジェクト作ろう
Nuxtプロジェクトを楽々セットアップしてくれる素敵な[create-nuxt-app](https://github.com/nuxt/create-nuxt-app)で始めていきましょう。

```shell
% yarn create nuxt-app miniapp
```

何もグローバルインストールしなくてもやってくれるみたいですね。ナウいです。
いくつか設定の質問があります。選択肢の中から必要なものを選んでインストール。

```shell
? Project name miniapp
? Project description My astounding Nuxt.js project
? Use a custom server framework express
? Use a custom UI framework bootstrap
? Choose rendering mode Single Page App
? Use axios module yes
? Use eslint yes
? Use prettier yes
? Author name myname
? Choose a package manager yarn
```
サーバーフレームワークは個人的に慣れてる[Express](http://expressjs.com)で、UIフレームワークは適当に[bootstrap](https://getbootstrap.com)を。[axios](https://github.com/axios/axios)はサーバーサイドでも使いたかったのでnuxtのモジュールだと逆に面倒ですし後で自分で入れるのも簡単なんですが、この記事では面倒なことしないのでアリ。規約もあったほうがいいので[eslint](https://eslint.org)と[prettier](https://github.com/prettier/prettier)は両方アリで。もうこの辺りは好みでいいでしょう。
プロジェクトができたなら、いざ動作確認！

```sh
% cd miniapp
% yarn dev
```

するとどうでしょう！

<img width="853" alt="スクリーンショット 2018-10-17 20.37.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/226634/58941d34-5a9f-7d50-090a-e46371e7206a.png">

ズコーって感じですね。動かないんかい。
prettierが怒ってますね。直してからまた実行しましょう。

```sh
% ./node_modules/.bin/eslint --fix pages/index.vue
% yarn dev
```

すると…

<img width="855" alt="スクリーンショット 2018-10-17 20.46.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/226634/d2b6ac40-5754-87fe-704b-715206997095.png">

よかった動いた。今後のためにpackage.jsonのscripts > lint のところに --fix オプションをつけておくと`yarn lint`で同じことができるので後が楽です。さっきのコマンド長いし。

### API作ろう
プロジェクト直下のserverフォルダにapi.jsを追加します。動作確認用の簡単なやつです。

```javascript:server/api.js
const express = require('express')
const router = express.Router()

router.get('/test', (req, res, next) => {
  const param = { test: 'success' }
  res.header('Content-Type', 'application/json; charset=utf-8')
  res.send(param)
})

module.exports = router
```

そしてserver/index.jsに二行だけ追記してルーティングします。

```js:server/index.js
const express = require('express')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = express()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 3000

const apiRouter = require('./api') // ここ追記！

app.set('port', port)

// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')

async function start() {
  // Set api route
  app.use('/api', apiRouter)  // ここも追記！

  // Init Nuxt.js
  const nuxt = new Nuxt(config)

  // Build only in dev mode
  if (config.dev) {
    const builder = new Builder(nuxt)
    await builder.build()
  }

  // Give nuxt middleware to express
  app.use(nuxt.render)

  // Listen the server
  app.listen(port, host)
  consola.ready({
    message: `Server listening on http://${host}:${port}`,
    badge: true
  })
}
start()
```

さあできました。`yarn dev`でサーバー起動して[localhost:3000/api/test](http://localhost:3000/api/test)にアクセス。

<img width="854" alt="スクリーンショット 2018-10-17 21.12.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/226634/b0a7e671-7d02-9564-64af-0009b1e4b53b.png">

できてますね。簡単便利。

### SPA作ろう
既にそれっぽいのがあるのでちょっと追記するだけにしておきましょう。API確認できればいいですし。

```vue:pages/index.vue
<template>
  <section class="container">
    <div>
      <logo/>
      <h1 class="title">
        miniapp
      </h1>
      <h2 class="subtitle">
        My astounding Nuxt.js project
      </h2>
      <h2 class="subtitle">
        api response result : {{ response }}  <!--ここと-->
      </h2>
      <!--中略-->
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  },
  // ここから
  data: function() {
    return {
      response: null
    }
  },
  mounted: function() {
    this.$axios
      .$get('/api/test')
      .then(response => {
        this.response = response.test
      })
      .catch(error => {
        console.log(error)
      })
  }
  // ここまで
}
</script>
<!--以下略-->
```

結果

<img width="885" alt="スクリーンショット 2018-10-17 21.34.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/226634/d7653a04-f326-594a-62ba-48659ac1f813.png">

大丈夫そうです。最初にnuxtモジュールでaxios入れておけば、importしなくても使えます。素敵。
本格的に何か書きはじめるなら素のhtmlより[pug](https://pugjs.org/api/getting-started.html)をお勧めします。こっちの方がスッキリ見やすく書きやすいです。このプロジェクトへの導入も簡単です。Nuxt.js公式の[プリプロセッサを使うには？](https://ja.nuxtjs.org/faq/pre-processors/)が参考になります。
その場合はこのようになります。

```vue:pages/index.vue
<template lang="pug">
  section.container
    div
      logo
      h1.title
      h2.subtitle My astounding Nuxt.js project
      h2.subtitle api response result : {{ response }}
      div.links
        a(href="https://nuxtjs.org/", target="_blank").button--green Documentation
        a(href="https://github.com/nuxt/nuxt.js", target="_blank").button--grey GitHub
</template>
<!--以下略-->
```
あらスッキリ！

## 所感
チャッチャと簡単に何か作るときにはNuxt.jsすごく便利です。というかcreate-nuxt-appが。バックエンドもこのまま作り込めそうだし、簡単便利で素晴らしい。これの上にファイルアップロードの色々とか各種APIとコマンドのラッパー的なの作って、なんとか今回欲しかったちんまい3Dデータ変換アプリは一日かけずに完成しました。
[vue-cli](https://cli.vuejs.org)は便利でかっこいいけどバックエンドまでは含めてくれないし、別段SSRしたくなくても、小規模なwebアプリのためのまるごと全部入りパッケージとして、Nuxt.jsなかなかアリだと思います。作ってくれた人たちに多謝。