I want to deploy AWS Lambda functions with Node8.10 and Ruby2.5 runtimes from one serverless.yml file.
I set up the following folder structure, with /node and /ruby holding my respective handlers.
-/nodeRubyLambdas
-/node
-handler.js
-package.json, package-lock.json, /node_modules
-/ruby
-rubyRijndaelEncryption.rb
-Gemfile, Gemfile.lock, /vendor
-serverless.yml
-webpack.config.js
-package.json for serverless-webpack
Here is my serverless.yml
service: nodeRubyLambdas
plugins:
- serverless-webpack
- serverless-offline
custom:
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
provider:
name: aws
stage: dev
region: us-west-2
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "*"
package:
individually: true
functions:
nodeMain:
handler: node/handler.main
runtime: nodejs8.10
events:
- http:
path: main
method: get
package:
individually: true
rubyEncryption:
handler: ruby/rubyRijndaelEncryption.lambda_handler
runtime: ruby2.5
environment:
RIJNDAEL_PASSWORD: 'a string'
package:
individually: true
My webpack configuration: (This is the base example, I just added the bit to ignore ruby files when I got my first error.)
const slsw = require("serverless-webpack");
const nodeExternals = require("webpack-node-externals");
module.exports = {
entry: slsw.lib.entries,
target: "node",
// Generate sourcemaps for proper error messages
devtool: 'source-map',
// Since 'aws-sdk' is not compatible with webpack,
// we exclude all node dependencies
externals: [nodeExternals()],
mode: slsw.lib.webpack.isLocal ? "development" : "production",
optimization: {
// We do not want to minimize our code.
minimize: false
},
performance: {
// Turn off size warnings for entry points
hints: false
},
// Run babel on all .js files and skip those in node_modules
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: __dirname,
exclude: [/node_modules/, /\.rb$/]
}
]
}
};
Fail #0: [Webpack Compilation error] Module parse failed
Fail #1: Basically, webpack assumes all functions are .js and tries to package them as such. Based off this suggestion, I forced my entry point in webpack config to be my handler.js
module.exports = {
entry: "./node/handler.js",
target: "node",
...
This packages ONLY the Node Lambda. An empty placeholder for the Ruby Lambda is created on AWS.
Fail #2: I commented out webpack from serverless.yml and added include and exclude statements in the functions package options.
functions:
nodeMain:
package:
individually: true
include:
- node/**
- handler.js
exclude:
- ruby/**
- rubyLambda/**
rubyEncryption:
package:
individually: true
include:
- vendor/**
- rubyRijndaelEncryption.rb
exclude:
- Gemfile
- Gemfile.lock
- node/**
This gets an [ENOENT: no such file or directory] for node/node_modules/@babel/core/node_modules/.bin/parser. This file is not there but I don't understand why it is looking for it, since webpack is not being called.
Sort of success?: I was able to get the Lambdas to deploy if I commented out webpack and used
serverless deploy function -f <function name here>
to deploy the Ruby Lambda and then uncommented webpack and used the same thing to deploy the Node Lambda.
I'm convinced that there's a better way to get them to deploy; Have I missed something in my setup? Is there another option I haven't tried?
P.S. I did see this pull request https://github.com/serverless-heaven/serverless-webpack/pull/256, but it seems to be abandoned since 2017.
serverless-webpack
is not designed for non-JS runtimes. It hijacks serverless
packaging and deploys ONLY the webpack output.
Here are your options:
serverless-webpack
and simply use serverless
' built-in packaging.webpack
directly (not serverless-webpack
), and change your build process to compile using webpack
first and then let serverless
deploy the output folder.P.S. The package.individually
property is a root-level property in your serverless.yml
. It shouldn't be in provider
or in your function definitions.