Serverless-Side Rendering With AWS Lambda & NuxtJS

There are two things that I love right know:

  • Serverless Ecosystem like AWS Lambda
  • The VueJS Ecosystem

One day, I was discussing with some folks in the office about Serverless and Lambdas in general, how to make a lambda, how to use the Serverless framework, create your own REST API, etc.

After that discussion, and given that I am working with VueJS, a simple but crazy idea came up:

“What if we can provide server-side rendering Front End using AWS Lambdas instead of a Virtual Machine?”

I decided to take a look into it using NuxtJS because is my favorite tool for the job and also, AWS just launched the NodeJS 8.10 runtime for AWS Lambda, making this a perfect moment to test this idea and the new runtime.

Where to find the example?

If you want to directly jump to the final version of the code, the repo is available in github right here:

Prerequisites

Setup

First we will need to init a new NodeJS project using yarn (or using NPM) using the next command:

$ yarn init

Then, it’s time to install the dependencies what we will need for this project:

$ yarn add aws-serverless-express axios express nuxt

but, what are these dependencies? let me explain briefly:

  • ExpressJS is a minimalist framework for web development for NodeJS
  • aws-serverless-express is a proxy to run express applications in AWS Lambda (The spine of this project)
  • axios is a HTTP Client for NodeJS and Web Browsers
  • NuxtJs is a Server Side Rendering Framework for VueJS

After installing all the dependencies, we will need a serverless plugin to make this whole thing to work:

$ yarn add -D serverless-apigw-binary

This Serverless plugin automates the process of adding binary files support in API Gateway. (From the Github Repo)

Now, is time to add some scripts to our package.json:

...
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"deploy": "npm run build && sls deploy"
},
...
  • “dev” is to run nuxt locally and test if our pages and layouts work properly
  • “build” is for building the scripts and assets that NuxtJS require to serve static html
  • “deploy” runs project building and uses the Serverless CLI to deploy our function in AWS Lambda.

Configuration

First of all, we need to some config related to NuxtJS and Serverless

NuxtJS Config

In our root folder we will create a file called nuxt.config.js a file designed to contain all the config that NuxtJS needs to be built and run properly. You can check the documentation of the config file in the NuxtJS Site.

I’m just going to point the important parts of this file:

srcDir: 'src/',
performance: {
gzip: false
},
router: {
base: '/dev/'
},
dev: false
  • “srcDir” is self-explanatory; is the path of where all the source files live in the project.
  • “performance>gzip” is for performance configurations, since we don’t want gzip based request (not quite well supported by AWS Lambda), we just disable it.
  • router” is the web path where NuxtJS is going to be triggered, maybe you want the frontend to be executed in /site/ instead of root.
  • “dev” a flag that tells to NuxtJS if the project will run in production mode

Serverless Config

In the root file, you will create a file called serverless.yml that contains all the config needed to deploy our Lambda function in AWS or maybe your function in another provider. You can check the Serverless YAML reference guide in the Serverless documentation.

In the provider config, we set that our function is going to be deployed into AWS using the NodeJS 8.10 runtime and in the region us-east-1 in the dev stage. Our function is going to be called nuxt and the handler of it will be in the handler.js file on the property nuxt, we will se more details of it in the code; and the events that will trigger this function will be HTTP events (via API Gateway) with Any method to any path to support the NuxtJS routing.

The custom part of all this is related to binary files in the response. Since our lambda will provide Static assets like HTML, css and JS, we will need to support these kind of file using the type */*.

Project Structure

Project Structure

Time to code!

First of all, we will need to create the handler.js which serves a the entry file for our Lambda

This file does a couple of things:

  • First, we import our server.js that contains all the config related to Express Middlewares and Routing.
  • We use a “workaround” to serve static files from our lambda.
  • We create our Server object using the Express and MIME configs.
  • Finally, we use the Express Serverless Proxy in our lambda handler.

Express Server file

Since we are using an Express Proxy, we use the same config as always!

What does this file do?

  1. We import the necessary packages to config Express.
  2. We create our Express App.
  3. We set the API Gateway Middleware.
  4. We config the path to access to the NuxtJS static assets.
  5. We add our Nuxt App as a Express Middleware.
  6. We export the Express App to use it in the proxy.

NuxtJS

The time has come! It’s NuxtJS time.

We need to create two folders in the src folder, layouts and pages. The NuxtJS documentation defines these folders as:

The layouts directory contains your Application Layouts.
The pages directory contains your Application Views and Routes. The framework reads all the .vue files inside this directory and creates the application router.

You can check more info about directories in the NuxtJS Documentation.

To serve the root path of our url (Ex: https://mysite.io/), we will create a new index.vue file in the root of the pages dir

This file will render a Hello World like page, but the interesting part of this is that first it will fetch the data of Luke Skywalker from the Star Wars API using and pass it to the template to generate the HTML using the asyncData Method. The NuxtJS define the asyncData Method as this:

You may want to fetch data and render it on the server-side. Nuxt.js adds an asyncDatamethod to let you handle async operations before setting the component data.

You can check more info about the asyncData method in the NuxtJS Documentation.

The next file will be rendered like this:

Our root path is ready 🙌

Next, we will create the next paths:

  • /serverless To show another Hello World like page but it will use a layout for it. Will be handled by the file src/page/serverless/index.vue
  • /serverless/:name To show the param used in the path in a Hello {person} like page. Will be handled by the file src/page/serverless/_name.vue

Since we a re going to use a different layout for this, let’s create the layout folder and the layout to use, in my case I created a layout called serverless.

This layout will only add the Materialize CSS file to our page.

Let’s use our brand new layout in the path /serverless

What this page does is prints a data called type from our Vue object and it will use the serverless layout. It should print a page like this:

/serverless path ready 🙌

And to finish all of these, let’s create the param route /serverless/:name

What this page does, it will use a data called name that will retrieve the param use in the /serverless/:name path, it will render it in the template and then it will use it in the HTML header to generate the title and meta.description tags. The Page should be rendered like this:

It renders my name in the site and in the title 🙌
Hey Look! The title and the meta are in the HTML 🙌

Deploying

It’s time to deploy our lambda, just type the command yarn run deploy to build and deploy your app. It will take a couple of minutes.

Our NuxtJS Site built and deployed!

Conclusion

You can do almost everything in AWS Lambda! I couldn’t believe the first time I made to work this. If you have an Express powered application and you want to go full serverless, take a look to the aws-serverless-express, the migration to AWS Lambda is extremely easy and comfortable. I found a couple of use cases that you might go with this approach:

  • You may want to build a personal website with some degree of dynamism.
  • You may want to save money in idle times for your personal website.
  • You may want a Small Front End to be powered by a headless CMS like Prismic.

If you found more use cases or you want to discuss the mentioned ones, feel free to leave a comment!


🙌 Thanks for reading 🙌

Like what you read? Give Fernando Alvarez a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.