LoginSignup
8
12

More than 5 years have passed since last update.

Nuxt で Express を使いときの reload 問題。

Last updated at Posted at 2018-12-23

はじめに

こんにちは。今日も明治大学 advent calendarやっていきます。

アドベントカレンダー忘れてて、数週間前に貯めておいた記事でどうにか繋ぐ。

Reload 問題

nuxtとapi serverを実装して最高のSSR applicationを作りたいぜ!なんて思うでしょ?
でもね、ググって出てくるnuxt & api serverって思ったより微妙なんだ。どれも、開発時のreloadが気持ちよくない。

nuxt & expressでググって良く出てくるのは以下の2つのパターン。
1. nuxt as an express middleware
2. express as a nuxt middleware

1. nuxt as an express middleware

まずはこっち。nuxtが提供しているexpress middlewareを使うバターン。

Example

コードはこれ。見ての通り、 Nuxt builder middlewareをexpressで使う。api serverをNodemonとかでwatch&reloadするような開発と非常に相性が悪い。

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)

Pros and Cons

  • Pros
    • 実装が楽
  • Cons
    • api server開発時にnuxtを最ビルドする必要があり、DX(Developer Experience)が最悪。

2. express as a nuxt middleware

次はこっち。Nuxtのmiddlewareとしてexpressを使うパターン。

Example

なんと、NuxtがserverMiddlewareなる機能を提供してくれていて、それを使うと本当に簡単にapi serverを実装できる!しかもね、api serverの変更をwatchしてくれて、server processだけをreloadしてくれるスグレモノ。これこそ、何も考えずにssr開発できるのがnuxtの強みなんだよな。

でもね、このexampleの場合、/api/index.jsの変更しかwatchしてくれないんだ。だから、./routes/usersを変更してもserverがreloadされない。

んーーーーーーーーーーーー、、、惜しいっっっ

nuxt.config.js
module.exports = {
  // ...
  serverMiddleware: [
    // API middleware
    '~/api/index.js'
  ]
}
/api/index.js
const express = require('express')

// Create express instnace
const app = express()

// Require API routes
const users = require('./routes/users')

// Import API Routes
app.use(users)

// Export the server middleware
module.exports = {
  path: '/api',
  handler: app
}

Nuxtならできるだろ?設定でなんとかできないのか?

ということで、Nuxtのソースコードを眺めてみる。ここは、serverMiddlewareのwathcerの部分。

一応、watch optionでwatchするファイルやディレクトリを指定することができる。が、Clientをwatchするときにも同じoptionを使うので、serverだけwatchしたいなんて要望には沿わない。

結局、できなかった

nuxt github: builder.js

  watchServer() {
    const nuxtRestartWatch = concat(
      this.options.serverMiddleware // ← ここ
        .filter(isString)
        .map(this.nuxt.resolver.resolveAlias),
      this.options.watch.map(this.nuxt.resolver.resolveAlias), // watch は watchClient() と共有
      path.join(this.options.rootDir, 'nuxt.config.js')
    )

    this.watchers.restart = chokidar
      .watch(nuxtRestartWatch, this.options.watchers.chokidar) 
      .on('change', (_path) => {
        this.watchers.restart.close()
        const { name, ext } = path.parse(_path)
        this.nuxt.callHook('watch:fileChanged', this, `${name}${ext}`)
      })
  }

Pros and Cons

  • Pros
    • 実装がめっちゃ楽
  • Cons
    • 一応、api server only reloadはできるけど、entry pointのみのreloadになるので、完璧なDXとは言えない。

Temporary Solution

とはいえ、わざわざ、nuxt serverとapi serverを分離させてproxyで...なんて面倒なことやりたくない。nuxtがサポートしてくれるまで寝て待てばいいのだろうけど、ずっと寝ちゃいられない。ということで、苦肉の策だけど、即時的というか一時的な解決策としては、これぐらい。

webpackとかでbuildしたやつをserverMiddlewareに設定する

あれ、nuxt serverとapi serverを分離させた方が良いんじゃ、、

おわりに

もしかして良い方法ってあるの?あったら教えてください☺️
自分だったら頑張って、分離させてproxyでほげほげしちゃうかも。面倒だけどね。typescriptも使いたいし。

追記

本当は Rust で Parser Combinator 実装!みたいな内容にしたかったんだけど、Ownership と Lifetime に苦しまされていて何も実装できなかった。Rust でコンビネーターはキツくない??

8
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12