Correct implementation of babel with serverless

1k Views Asked by At

In our project, we've recently decided that for some implementations es6+ functions are making our life a lot easier. However, this "easier" isn't being very translated by babel in combination with serverless.

The project structure is the following:

+
|- serverless.yaml
|- package.json
|- .babelrc
|- /src
   |- handler.js
   |- package.json
|- /test
   |- test.js

This shows the overall project folder. Following are the source code for the individual files.

serverless.yaml

provider:
  name: aws
  runtime: nodejs6.10
functions:
  getHello:
    handler: handler.lambdaGetHello
    events:
      - http:
          path: api/hello
          method: GET
          authorizer: aws_iam
          cors: true
    package:
      include:
        - handler.js
        - node_modules/**

package.json (toplevel, note that this probably has too too many packages, the actual code has more usages, however cleaning this could be in order)

{
  "name": "Default-package-JSON-file",
  "version": "0.1.0",
  "description": "Simple serverless test",
  "scripts": {
    "build": "npm run build:init && npm run build:js && npm run build:install",
    "build:init": "rm -rf dist && mkdir dist && rm -rf src/node_modules && rm -rf src/test",
    "build:install": "cp src/package.json dist/ && cd dist && yarn",
    "build:js": "babel src --out-dir dist",
    "install-base": "npm run install-base:tld && npm run install-base:src",
    "install-base:tld": "yarn",
    "install-base:src": "cd src/ && yarn",
    "svl-deploy": "cp serverless.yaml dist/ && cd dist && serverless deploy",
    "test-dist": "cp -R test/ dist/ && cd dist && mocha",
    "test-src": "cp -R test/ src/ && cd src && mocha"
  },
  "author": "Mathieu Devos",
  "license": "UNLICENSED",
  "dependencies": {
    "add": "^2.0.6",
    "babel-runtime": "^6.26.0",
    "chai": "^4.0.1",
    "mocha": "^3.4.2",
    "serverless": "^1.20.2"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-eslint": "^7.2.3",
    "babel-plugin-transform-async-to-generator": "^6.24.1",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-register": "^6.26.0"
  },
  "private": true
}

.babelrc

{
  "plugins": [
    "transform-async-to-generator",
    "transform-runtime", {
        "polyfill": false,
        "regenerator": true
      }],
  "presets": ["es2015"]
}

src/handler.js (obviously not everything is defined, this is just an example).

async function hello(items = []) {
    const output = [];
    for (const item of items) {
        output.push(await item.handle());
    }
    return output;
};
module.exports.hello = hello;

const lambdaAddItems = (event, context, cb) => {
     const req = new Request(event);
     const args = context.args;
     magicFunction(hello, [args], callback);
};
module.export.lambdaHello = hello;

src/package.json (this one only contains all the different packages needed in src, now this just contains enough to do the Request).

{
  "name": "source-package-json-file",
  "version": "0.1.0",
  "description": "Generic package module for source code",
  "scripts": {},
  "author": "Mathieu Devos",
  "license": "UNLICENSED",
  "dependencies": {
    "lambda-proxy-utils": "^1.2.4"
  },
  "devDependencies": {},
  "private": true
}

test/test.js (tests local code).

const handler = ../handler.js;
const hello = handler.hello;
const lambdaHello = handler.lambdaHello;

...

Run the tests 

So what are we doing to run this code?

We have a pipeline (or a local script if you so please) to run the following commands in order:

npm run install-base npm run test-src npm run build npm run test-dist npm run svl-deploy

Explanation of the different commands: 1) npm run install-base - Installs all the dev dependencies and the commands to run the linting, testing, babel, and serverless. It also goes into /src to install the required pacakges there so that src can run

2) npm run test-src - Copies test to src and runs it, this will test all the code to the local folder (in this case the src folder)

3) npm run build - Removes node_modules & test from src, translates src to dist using babel (this actually properly translates)

4) npm run test-dist - Copies test to dist and runs it, this will test to the local folder in this case dist. Here the problem is that this does not work without --require babel-polyfill command. However the translation is made

5) npm run svl-deploy - Given that everything went fine, deploy to serverless.


The problems appear on step 4, if I run it without --require babel-polyfill I get the error:

regeneratorRuntime is not defined

I can "fix" that with giving the mocha the following command --require babel-polyfill.

However running that leaves my serverless deployment broken.

My question now is: what is the "sane" way of going about this? If possible I want to keep the folder overview like this, as it really clearly shows what's needed where, without cluttering the overall view.

BR, Mathieu

1

There are 1 best solutions below

0
On

The answer was hiding in transform runtime plugin for babel.

Correct .babelrc file:

{
  "plugins": [
    "transform-async-to-generator",
    "transform-runtime"
  ],
  "presets": ["es2015"]
}

with the addition of babel-polyfill in the src/package.json (since serverless needs to be deployed with this).

Alternatives such as using webpack in conjunction with serverless are highly disrecommended.