Server Side Rendering And Pre-Rendering With Nuxt.js
Vue.js
02/04/2019
In my previous article titled Single Page Applications vs. Multi Page Applications, I discussed the tradeoffs using each type of application. One major drawback to using SPAs is that they aren't particularly Search Engine Optimisation (SEO) friendly. This makes it hard for search engines such as Google to index them. Fortunately, two methods have been developed to address this issue: Server Side Rendering (SSR) and pre-rendering. In this tutorial, I'll give an overview of what each method has to offer and how you can implement them in your Vue.js app with Nuxt.js. 💁♂️
SSR and pre-rendering explained
While both methods address the issue of SEO, they both differ in many ways beyond that.
Pre-rendering
If you are solely interested in improving SEO for your SPA, then pre-rendering is the way to go. Sometimes it's also referred to as static site generation, and you're about to see why. The most fundamental difference between pre-rendering and SSR is that the former does not require any server whatsoever. Instead of being rendered on a server and then served to a client, static HTML files are generated for SPA components/routes of your choice when you build your project.
For instance, imagine you want to pre-render your home.vue
and about.vue
components. As a result, you will receive two static HTML files full of content named home.html
and about.html
, which will enable a web crawler to index your site. Afterwards, you can host these static files on a free hosting website like Github or Netlify.
Besides making your website more SEO friendly, pre-rendering also speeds up your initial load time and gets rid of any accompanying UI flickering (unless you were already using Nuxt.js 😜). However, the more routes you'd like to pre-render, the longer your project's build time is going to be.
Server Side Rendering
SSR is like pre-rendering, but more... and is quite often considered an overkill as it isn't easy to implement. So what advantages does this more include? Well, the most distinguishing feature of SSR, the server, is also its greatest asset. Namely, the server can re-render the application anytime and on the fly.
But in which cases is this useful? 🤔 Well, if you expect the content of your application to undergo a lot of changes after deployment, e.g. due to user generated content such as blog posts, SSR is undoubtedly the way to go my friend! On the other hand, you need to go through the process of setting up a server. Furthermore, it needs to be powerful enough to handle the processing, especially under high traffic. Add to this considerably more development time than if you were to simply implement a pre-rendering solution.
Lastly, server side rendered SPAs can also be referred to as "isomorphic" or "universal" apps since the majority of the app's code runs on both the server and the client.
Using Nuxt.js
Whether you're new to or experienced with Vue SPA development, if you haven't tried out Nuxt.js yet, you should consider doing so. It's a Vue.js framework that abstracts away quite a bit of complexity, including our two favourite topics: SSR and pre-rendering 🤓. Naturally, this will make our development experience much more enjoyable.
Pre-rendering
So how do we pre-render a SPA with Nuxt.js? To start off, let's first take a look below at a folder structure from an example project. In this SPA we've got two routes in the pages folder: index.vue
and inspire.vue
.
How would we go about pre-rendering these two routes? Amazingly, Nuxt.js automatically takes care of this task for static routes! By simply running the command npm run generate
, we output the rendered HTML files in a dist
folder as seen below. Nuxt also takes care of any asynchronous data for us during the static page generation. 😍
// dist folderindex.htmlinspire/ index.html
However, for dynamic routes such as pages/users/_id/index.vue
, we will have to inform Nuxt.js how to render these routes since it won't know what the value of _id
is. To address this issue, we have to turn towards the nuxt.config.js
file and add a generate
property.
generate: { routes: function () { return [ '/users/1', '/users/2' ] }}
The code above tells Nuxt that it should generate two HTML pages with the _id
1 and 2. Pretty easy, right? But we're not done yet...
The issue with this solution is that you need to know all of your dynamic routes upfront. This can be difficult and quite a tedious task. Fortunately, we can fetch data, like user IDs, from a database and indicate our desired routes dynamically. In order to do this, we would have to change our previous chunk of code to something like this:
generate: { routes: function () { return fetch('http://chunkbytes.com/userlist') .then((res) => { return res.data.map((user) => { return { route: '/users/' + user.id } }) }) }}
For more information on what the generate
property has to offer, why not check out Nuxt's documentation?
Server Side Rendering
In order to enable SSR in your application, we need to head to our beloved nuxt.config.js
file again and make sure that the mode
property is set to universal
. This tells Nuxt it should create an isomorphic application, i.e. execute SSR and Client Side Rendering. If the mode
property isn't declared, it automatically defaults to universal
. And that's all there is to it! Yes, I'm serious... 😅
To see your application in action, all that's left to do is build it with npm run build
and launch it with npm run start
.
Final thoughts
Nuxt.js is a powerful tool to easily enable SSR and pre-rendering. Yet, the ease of setting these features up should not stop you from thinking twice about whether you truly need them, in particular SSR. However, Nuxt provides a number of other powerful features that should definitely not be overlooked and should be worth your time and consideration.
- Single Page Applications vs. Multi Page Applications
- Understanding The Nuxt.js Folder Structure - The Basics