Hosting Your Single Page Application using Node and Express

10-05-2018

Client side applications are extremely popular and powerful, taking advantage of all the processing power available to the browser. Single Page Applications (SPA) built using frameworks and libraries like Angular, React, and Vue have changed a lot about how we think about developing an immersive user interface. Hosting those applications can be a little tricky however.

When hosting a single page application we have to consider a few factors. Given that our applications are decoupled from our API server we have to configure our request URLs appropriately. This might mean creating a seperate bundled version of the application for each environment, e.g. dev, staging, and production. A simple, but often overlooked change that can result in unexpected behaviors.

We also have to decide on which web server we will use and figure out how to configure it to allow the SPA frameworks routing mechanism to work properly. In the past I’ve used web servers like Apache, Nginx, and IIS. They all work great and have advantages and disadvantages. Almost all of the applications I’m working on these days use NodeJS and Express to create API endpoints which my SPA interacts. Instead of adding another dependency to our infrastructure, I’ve been leveraging NodeJS/ Express to serve my SPA’s static assets, ex: index.html, JS files, etc.

Here’s how I configure Node to serve those files:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
‘use strict’;

const app = express();

app.use(express.static(__dirname + '/static', {
setHeaders: function(res, path, stat){
res.set("Access-Control-Allow-Origin", "*");
res.set('Content-Security-Policy', "connect-src https://*.mydomain.com");
res.set('X-Frame-Options', 'SAMEORIGIN');
res.set('X-XSS-Protection', '1; mode=block');
res.set('X-Content-Type-Options', 'nosniff');
}
}));
....
app.get('*', (req, res) => {
res.redirect('/');
});

This will allow Express to serve assets from the /static directory. All I have to do is bundle up my SPA code and place it in the /static directory. I then configure all of my domain routing to point to my Node Server. Then when a user requests the application Express will see the request to mydomain.com/ and since there are no other matching endpoints Express will serve the index.html file from the /static directory.

With this configuration I also only need to configure my SPA API base URL one time. I won’t need to change it for various environments. The API URL might look something like:

1
2
3
const  apiEndpoint = ‘/api’;

http.get(`${apiEndpoint}/users`)...

Because the API server that is receiving the requests also served the SPA assets the request URL is translated to mydomain.com/api… This let’s me take the same version of the SPA code and copy it to different environments without making any changes.