Deploying a Serverless application (using Webpack and Babel to support ES2015) to AWS

Until now, we know how to start our serverless application in a local environment. We can test it and even save things in a local DynamoDB.

It’s moment to finally deploy to AWS!

The Serverless Framework makes deploying a simple task. Run one command and (as long as you have an AWS key configured in your local environment) all the resources required for your application will be deployed.

However, there are still a few kinks we need to address.

In previous posts I told a half-lie without realizing: AWS supports ES5 in NodeJS, but not completely. In NodeJS 6.10, modules are still not supported.

In our TacoGallery application we are already using “import” instead of “require” to include dependencies. Oh-oh.

Fortunately, Serverless has plugins to use Webpack and Babel to bundle and transpile our application into something AWS can comfortably execute.

The serverless-webpack plugin will build our code when we deploy our application. Install it with the following command:

npm install serverless-webpack --save-dev

Add the following to your serverless.yml file:

plugins:
  - serverless-webpack

We already have a .babelrc file from previous posts, but if you don’t, create one:

{ "presets": ["es2015"] }

Just to make sure Webpack has everything it needs to transpile our code correctly, install the following Babel dependencies:

npm i --save-dev babel-loader babel-core babel-preset-es2015

By default, the plugin will look for a webpack.config.js file in the root folder, so let’s add one:

var nodeExternals = require('webpack-node-externals')

module.exports = {
   entry: './handler.js',
   target: 'node',
   externals: [nodeExternals()],
   output: {
      libraryTarget: 'commonjs',
      path: '.webpack',
      filename: 'handler.js', // this should match the first part of function handler in serverless.yml
   },
   module: {
      loaders: [
         {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            loaders: ["babel-loader"]
         }
      ]
   }
};

Note we are importing a dependency webpack-node-externals, and we’re putting it in the externals section of our file. This will prevent Webpack from bundling dependencies in node_modules like AWS, which are already included in AWS Lambda.

However, we do want a few dependencies to be bundled. To control what is bundled and what is not, the serverless-webpack plugin leverages our package.json file to do this filtering: everything in dependencies will be bundled; everything in devDependencies wont:

"dependencies": {
  "babel": "^6.23.0",
  "babel-core": "^6.23.1",
  "babel-preset-es2015": "^6.22.0",
  "jsonschema": "^1.1.1",
  "serverless-dynamodb-client": "0.0.2",
  "uuid": "^3.0.1"
},
"devDependencies": {
  "aws-sdk": "^2.20.0",
  "babel-core": "^6.24.0",
  "babel-loader": "^6.4.1",
  "babel-preset-es2015": "^6.24.0",
  "chai": "^3.5.0",
  "dynalite": "^1.1.1",
  "jsonschema": "^1.1.1",
  "mocha": "^3.2.0",
  "serverless-dynamodb-local": "^0.2.19",
  "serverless-offline": "^3.10.2",
  "serverless-plugin-simulate": "0.0.10",
  "serverless-webpack": "^1.0.0-rc.4",
  "webpack-node-externals": "^1.5.4"
}

We can configure where our package.json file’s location is by adding the following property to serverless.yml:

custom:
  webpackIncludeModules:
    packagePath: './package.json'

Before we deploy, make sure your serverless.yml file points to the AWS Region you want your application to be deployed to; and since we’re still on development, set the stage property to dev:

provider:
  name: aws
  runtime: nodejs6.10
  region: us-east-2
  stage: dev

Now, you’re ready to deploy. Execute the following command:

serverless deploy

After a few log lines show in console, you will see the URL where the Serverless Framework deployed our AWS Lambda exposed by the API Gateway.

We have a test enpoint hello which will let us confirm the application was deployed correctly:

Navigate to the URL provided by the Serverless console, plus the URL path “hello”

You can confirm everything is working by navigating to AWS web console, select the Lambda service (make sure you’re in the same Region you choose to deploy) and click on Test:

Successfully executing our Lambda function in the AWS web console

Like we always do, let’s list all the files we changed in this post:

There is big concern here, can you point it out?

Our API Gateway endpoint is not secured! Anyone who knows what our URL is can access it. Since our endpoint connects to DynamoDB, we have an open door to anyone who wants to add data to our application.

In our next post, we will learn how to secure our API Gateway endpoints.