Nuxt.js: programatic usage with koa fails since migration from 1.0.0-alpha.4 to v1.0.0-rc3

Created on 29 Jul 2017  路  13Comments  路  Source: nuxt/nuxt.js

This is my koa app that serves nuxt app.

  • if NODE_ENV=production it always serves "OK" and nothing happens on server
  • if NODE_ENV=development it always serves "OK" and in server logs I see that app fetches async data and then there is error UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
  • it works with express
import Koa from 'koa'
import { Nuxt, Builder } from 'nuxt'
import config from './../nuxt.config.js'

const app = new Koa()

config.dev = !(process.env.NODE_ENV === 'production')

const nuxt = new Nuxt(config)

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

app.use(async (ctx, next) => {
  ctx.status = 200
  await nuxt.render(ctx.req, ctx.res)
})

app.listen(3000)
console.log('Server listening')

Note that following piece of code is exactly the same I used with nuxt 1.0.0-alpha.4

app.use(async (ctx, next) => {
  ctx.status = 200
  await nuxt.render(ctx.req, ctx.res)
})

This question is available on Nuxt.js community (#c1063)

Most helpful comment

@IlyaSemenov Thanks! I found lib that allows to use connect middleware with koa: https://github.com/vkurchatkin/koa-connect. I use it like this and it works:

import koaConnect from 'koa-connect'

app.use(async (ctx, next) => {
  ctx.status = 200
  await koaConnect(nuxt.render)(ctx, next)
})

All 13 comments

In [email protected] they reworked the renderer, nuxt.render is now a connect middleware and not an async function like it used to be before. Moreover, it's a "terminating" middleware (it doesn't call next()), so it can't be directly promisified. You need to use a mocked response object, like this:

app.use(async ctx => {
  ctx.status = 200 // koa defaults to 404 when it sees that status is unset

  return new Promise((resolve, reject) => {
    const mockedResponse = {
      __proto__: ctx.res,
      end() {
        ctx.res.end.apply(ctx.res, arguments)
        // nuxt.render doesn't call next() on successful render,
        // resolve promise manually
        resolve()
      }
    }
    nuxt.render(ctx.req, mockedResponse, promise => {
      // nuxt.render passes a rejected promise into callback on error.
      promise.then(resolve).catch(reject)
    })
  })
})

EDIT: Don't use this code, use the updated variant from https://github.com/nuxt-community/koa-template/pull/21

@IlyaSemenov Thanks! I found lib that allows to use connect middleware with koa: https://github.com/vkurchatkin/koa-connect. I use it like this and it works:

import koaConnect from 'koa-connect'

app.use(async (ctx, next) => {
  ctx.status = 200
  await koaConnect(nuxt.render)(ctx, next)
})

@alekbarszczewski Yes I'm aware of koa-connect but it doesn't work correctly.

Add debug output to your code:

app.use(async (ctx, next) => {
  ctx.status = 200
  console.log("koaConnect called")
  await koaConnect(nuxt.render)(ctx, next)
  console.log("koaConnect returned")
})

You will see that await never returns. This is because koa-connect relies on the middleware to call next(), which nuxt.render doesn't.

That most probably leads to a memory leak in Node's async stack in the long run.

@IlyaSemenov Thanks man! I am using your code snippet now and it works (though it looks ugly haha).

Ya, indeed, ugly as hell. I should probably make a PR for koa-connect instead.

Hmm, there is another bug that might be related when in dev mode:

const builder = new Builder(nuxt)
builder.build()

When I have any file in static folder (for example static/images/sprites.svg and I visit http://localhost:3000/images/sprites.svg then it loads forever with no error and no response. However it works when I first nuxt build and then start my custom server in production mode.

Why is this ticket Closed ?
I am having issues with this ...

  • [ ] I know have to include some kind of Promise lib in my dependencies
  • [ ] CSS nano Nuxt package is briging up errors about promises
  • [ ] The solution proposed is ugly

I just "migrated" to express because I had too many problems with it :(

Even after "migrating" to express still had the same issues as running rc-3 in production with the ugly Koa hacks, page just hangs, staying on alpha4

@IlyaSemenov when i use koa template the problem is sitll Can't set headers after they are sent.
use middleware or redirect url like:
res.writeHead(302, {
'Location':'http://baidu.com'
});
res.end();

@shawon1220 Koa documentation clearly says:

Bypassing Koa's response handling is not supported. Avoid using the following node properties:

  • res.statusCode
  • res.writeHead()
  • res.write()
  • res.end()

So it's not a problem with Koa template, it's a problem with you not using Koa properly.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

uptownhr picture uptownhr  路  3Comments

bimohxh picture bimohxh  路  3Comments

pehbehbeh picture pehbehbeh  路  3Comments

vadimsg picture vadimsg  路  3Comments

vadimsg picture vadimsg  路  3Comments