1
votes

I want to use a AWS Lambda Layer with some AWS API Gateway endpoints that I am building and deploying using the Serverless Framework and Webpack.

I created one Lambda Layer in the AWS Console which I want to use with all of my API Gateway endpoints. It's a collection of node_modules used by all functions (e.g. lodash, axios, mysql2, etc).

In the serverless config, I've told each endpoint where the layer is, referencing the ARN.

serverless.yml
custom:
  webpack:
    packager: 'yarn'
    webpackConfig: ../../webpack.config.js
    includeModules: false
    keepOutputDirectory: true

functions:
  login:
    handler: login/lambda.handler
    description: Login
    events:
      - http: 'POST /login'
    layers:
      - arn:aws:lambda:us-east-1:000000000000:layer:api-layer-common:1

plugins:
  - serverless-plugin-include-dependencies
  - serverless-webpack

However, whenever I package one of my services (e.g. serverless package auth --stage dev) with Webpack, the resulting bundle always includes the required() node modules, even though I have specified in the config (webpack-node-externals) that I don't want them in the bundle.

const slsw = require('serverless-webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  target:       'node',
  mode:         slsw.lib.webpack.isLocal ? 'development' : 'production',
  entry:        slsw.lib.entries,
  externals:    [nodeExternals()],
  ...
}

So, I'm confused.

  1. Is Webpack doing the bundling or is Serverless doing the bundling?
  2. Do I need to tell Serverless to exclude node_modules or does Webpack need to know or both?
  3. I wonder if a global Lambda Layer is even possible given that Webpack will need to know where the node_modules are in order to require() them correctly in the bundle. I've created DLL files with Webpack but I'm not sure that's the right option, either.

I've read several examples of using Serverless/Webpack/Lambda Layers and tried numerous configuration settings in those posts, but none of the tutorials seem to work for my use case.

Any suggestions would be greatly appreciated.

Thanks!

2

2 Answers

0
votes

Maybe you can change your webpack.config.js to this form:

const slsw = require('serverless-webpack');
// const nodeExternals = require('webpack-node-externals');

module.exports = {
  target:       'node',
  mode:         slsw.lib.webpack.isLocal ? 'development' : 'production',
  entry:        slsw.lib.entries,
  externals:    {
    'aws-lambda': 'commonjs2 aws-lambda',
    'aws-sdk': 'commonjs2 aws-sdk',
    'pg': 'commonjs2 pg',
    'reflect-metadata': 'commonjs2 reflect-metadata',
    'typeorm': 'commonjs2 typeorm',
    'typescript-memoize': 'commonjs2 typescript-memoize',
    'axios': 'commonjs2 axios',
  },
  ...
}

This works for me.
You can also use a function inside your webpack.config.js file to get all dependencies from package.json and insert them into externals property.

0
votes

The webpack-node-externals documentation would have you believe that all you need to do is this:

  externals:    [ nodeExternals() ]

It only worked after I explicitly set the node_modules folder this way:

  externals:    [
    nodeExternals({
      modulesDir: path.resolve(__dirname, './node_modules')
    })
  ]

Then, my bundle size went from 1.3MB to 44KB because all node modules were considered external dependencies.