Implicit serverside rendering in Vue using Nuxt
Have Vue CLI installed on your computer, preferably version 3 Basic knowledge of JavaScript and Vue Have Node.js and NPM setup on your computer
Nuxt came to answer the call of all Vue developers who wanted to render their application on the server. So, if the term — server-side rendering, is a bit confusing to you, do not think about it too much. It can be seen as the equivalent of loading static .html
pages when you visit a URL.
Vue applications by default are rendered on the client. They are generated right there on the browser as you are going through them. This is the core of single page applications. It works excellently as you can build an application in which a user can traverse entirely without having to load any new page.
Even when you reload a URL, the page comes up very quickly, and then the content loads up completely. The downside of this is that you will not have any content on the source of the page. If you are not very conversant with how search engines work, you will never fully understand the harm this does to your application, and potentially your business. Search engines will not be able to see your content, and you may never leave a footprint online.
For Vue applications, Nuxt will change all of that and render the page on the server, generating the necessary HTML and returning it to the user. Take a moment and think about how game-changing this will be for your application. 😃
Prerequisites
- Have Vue CLI installed on your computer, preferably version 3
- Basic knowledge of JavaScript and Vue
- Have Node.js and NPM setup on your computer
Setting up a Vue application
We will build a simple Vue application with Nuxt and another without Nuxt and we can compare the performance and output of both applications. Open your terminal and make two directories:
$ mkdir with-nuxt
$ mkdir without-nuxt
Change your working directory to without-nuxt
and install a Vue application using the Vue CLI tool.
$ cd without-nuxt
$ vue create .
If you do not have Vue CLI installed, run the following command on your terminal to install it globally
npm install -g @vue/cli
Follow the prompt and finish it, the default options are fine. We are not going to create a new component. Vue is nice enough that each installation comes with example components, which is all we need.
Run the application:
$ npm run serve
Open the application and view the source. This is what you will see:
Meanwhile, this is what I see on my browser
If you are screaming “Accessibility issues are way off the chart!!!”, then we might be best friends without knowing. You can see from the view of the page that there is a lot of information on it. However, when we view the source (which is what users without browsers or browsers without JavaScript will see), you can see that many people are already disenfranchised before you even wrote any line of code.
This is a major issue no matter how you want to look at it.
Let’s do it with Nuxt
So, we will do this with Nuxt and see what results we get. From your terminal, change your working directory to the with-nuxt
we created earlier and run the following command:
$ vue init nuxt/starter .
Follow the prompt and finish the installation. Afterward, install the packages:
$ npm install
Then start your Nuxt application
$ npm run dev
And the source:
Now you see that when you use Nuxt, your Vue pages are rendered before they are served. I no longer need JavaScript to at least get the basic juice your site is offering. There will still be some functionalities triggered by JavaScript, but at the core, the information I want to pass across has been communicated in plain text. Can I get a “Nuxt for president!”?
The architecture of Nuxt
Starting from the top, here is what each directory holds in a nutshell:
assets
- things like your SASS and JS files (for example, unminified bootstrap.js) which haven’t been compiled.
components
- the various Vue components of your application.
layouts
- these are like global components that will house other components.
middleware
- these are helper functions that are run before pages are rendered (for example, authentication checks).
node_modules
- all your node modules are here.
pages
- these are pages that are visible to the public with each file forming a route for your application (cool right? 😃).
plugins
- we add plugins we will want to be loaded as our application is instantiated (for example, modal plugin).
static
- this is for things like images, SVGs or even CSS files that will never need to be compiled
store
- all things vuex
Ok. So there are configurations files. package.json
file defines app dependencies and scripts while the nuxt.config.js
file is the main configuration file. In here, you can set things like the mode of the app — if it will be a single page application (SPA) or not, define things like loaders and more.
If you set
mode: 'spa'
in thenuxt.config.js
file, you will no longer get generated HTML code when you load a URL.
Let’s make the second page
In the pages
directory, create a file second.vue
and add the following:
/* pages/second.vue */
<template>
<section class="container">
<div>
<app-logo/>
<h1 class="title">
Second
</h1>
</div>
</section>
</template>
<script>
import AppLogo from '~/components/AppLogo.vue'
export default {
components: {
AppLogo
}
}
</script>
<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
Now, go to /second
on your browser, and you should see this:
So you see that Nuxt automatically creates a route for us based on the name of the files we have in our pages
directory. If you want a route like /services/beta
you will do the following:
- Create a subdirectory named
services
inside thepages
directory - Create a file
beta.vue
inside theservices
directory
Let’s give it a shot. Create the directory and create the beta.vue
file. Then add the following to it:
/* pages/services/beta.vue */
<template>
<section class="container">
<div>
<app-logo/>
<h1 class="title">
Beta
</h1>
</div>
</section>
</template>
<script>
import AppLogo from '~/components/AppLogo.vue'
export default {
components: {
AppLogo
}
}
</script>
<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
If you guessed I was going to copy the previous code and change the title text, then you already know me very well 😆.
Here is the output of the page now
We have finished building… What next?
Deployment obviously. We can either deploy a statically generated application or a server-side rendered application or even a regular SPA.
For a static generated application
This will make HTML pages out of our application. Run the following command:
$ npm run generate
This will create a dist
directory with each of our pages regenerated as HTML files.
Stop for a second and think about how fast your website is going to be with only static HTML pages. No database calls. No server-side language gymnastics. Nothing. Just plain old HTML 😃.
Now, you can upload your dist
directory to your server, and your application will work fine.
For serverside rendered pages
Here, Nuxt will have to parse all your pages and generate the HTML for each one before sending it to the server. It has its upsides which we will consider later.
Run the following commands:
$ npm run build
$ npm run start
Now, your application will be available on the same port as before. You might ask “So, what changed?”. Excellent question. Take a closer look at the following screenshots
This was when we were in development mode
Notice how our pages are built every time before they get served to us? The time for building as we see there might be negligible, but when your app files grow both in size and number, this can cause substantial performance issues.
Compare the above to this:
You will notice that the pages are returned automatically. Nothing is generated as Nuxt has already done all of it with the build.
You can already begin to see the performance improvements with server-side rendering. Removing the build process or the generation of the page on the client side means clients can see your pages faster. It also means you can run away from issues like support for certain JavaScript concepts or even versions completely (in the case of older browsers). Ultimately, you have a more accessible website that clients without JavaScript can still use.
Server-side rendering for president of the world! 💪
Conclusion
In this tutorial, we have looked at what happens behind the scenes with our Vue applications and how it is made better with Nuxt. We have also seen how Nuxt works in a nutshell and the some of the improvements it makes to our existing application.
Now, we can comfortably merge the old (plain old HTML pages) with the new (JS powered client-side applications) and create better applications for our users.
28 September 2018
by Christian Nwamba