Photo by Ravi Kant from Pexels

Data Rich SPA with NGINX

Gregory Tomlinson (GT)
disney-streaming
Published in
5 min readDec 8, 2021

--

How we are serving Single Page web Applications (SPA) at Disney Streaming. This post will give a brief overview of our approach. In concert with this blog post, we are also releasing a template repository. This repository will allow you to get started using the NGINX web server to build and serve JavaScript SPA.

We have been exploring, with great success, using the web server NGINX and Docker containers to deploy JavaScript SPA. This post will review a few highlights of this technical approach and walk through some of the code. We think using NGINX for SPA in full stack engineering teams is a good approach. This post doesn’t address build tool chains. The sample code uses React without JSX.

When it came time to build a platform tool that would allow internal employees to view movies and series metadata from the Disney+ and Star+ Digital Media Catalog, it was a chance to start something from scratch. The autonomy that Disney Streaming affords each team to make the best technical choices for a software project meant that our team could choose freely from a variety of languages and frameworks. However, our deployment infrastructure requires containerization.

Photo by Antonio Batinić from Pexels

At Disney Streaming we use this template repository as the basis for our internal tools. These tools do not require any Search Engine Optimization (SEO). For our purposes, we needed a Single Page Application that would make heavy use of existing, independent APIs. And, our apps don’t require any specific pre-processing of HTML. After some debate and a few draft Request for Comments (RFC), we settled on the plan of using NGINX.

One important consideration for us is environment alignment. In other words, we want our development environment server and production server to be closely aligned. The closer the better. To accomplish this goal we employ docker-compose and NGINX. That’s the core of the work that we are presenting today. We have created a public template repository that provides the minimal essential configuration for using docker-compose & NGINX to build Single Page Applications. We believe it provides a basic building block for others to base their own JavaScript SPA, which can be deployed via a container.

https://github.com/disneystreaming-blog-snippets/spa-nginx

To get started, clone the above repository. There are two tools required: 1. docker-compose and 2. yarn. Both are industry standard tools that many developers already have in their toolbox. Once the repository is cloned, run these commands in a terminal window.

yarn install
yarn start

We can view the “Welcome” message by visiting http://localhost:7000 in a web browser such as Google Chrome.

A quick tour of the template repository spa-nginx is in order. It’s simple and straight to the point. There are a JS, CSS and HTML file. That’s all of our app client files. The command yarn start can be found in the package.json file under “scripts” and last bit of glue is the docker-compose.yaml file. It’s going to handle mapping our nginx.local.conf file into the container as well as mapping our single page application files from the static/ directory into the container.

Diving into the code, let’s look at the docker-compose.yaml file. We are leveraging docker-compose volumes to map our Single Page Application code into the standard NGINX docker image.

Starting with line no. 9, we map in our custom nginx.local.conf, as well as our vendor libraries and our app JavaScript files. We map the static files into the docker container to be served by NGINX. The file nginx.local.conf is mounted over the NGINX default.conf configuration file. The folder node_modules/ is also mapped into the container at the path /mnt/app/node-static and finally the static folders: JS, CSS and the HTML are mapped into the NGINX container via the static/ folder.

Now, let’s look closely at our barebones NGINX configuration file. It’s fairly self explanatory. It contains three location blocks. One detail to note is the alias path matches the path assign in the docker-compose.yaml file.

The above file handles routing HTTP requests to the correct resources in the container. In the NGINX configuration file is a location block for ^~ /static/js/vendor(line 20), which serves any packages added via the yarn add command. In addition, there is a location block for the remaining static files. The last location block starting on line 34 handles the SPA portion of the JavaScript application. We can see that from lines 9–16; 23–30 and 37–44 we are disabling all caching. That’s because this is for development. In production, we would not want to disable these features.

The third file to review is static/js/main.app.js.

It’s a very simple JavaScript web router. NGINX handles the SPA aspects. It is going to serve the same HTML file, which is found in static/html/index.html, for all URLs that don’t start with /static. In the JavaScript router, we will trigger a method based on the path. For demonstration purposes, a second route — line 13 — has been added as well as a 404 handler on line 19. We can view that second route in the browser at http://localhost:7000/page/two and the 404 route handler at http://localhost:7000/this/page/404

The last file to examine is the static/html/index.html file.

Notice that on lines 10–12, we include our vendor libraries. In this case, React, React-DOM and underscore.js. Line 13 includes our entry point JS file with the special type module. This allows our application to leverage ESM, which allows the SPA to use import such as the import found on line 3 of static/js/main.app.js.

We can easily expand on this example by continuing to develop an application with React, or leverage the basic setup to install a different web framework. In either case, this project should serve as a building block and reference for how to serve data rich SPA with NGINX.

Caveats

The library selected for this single page application is React and some utilities. These are primarily for demonstration purposes. While we chose to use React for our project, it’s not required. The choice for web framework isn’t limited to this example. In addition to React, this template repository also contains starter configuration files for both ESLint and Stylelint. While we have found these useful, they are by no means required. This repository isn’t intended to be “production-ready”. It is, however, a building block to begin a future project or future refactoring for any team.

--

--