Implicit serverside rendering in Vue using Nuxt

Introduction

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:

1$ mkdir with-nuxt
2    $ mkdir without-nuxt

Change your working directory to without-nuxt and install a Vue application using the Vue CLI tool.

1$ cd without-nuxt
2    $ 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:

Vue default console

Meanwhile, this is what I see on my browser

Vue homepage

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
Homepage with Nuxt

And the source:

Page source with Nuxt

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

Nuxt app structure

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 the nuxt.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:

1/* pages/second.vue */
2    
3    <template>
4      <section class="container">
5        <div>
6          <app-logo/>
7          <h1 class="title">
8            Second
9          </h1>
10        </div>
11      </section>
12    </template>
13    
14    <script>
15    import AppLogo from '~/components/AppLogo.vue'
16    
17    export default {
18      components: {
19        AppLogo
20      }
21    }
22    </script>
23    
24    <style>
25    .container {
26      min-height: 100vh;
27      display: flex;
28      justify-content: center;
29      align-items: center;
30      text-align: center;
31    }
32    
33    .title {
34      font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
35      display: block;
36      font-weight: 300;
37      font-size: 100px;
38      color: #35495e;
39      letter-spacing: 1px;
40    }
41    
42    .subtitle {
43      font-weight: 300;
44      font-size: 42px;
45      color: #526488;
46      word-spacing: 5px;
47      padding-bottom: 15px;
48    }
49    
50    .links {
51      padding-top: 15px;
52    }
53    </style>

Now, go to /second on your browser, and you should see this:

Second page

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 the pages directory
  • Create a file beta.vue inside the services directory

Let’s give it a shot. Create the directory and create the beta.vue file. Then add the following to it:

1/* pages/services/beta.vue */
2    
3    <template>
4      <section class="container">
5        <div>
6          <app-logo/>
7          <h1 class="title">
8            Beta
9          </h1>
10        </div>
11      </section>
12    </template>
13    
14    <script>
15    import AppLogo from '~/components/AppLogo.vue'
16    
17    export default {
18      components: {
19        AppLogo
20      }
21    }
22    </script>
23    
24    <style>
25    .container {
26      min-height: 100vh;
27      display: flex;
28      justify-content: center;
29      align-items: center;
30      text-align: center;
31    }
32    
33    .title {
34      font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
35      display: block;
36      font-weight: 300;
37      font-size: 100px;
38      color: #35495e;
39      letter-spacing: 1px;
40    }
41    
42    .subtitle {
43      font-weight: 300;
44      font-size: 42px;
45      color: #526488;
46      word-spacing: 5px;
47      padding-bottom: 15px;
48    }
49    
50    .links {
51      padding-top: 15px;
52    }
53    </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

Beta page

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.

Dist directory

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:

1$ npm run build
2    $ 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

In development

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:

Serving a static site

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.