【Node.js】express + Nuxt.jsでシンプルなテンプレートを作った

#はじめに
https://qiita.com/seapolis/items/ac950e099db2775ba6a2
前回、こちらの記事でexpressとVue.jsを用いたシンプルなテンプレートをご紹介したのですが、結局その後Vue.jsを用いたフレームワークであるNuxt.jsに触れ、その便利さに感動してしまい、自分が作ったフレームワークなどすっかり忘れてNuxt.jsをずっといじくっておりました。

で、自作プロダクトに適用する折となり、初めに[nuxt-community/express-template](https://github.com/nuxt-community/express-template)を使っていたのですが、最近になってこのテンプレートが更新され、最新のNuxtが使われるようになったとともに、構成が大幅に変更されてしまい、Nuxt.jsがexpressをserverMiddlewareとして抱き込むような形となりました。

この構成、ファイル数が少なくて見通しもよく確かに便利は便利なんですが、Open ID ConnectのClientを実装しようとした際に、従来であればexpressのapp.jsにopenid-clientのPromiseオブジェクトを渡すような実装を行いますが、このテンプレの構成だと通用しないことが判明しました。

というわけで、「expressを土台に、Nuxtをミドルウェアとして実装するテンプレート」を作ることにしました。

#要件定義
* サーバーサイドはexpress
* クライアントサイドはNuxt.js
* expressのミドルウェアとしてNuxt.jsを使う
* サーバーサイドの自動監視
* サーバーサイドもbabelでES2015を使えるようにする
* ESLint

#できたもの
https://github.com/kaito3desuyo/express-nuxt-template
こちらになります。
基本的にはgit cloneしてnpm run startで走ってくれると思います。

#実装の詳細
ここからは中身について簡単ではありますが説明していきます。
下地として、expressのstarter-templateを用いました。
##app.js
app.jsに関しては最小限のコードを残して削除しています。

```js:app.js
const express = require("express")
const { Nuxt, Builder } = require("nuxt")

const app = express()

let config = require("./nuxt.config.js")
config.dev = !(process.env.NODE_ENV === "production")
const nuxt = new Nuxt(config)

if (config.dev) {
    const builder = new Builder(nuxt)
    builder.build()
}

const api = require("./api")

app.use("/api", api)
app.use(nuxt.render)

module.exports = app
```
Nuxtをミドルウェアとして読み込むために、[Nuxt.js公式](https://ja.nuxtjs.org/api/nuxt)でも紹介されているコードを追加しています。

##backpack.config.js
```js:backpack.config.js
module.exports = {
    webpack: (config, options, webpack) => {
        config.entry.main = "./server/index.js"
        return config
    }
}
```
Webpackの簡易版のようなものです。書き方は特殊ですが設定はWebpackのものが流用できます。

##nuxt.config.js
```js:nuxt.config.js
module.exports = {
    head: {
        titleTemplate: "%s - Nuxt.js"
    }
}
```
読んでくれればなんでもいいや、という感じ。

##package.json
```json:package.json
{
  "name": "express-nuxt-template",
  "version": "0.0.0",
  "private": false,
  "scripts": {
    "dev": "backpack dev",
    "build": "backpack build",
    "start": "node ./build/main",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "lintfix": "eslint --fix --ext .js,.vue --ignore-path .gitignore ."
  },
  "dependencies": {
    "express": "~4.16.0",
    "nuxt": "^1.4.1"
  },
  "devDependencies": {
    "babel-eslint": "^8.2.6",
    "babel-preset-stage-0": "^6.24.1",
    "backpack-core": "^0.7.0",
    "eslint": "^5.2.0",
    "eslint-config-prettier": "^2.9.0",
    "eslint-loader": "^2.1.0",
    "eslint-plugin-import": "^2.13.0",
    "eslint-plugin-node": "^7.0.1",
    "eslint-plugin-prettier": "^2.6.2",
    "eslint-plugin-vue": "^4.7.0",
    "prettier": "^1.13.7",
    "webpack-node-externals": "^1.7.2"
  }
}
```
npm run dev時にbackpackを実行するようして、
サーバーサイドもES2015のプリコンパイルと自動リロードを実現。
ESLintのplugin構成はNuxt公式を参考にしました。

##.eslintrc.js
```js:.eslintrc.js
module.exports = {
    root: true,
    env: {
        browser: true,
        node: true,
        es6: true
    },
    parserOptions: {
        "parser": 'babel-eslint',
        "sourceType": "module"
    },
    extends: [
        "eslint:recommended",
        "plugin:prettier/recommended",
        "plugin:vue/recommended",
        "plugin:import/errors",
        "plugin:import/warnings"
    ],
    rules: {
        "semi": [2, "never"],
        'indent': ['error', 4, {"SwitchCase": 1}],
        "no-console": "off",
        "prettier/prettier": ["error", { 
            "semi": false,
            "tabWidth": 4
        }],
        "arrow-body-style": "error",
        "arrow-parens": "error",
        "arrow-spacing": "error",
        "generator-star-spacing": "error",
        "no-duplicate-imports": "error",
        "no-useless-computed-key": "error",
        "no-useless-constructor": "error",
        "no-useless-rename": "error",
        "no-var": "error",
        "object-shorthand": "error",
        "prefer-arrow-callback": "error",
        "prefer-const": "error",
        "prefer-rest-params": "error",
        "prefer-spread": "error",
        "prefer-template": "error",
        "rest-spread-spacing": "error",
        "template-curly-spacing": "error",
        "yield-star-spacing": "error",
        "vue/max-attributes-per-line": "off"
    }
}
```
必要最低限の定義だけしてあります。お好みでどうぞ。

#終わりに
ここまでやって、これが更新される前のnuxt公式テンプレの焼き直しであることに気づきました。
車輪の再発明ェ…