Writing koa/nuxt applications
Introduction
You’re ready to make your new application.
You take Vue 2 as your framework
But you want your application to be:
- fast
- bulletproof
So you decide to make a Universal Web Application with Nuxt 2 & Koa 2
It will:
- fasten the first rendering
- be able to run without JS activated on the client side
Notes:
- You will need to be familiar with Koa/Nuxt.
- Be aware that both Nuxt and Koa use the concepts of
context (ctx)
&middleware
.
I’ve tried to differentiate them as much as I could in the following post, but if you’re confused reread carefully and try to sort it out 😅 - You can find a working example of what I’m talking next in the koa-nuxt-example repository
Shaped for express
Because express.js is the most commonly used Node.js server framework, most of the UWA frameworks render function
are shaped for it.
This means that in express, Nuxt integration came out of the box.
You just need to call it like any express middleware:
1 |
|
Since we want to use Koa, we will need to make our own middleware.
No need to think a lot about integration since this has already been solved but the Nuxt community
1 |
|
This will work perfectly if you’re only interested in server rendering.
Handling POST
Let say we want to be able to post a form.
- First we will install/use koa-router and koa-body
- Then with those, we will be able to handle our
POST
action - And we might want to do a database call inside it (
doSomethingAsync
in the example)
1 |
|
This is kind of ok:
- we can now post some data
- redirect to
/
where Nuxt will handle the markup
JSON response can be added by later by
- checking what’s the request
Content-Type
header (ctx.is('application/json')
) - don’t redirect
- send back the appropriate response
Handling errors
We should write an error middleware.
It will make sure that if something went wrong, our application won’t crash.
To catch all the things, it will be our first middleware.
1 |
|
So now if anything throw (DB call, JSON parsing…) we will render a page with the error printed.
Handling Server data with Nuxt
We also should send back some data validation to the user form.
In order to display any validation in the Nuxt application we will need to:
- persist data between our post route and the redirection
- pass those data down to the Nuxt application
- do something with it
Koa-session
The most common way to handle data between routes is with sessions.
We’ll use koa-session for this.
The installation guide is pretty self explanatory.
This will add a ctx.session
object where we can pass any kind of information.
Here is the different steps to follow:
- Validate our form
- Add the validation to the session
- Pass it to Nuxt
- Because Nuxt doesn’t use the Koa
ctx
but usereq
&res
, copy our session information into those objects. - This will be done in a Koa middleware just before the nuxt-rendering middleware
- Because Nuxt doesn’t use the Koa
- Integrate it in the Nuxt application by either using:
- a Nuxt middleware
- the nuxtServerInit for Vuex integration
Right now let’s start withnuxtServerInit
.
- …and since now all is in the Vue realm, just use our Vue Components.
1 |
|
In the store/index.js
1 |
|
And that’s it, we now have a Vuex store updated with our server validation.
Use the mapState helper in our Vue component to access it.
Can’t set headers after they are sent
Right now, we set the validation on our POST route, and never update it again.
It means that the validation will be persisted until the user send a good form.
So if the user change page and go back to the form, the application will still display the last validation result.
This isn’t right, we should clear the validation once displayed.
This should be easy by updating our Koa middleware that link our session to nuxt.
1 |
|
⚠️ But this won’t work
You’ll find in the server logs a Can't set headers after they are sent
.
The problem comes from the nuxtMiddleware
& how it bypasses the regular Koa flow.
Usually we set a ctx.body
and all the previous middleware will continue their work.
But that’s what happen here
To fix that we need to make sure that our headers are set before the Nuxt middleware.
autoCommit: false to the rescue
Koa-session lets us send the headers manually with the manuallyCommit() method
So we have to refactor our server code like this:
1 |
|
This will solve our problem ❤️
We just have now to remember calling manuallyCommit()
every time we update the session… 😶
Displaying all errors with Nuxt
There is one last thing we have to take care of.
Right now our handleError
middleware will make Koa show the error.
But Nuxt support an error layout and we should take advantage of it.
To do this we’ll need to modify our handleError
middleware:
- set the error to the
ctx.req
object (Remember Nuxt still only work withreq
&res
) - call Nuxt to render the page inside our
handleError
middleware - write a Nuxt middleware that will render the error page by calling nuxtContext.error
1 |
|
And for the Nuxt part:
- create a
middleware/handle-server-errors.js
file - reference it in the
nuxt.config.js
1 |
|
Conclusion
Making Nuxt working with Koa isn’t as smooth as with Express.
Still I prefer working with Koa, and with a little more boilerplate everything’s fine.
I’m sure there is room for improvements, but it’s working for me.
The downside is mainly more boilerplate code and handling session updates manually.
Most of the code here isn’t necessary if
- you just want some basic server rendering
- you don’t need to support any kind of session
Supporting asynchronous code should be easy
- Koa is build around that
- nuxtServerInit supports async function
- the same goes for Nuxt middleware
As a reminder you can find a full example here
💚 Nuxt 💙 KOA