Writing AWS Lambda functions in TypeScript
April 3rd, 2020
serverless, typescript
The Serverless Framework makes writing Lambda functions in Node.js pretty easy to get up and running. But once you add a few dependencies from npm
, you pretty quickly end up packaging and deploying huge node_modules
folders to AWS.
The Serverless Webpack plugin can help optimize these functions, and also allows you to integrate your favorite build tooling to do things like compiling TypeScript or optimizing your deployed bundles.
A basic configuration for TypeScript may look like this:
npm install --save-dev serverless serverless-webpack webpack typescript ts-loader
# serverless.yml
service: serverless-webpack-example
plugins:
- serverless-offline
- serverless-webpack
custom:
webpack:
includeModules: true
provider:
name: aws
runtime: nodejs12.x
functions:
hello:
handler: src/hello.handler
events:
- http:
path: hello
method: post
Add a webpack.config.js
file like this.
// webpack.config.js
const path = require('path')
const slsw = require('serverless-webpack')
module.exports = {
mode: 'production',
entry: slsw.lib.entries,
target: 'node',
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js'
},
resolve: {
extensions: ['.js', '.ts']
},
module: {
rules: [
{ test: /\.ts$/, use: 'ts-loader' }
]
}
}
Now you can write you functions in TypeScript, and Serverless will automatically build and compile your code for you. This integrates with other Serverless Framework commands such as serverless invoke local
, as well as the serverless-offline plugin for local development.
Optimizing your Webpack configuration
But we can still do a little better. A simple configuration like this can still end up bundling a lot of extra unnecessary code if you're not careful, such as the aws-sdk
package. Some of these packages don't need to included in your bundle, since they're already included in the AWS runtime. One option is to use the webpack-node-externals
plugin to exclude all node_modules
from bundling, and only build your own source code.
// webpack.config.js
...
const nodeExternals = require('webpack-node-externals')
module.exports = {
...
externals: [nodeExternals()],
...
}
However, once again you'll packaging huge node_modules
folders to AWS leading to slower builds and giant Lambda packages. Instead, you can exclude individual dependencies from your build.
// webpack.config.js
...
module.exports = {
...
externals: ['aws-sdk'],
...
}
This will tell Webpack to exclude aws-sdk
from your bundle, but it will still zip it into a node_modules
folder to deploy to AWS. You can go one step further to avoid packaging the library entirely by excluding it in your serverless-webpack
configuration.
# serverless.yml
service: serverless-webpack-example
...
custom:
webpack:
includeModules:
forceExclude:
- aws-sdk
...
This will prevent aws-sdk
from being bundles in your JavaScript bundle, or shipped to AWS in a node_modules
folder, and you'll end up with leaner, better optimized JavaScript bundles.