Serverless-side rendering with Vue.js and Nuxt.js

This project demonstrates how to use Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.

Use-cases

  • Develop single-page apps without worrying about SEO optimization.

Benefits

  • SEO boost server-side rendering provides
  • Speed of a Single Page Application
  • Cheap hosting in a serverless environment on AWS Lambda
  • Easy deployment with the Serverless Framework
  • Can easily integrate with your own API or 3rd party APIs such as headless CMS, e-commerce or serverless architecture.

How it works

Well, first thing's first. We want a super fast Single Page Application. But, this usually comes with a cost. Lousy SEO capabilities. That won't do, meaning we also want the app to have server-side rendering. Okay, sounds simple. We'll grab Nuxt.js, which is a framework for creating universal Vue.js applications, and configure it to server-side render our pages.

To accomplish this we need to spin up a simple Express server and configure the Nuxt renderer to serve files through Express. It is way simpler than it sounds.

Setup

Deploy

  1. Deploy service without custom domain:

    $ npm run deploy

    Output:

    > aws-node-vue-nuxt-ssr@1.0.0 deploy /home/raha/code/serverless/examples/aws-node-vue-nuxt-ssr
    > npm run build && sls deploy
    > aws-node-vue-nuxt-ssr@1.0.0 build /home/raha/code/serverless/examples/aws-node-vue-nuxt-ssr
    > nuxt build
    Hash: 969f557230f1916aaab2
    Version: webpack 4.31.0
    Time: 5531ms
    Built at: 05/14/2019 12:22:28 AM
    Asset Size Chunks Chunk Names
    ../server/client.manifest.json 6.81 KiB [emitted]
    1aeb026dc2ca77c8b429.js 952 bytes 3 [emitted] pages/dogs/index
    775caefedab77dd6e1a6.js 147 KiB 1 [emitted] commons.app
    92fcd17f0b85f40f90ad.js 1.15 KiB 2 [emitted] pages/dogs/_breed
    9f5aaac1c101c273e65f.js 845 bytes 4 [emitted] pages/index
    LICENSES 464 bytes [emitted]
    cf8b2abbbaec4a0c7b76.js 2.27 KiB 5 [emitted] runtime
    fa6324eac05d1b7d36b0.js 42.3 KiB 0 [emitted] app
    + 2 hidden assets
    Entrypoint app = cf8b2abbbaec4a0c7b76.js 775caefedab77dd6e1a6.js fa6324eac05d1b7d36b0.js
    Hash: ac61088f50920f2fc1a4
    Version: webpack 4.31.0
    Time: 1266ms
    Built at: 05/14/2019 12:22:30 AM
    Asset Size Chunks Chunk Names
    92cd2f7d0e5f9c484439.js 641 bytes 2 [emitted] pages/dogs/index
    bbeb65244f57ade7cfbe.js 828 bytes 1 [emitted] pages/dogs/_breed
    e3465bc88d2bf9e1b91d.js 536 bytes 3 [emitted] pages/index
    server.js 25.1 KiB 0 [emitted] app
    server.manifest.json 483 bytes [emitted]
    + 4 hidden assets
    Entrypoint app = server.js server.js.map
    Done in 9.03s
    Serverless: Packaging service...
    Serverless: Excluding development dependencies...
    Serverless: Creating Stack...
    Serverless: Checking Stack create progress...
    .....
    Serverless: Stack create finished...
    Serverless: Uploading CloudFormation file to S3...
    Serverless: Uploading artifacts...
    Serverless: Uploading service .zip file to S3 (42.47 MB)...
    Serverless: Validating template...
    Serverless: Updating Stack...
    Serverless: Checking Stack update progress...
    .................................
    Serverless: Stack update finished...
    Service Information
    service: serverless-side-rendering-vue-nuxt
    stage: dev
    region: us-east-1
    stack: serverless-side-rendering-vue-nuxt-dev
    api keys:
    None
    endpoints:
    ANY - https://<api_id>.execute-api.us-east-1.amazonaws.com/dev
    ANY - https://<api_id>.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
    functions:
    nuxt: serverless-side-rendering-vue-nuxt-dev-nuxt

    Once deployed you'll have your app running on a default API Gateway URI.

  2. Create domain:

    Uncomment domain settings in serverless.yaml.

    [...]
    plugins:
    - serverless-apigw-binary
    - serverless-domain-manager # uncomment the plugin
    - serverless-offline
    [...]
    custom:
    secrets: ${file(secrets.json)}
    apigwBinary:
    types:
    - '*/*'
    customDomain: # uncomment the whole customDomain section
    domainName: ${self:custom.secrets.DOMAIN}
    basePath: ''
    stage: ${self:custom.secrets.NODE_ENV}
    createRoute53Record: true

    Run the create domain command:

    $ sls create_domain

    This will take a few minutes, go grab a coffee in the meantime. :smile:

  3. Re-deploy the service with the domain settings:

    $ npm run deploy

    Output:

    [...same as above but also with the domain info]
    Serverless Domain Manager Summary
    Domain Name
    vuessr.yourdomain.com
    Distribution Domain Name
    <cdn_id>.cloudfront.net

Usage

Navigate to vuessr-yourdomain.com or whichever domain you picked. You'll see the Vue.js SPA running.


I've written a detailed tutorial about the process. You can check it out here. (NOTE: Some parts are outdated and are for nuxt@1. Please refer to this example for using with nuxt@2)