JavaScript
Express
vue.js
nuxt.js

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

要約

いまさらNuxt.js使ってみたらすごくいい感じだったので、その導入部分をご紹介。

あらまし

動機

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

何使う

以前DjangoとVue.jsでこんなことしましたけれど、正直Pythonとjs書き分けるのもダルいです。それにプロジェクト設定も多くて面倒。あー、一つの言語で両方書けてコマンド一発でいい感じに設定されたプロジェクト作ってくれるやつないかなー。…調べたらありました。フロントはVue.jsで、バックはExpressで、プロジェクトはcliがよしなにしてくださるらしい。Nuxt.jsキミに決めた!

やってみよう

環境

Node.jsはもちろんですが、加えてYarn使います。まだ入れてなかったら入れてね。Node.jsはmacOS上のv10.12.0とCentOS6のv9.11.2で問題なく動きました。

プロジェクト作ろう

Nuxtプロジェクトを楽々セットアップしてくれる素敵なcreate-nuxt-appで始めていきましょう。

% yarn create nuxt-app miniapp

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

? 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で、UIフレームワークは適当にbootstrapを。axiosはサーバーサイドでも使いたかったのでnuxtのモジュールだと逆に面倒ですし後で自分で入れるのも簡単なんですが、この記事では面倒なことしないのでアリ。規約もあったほうがいいのでeslintprettierは両方アリで。もうこの辺りは好みでいいでしょう。
プロジェクトができたなら、いざ動作確認!

% cd miniapp
% yarn dev

するとどうでしょう!

スクリーンショット 2018-10-17 20.37.44.png

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

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

すると…

スクリーンショット 2018-10-17 20.46.55.png

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

API作ろう

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

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に二行だけ追記してルーティングします。

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にアクセス。

スクリーンショット 2018-10-17 21.12.05.png

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

SPA作ろう

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

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>
<!--以下略-->

結果

スクリーンショット 2018-10-17 21.34.30.png

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

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は便利でかっこいいけどバックエンドまでは含めてくれないし、別段SSRしたくなくても、小規模なwebアプリのためのまるごと全部入りパッケージとして、Nuxt.jsなかなかアリだと思います。作ってくれた人たちに多謝。