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
The answer was hiding in transform runtime plugin for babel.
Correct .babelrc file:
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.