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 :

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.

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.

vue-server-render : Vue library for SSR.

: Vue library for SSR. vue-router : Vue library for SPA.

: Vue library for SPA. express : We need a NodeJS server running.

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

Let’s now add the server webpack configuration:

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

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

The dist folder is created by webpack when building the node_modules (well, you know this!).

folder is created by webpack when building the (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.

contains our Vue app. Inside you’ll find the server and client entry points, the Vue file, the component, a folder for the components (we have and components), the router folder containing the router configuration, and finally the assets folder. .babelrc , .gitignore , packages.json — you probably know what they are.

, , — you probably know what they are. index.html is the main HTML for our app.

is the main HTML for our app. server.js is the server configuration and starting file.

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.

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.

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.

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:

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.

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.

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.

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:

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.

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.

library and create the rendering providing the location for the template. We configure the express path.

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 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!