Server-Side Rendering a Single Page App on Section

May 8, 2019

This article breaks down how to use Section’s Node JS module to spin up a server-side rendering framework for Vue JS (or any other front-end framework).

The transformative benefits that edge computing promises cover a wide range of objectives and use cases. While many are obsessing over IoT applications, others in more mainstream industries, such as e-commerce, are starting to adopt microservices strategies to reap the benefits of edge computing.

We recently collaborated with one of our e-commerce clients, Adore Beauty, to deploy their Nuxt app at the edge using the Section Edge Compute Platform. While this walk-through is specific to Nuxt.js (a Vue.js framework), the same fundamentals can be adapted to other single page apps, such as React or Angular.

Architecture Overview

Section sits between the client and origin server, acting as a proxy for web traffic requests. Within Section’s container-based (Docker/Kubernetes) platform, all edge modules exist as a single container, including the Node JS module. Everything is managed through code, meaning there is no manual work needed during deployments. Let’s take a look at each of the components within this architecture.

node js module edge computing

Edge Proxy

Every Section application proxy stack implicitly begins with the Edge Proxy. The Edge proxy is the endpoint to which the User-Agent (e.g. web browser) connects, and it has a few responsibilities:

  • Performing the TLS handshake for HTTPS connections
  • Routing requests to the corresponding application edge module stack
  • Implementing the HTTP/2 protocol
  • Request correlation
  • Serving custom error pages
  • Request enrichment with geo headers, etc.

Users may choose to configure any number of edge modules within their edge stack. This example is highlighting the Node JS module, but most customers employ additional module layers, such as caching, bot blocking, web application firewall (WAF), etc., to meet the demands of their application. Within the Section platform, users can configure the order of their edge stack, along with the individual module configuration itself.

Node JS module

Inside the Node JS module, on Port 80, there is an Nginx web server. The server configuration, or location blocks, are specified by the user in the server.conf file that lives in the root of the Node JS module repository. Some requests you may want to pass along to the Node JS module and others along to the next-hop, whether that’s the next module in the stack (e.g. image optimizer module, A/B testing), or in this example, directly to the Last Proxy.

Inside the Node JS module lives the repository that contains the source code for the application that you want to run at the edge. Within this code base, there are a few minimum requirements that must be included:

  • There must be a package-lock.json file present.
  • You must have an npm start script in your package.json file to tell the container how to start the web server, or to start the application in general.
  • Your web server, whether using built-in Nuxt, Express.js, native Node.js HTTP module, Koa, etc., must listen on process.env.PORT to determine exactly which ports the application runs on. (We have adopted these specs as a standard from other providers like Heroku and AWS Lambda.)

In this example, the basic flow upon first deploy is as follows:

  • Copies the custom server.conf file and puts it into /etc/nginx/ directory
  • Runs npm install to install node modules
  • Runs npm start to start the application, which in turn kicks off the start script that:
  • Runs npm run build, which runs nuxt build
  • Runs nuxt server to start the built-in Nuxt web server using process.env.PORT
  • Starts Nginx to start accepting requests, where routing is controlled based on configurations

sample start script:

"scripts": {
  "dev": "nuxt",
  "build": "nuxt build",
  "start": "npm run build && nuxt start",
  "generate": "nuxt generate",
  "serverbuild": "nuxt build",
  "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
  "precommit": "lint-staged",
  "ngrok": "ngrok http 3000 -region=au"
}

For Adore Beauty, the front-end framework (i.e. Nuxt app) calls a Laravel API which houses all product, category, and pricing information.

This initial version of the Node JS module uses blue-green deployments for updates, but we’re actively working on migrating to a rolling deployment model, where Kubernetes will add an annotation to the deployment which triggers a new deployment, spins up a new pod for the Nuxt app, and routes traffic over when it’s healthy.

Last Proxy

The Last Proxy uses the X-Forwarded-Proto HTTP Header to determine which protocol to use when communicating with the Origin server. For Adore Beauty, the Origin is a Magento instance, where all of the shopping cart and checkout functionality is managed.

The Results

Adore Beauty now has a distributed Vue.js server-side rendering framework for which they needn’t worry about the infrastructure on which their app is running, and have configured their native Bitbucket pipeline to automatically deploy to Section on a git push to their master branch.

We’ve outlined a specific use case here, but hopefully, you can begin to see how this example can be adapted to other frameworks, web servers, use cases, etc. In fact, this is what excites us most about the future of edge computing … the possibilities are endless! What will you create?