VueJs: Server Side Render with Vue-Router

Improve your app’s speed by rendering pages before returning them

Image for post
Image for post

The aim of this piece is to provide all the information you may need to work out whether server-side render (SSR) is an approach you should consider. We’re also going to go through a basic (but not necessarily simple) example of how to configure and use SSR with vue-router.

I’ve written a shorter, implementation focused, version of this article in Anthony Gore blog (without any extra information about server-side render). Just in case you are interested only in the implementation I leave the link here: Vue.js Server-Side Rendering With Vue Router: Step-By-Step Guide

When Should I Consider Using SSR?

There are two main reasons to use SSR.

  • Better SEO. Search engine crawlers are going to see a fully rendered page when the application loads since the server is the one building that first loaded page.
  • Faster time-to-content. Since the first render is entirely built by the server, you get a fully-rendered page from the client side much quicker. This gives a better user experience and is really important for apps where time-to-content plays a critical role.

So if SEO or time-to-content is critical for your app you should probably use SSR no matter what the trade-offs are. In any other scenario, think twice and be certain you’re going to win more than you’re going to lose because the trade-off is not cheap. If your only concern is improving SEO there are other techniques to consider — like prerendering.

Trade-Offs

There are at least three major things you need to consider before choosing to use SSR.

  • Some three-party libraries may need some manipulation to be able to run in an SSR app.
  • SSR requires an environment where Node.js server can run.
  • This is going to be more expensive for a server than just serving static files, so, if your application has or expects high traffic, be prepared to deal with high server load.

Full Basic Implementation

Before jumping into the actual implementation there are some main concepts that you need to understand:

  • SSR consists of first creating a fully loaded version of the app for the actually requested route on the server. Once that page is rendered on the client-side, the client-side code takes ownership.
  • You are going to need two entry building points for your app — one for the server and one for the client.

The configuration is not simple and the information on the web about SSR using vue-router is, at this moment in time, rather poor.

So let’s hope the following example brings some clarity to the subject.

Dependencies

Let’s go through the dependencies we have to install.

  • We are going to use a template to start that has already configured a basic webpack build for a vueJs app. We are also going to need to install vue-cli:
Image for post
Image for post

Now we need to install all the dependencies of the webpack-simple template. Up to now, nothing is related to SSR — we’re just setting a general vueJs environment.

Image for post
Image for post
  • So now we have a vueJs project ready to start adding SSR configuration. But first, we need to add three dependencies, all related to SSR.
Image for post
Image for post
  • vue-server-render: Vue library for SSR.
  • vue-router: Vue library for SPA.
  • express: We need a NodeJS server running.
  • webpack-merge: We are going to use it to merge webpack configuration.

Webpack configuration

We are going to need two webpack configurations — one to build from the client entry file and one to build from the server entry file.

For our base webpack configuration we are just going to use the one that comes with the template we installed, except that we’re changing the entry to entry-client.js.

Image for post
Image for post

Let’s now add the server webpack configuration:

Image for post
Image for post

There’s nothing strange here except two things,: The entry is entry-server.js and for the output, we’re using commonjs as a library target.

That’s the webpack configuration. Now let’s see the scripts for building the app in packages.json.

Packages.json build scripts

You can change this to fit your needs but there are three steps you need to perform to start your application:

  • Build the client-entry
  • Build the server-entry
  • Start the server
Image for post
Image for post

In the configuration, we are using the start script that runs the three steps we just mentioned. But we have set scripts to run them separately if needed.

Folder structure

Image for post
Image for post
  • The dist folder is created by webpack when building the node_modules (well, you know this!).
  • src contains our Vue app. Inside you’ll find the server and client entry points, the Vue main.js file, the App component, a folder for the components (we have home and about components), the router folder containing the router configuration, and finally the assets folder.
  • .babelrc, .gitignore, packages.json — you probably know what they are.
  • index.html is the main HTML for our app.
  • server.js is the server configuration and starting file.
  • Finally, the two webpack configurations that we already talked about.

Index HTML

This is our main HTML file.

Image for post
Image for post

There are a couple of things to discuss:

  • I have added some interpolation to this template to populate that data later on the server. Is a functionality of Vue server-side render that I wanted to show.
  • We target the build.js that’s the result of the client bundle generated from webpack.

APP.vue component

This component is the root component of our app and it has a couple of responsibilities:

  • Configuration for menu using vue-router links.
  • Set the container for the route’s components to render.
  • Set the element with the id app, used for mounting the client-side part of the application.
Image for post
Image for post

Router file configuration

Since our application is going to start on the server, we need to provide a new instance of the router for each server request. Inside the router folder, we are going to have a file with our router config:

Image for post
Image for post

Let’s go through the code:

  • We import all the dependencies we needed.
  • We tell Vue to use vue-router.
  • We export a function that provides a new instance of the router configuration.
  • We instantiate the router in history mode and with the configuration of the two routes we’re going to handle.

Main Vue file configuration

For the same reason that we need to provide a new router instance, we need to provide a new app instance. This file has the responsibility of starting the router and the root app component.

Both the server and client entry points will use this file.

Image for post
Image for post

Let’s go through the code:

  • We import all the dependencies needed.
  • We export a function that provides a new instance of the app and the router.
  • We instantiate the router using the method we saw before in the `route.js` file.
  • We create a new app instance with the router and the render, passing the root app component.
  • We return both instances.

Client entry point

This code is quite straightforward. This is the entry file for the webpack client build configuration.

Image for post
Image for post

Let’s go through the code:

We import all the dependencies needed.

We create the app from the main.js file and keep the app instance.

We mount app in a node with the id set to app. In the case of this example, the node containing that id is the root element of the template of App.vue component, as mentioned before.

Server entry point

This file is the entry point for webpack server build. The result of that build is what we are going to target later when we configure the server.

Image for post
Image for post

Let’s go through the code:

  • We import all the dependencies needed.
  • We export a function that receives a context as param.
  • The functions return a promise.
  • We instantiate app and router from `main.js` create app function.
  • We get the current URL from the context (this is going to be provided by the server) in order to push the correct URL to the router.
  • Once the router is ready we check that a route matches the context URL. If it does we resolve the promise and return the app instance. If not we reject the promise.

Configuring and starting the server

We have almost everything ready. The only thing missing is the configuration and start-up of the express server:

Image for post
Image for post

And you thought it was too much before! Don’t worry let’s dig into the code and see what’s going on:

  • We’re importing express to create the server, we’re also importing some node js functionalities.
  • We import the server bundle that’s the result of the webpack server build.
  • We import the vue-server-renderer library and create the rendering providing the index.html location for the template.
  • We configure the express path.
  • We start the server.
  • The bundle is the result of building the serve-entry.js with webpack, so we can use the default function that receives the context as a param with the URL. Since it is a promise we set a success with and an error callback.

The success callback does a bunch of stuff so let’s go through that too:

  • We create a const with the data that is going to be interpolated in the index.html (we saw the interpolation in this HTML before).
  • We call the render to string function of the renderer that receives the app (returned by the resolved promise), the context that we just created (to use the interpolation in the index — this is optional), and the callback function if everything works well.
  • The render to string callback function checks if there are any errors. If not it just sends the generated HTML as a response.

Finally, we start listening to the port 8080.

Now if you run the script `start` and open the `localhost:8080` in the browser you are going to see things working SSR and vue-router.

And that, ladies and gentlemen, is it!

Conclusion

I don’t think I need to say that that is a lot of configuration to make things work! However, once it’s done you don’t have to touch it a lot. Just be sure SSR is what you need.

I leave you with the Github project.

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store