This project was created before AWS SAM CLI introduced support for building TypeScript projects. While it served a need at the time I would recommend using SAM CLI's TypeScript support.
I will no longer be providing updates to this package but if someone wants to create a PR to support new runtimes I will merge and release it.
This plugin will build your AWS SAM CLI project using Webpack. You can use it to replace the sam build
step if every function in your SAM template uses the nodejs18.x
, nodejs20.x
or nodejs22.x
runtime. If your project uses other runtimes then look at Building Apps with SAM, TypeScript and VS Code Debugging.
I started this project for two reasons:
- SAM doesn't have good support for TypeScript
- SAM build is slow because it runs
npm pack
andnpm install
for every function in your project.
The goals for this projects are:
- Build your SAM project using Webpack (including support for watch mode)
- Support TypeScript and Babel
- Compatibility with running
sam build
- Automatically generate VS Code debugging configuration
Create a package.json
in your projects root folder using npm init
or yarn init
.
Install the development dependencies:
npm install webpack webpack-cli typescript ts-loader aws-sam-webpack-plugin @types/aws-lambda rimraf --save-dev
or
yarn add webpack webpack-cli typescript ts-loader aws-sam-webpack-plugin @types/aws-lambda rimraf -D
Install the production dependencies:
npm install aws-sdk --save
or
yarn add aws-sdk --save
Create a webpack.config.js
file in your projects root folder and add this plugin. The entry
points can be set automatically using the .entry()
method from this plugin. The output should go to .aws-sam/build
.
Tip: If you set entry
to () => awsSamPlugin.entry()
it will reload your SAM configuration every time webpack rebuilds. You can disable this by setting entry
to awsSamPlugin.entry()
Example:
const path = require("path");
const AwsSamPlugin = require("aws-sam-webpack-plugin");
const awsSamPlugin = new AwsSamPlugin();
module.exports = {
// Loads the entry object from the AWS::Serverless::Function resources in your
// SAM config. Setting this to a function will
entry: () => awsSamPlugin.entry(),
// Write the output to the .aws-sam/build folder
output: {
filename: (chunkData) => awsSamPlugin.filename(chunkData),
libraryTarget: "commonjs2",
path: path.resolve("."),
},
// Create source maps
devtool: "source-map",
// Resolve .ts and .js extensions
resolve: {
extensions: [".ts", ".js"],
},
// Target node
target: "node",
// AWS recommends always including the aws-sdk in your Lambda package but excluding can significantly reduce
// the size of your deployment package. If you want to always include it then comment out this line. It has
// been included conditionally because the node10.x docker image used by SAM local doesn't include it.
externals: process.env.NODE_ENV === "development" ? [] : ["aws-sdk"],
// Set the webpack mode
mode: process.env.NODE_ENV || "production",
// Add the TypeScript loader
module: {
rules: [{ test: /\.tsx?$/, loader: "ts-loader" }],
},
// Add the AWS SAM Webpack plugin
plugins: [awsSamPlugin],
};
Create a TypeScript config file that compiles .ts
and .js
files from the src
folder.
Example:
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
To make building simple I like to add some scripts to the package.json
which handles building, building in watch mode and cleaning up.
{
"scripts": {
"build": "webpack-cli",
"clean": "rimraf .aws-sam .vscode",
"prebuild": "rimraf .aws-sam .vscode",
"prewatch": "rimraf .aws-sam .vscode",
"watch": "webpack-cli -w"
}
}
You can set the NODE_ENV
environment variable while executing the scripts to change how it's built:
NODE_ENV=development npm run-script build
Create a src
folder with one sub-folder for each function. Place your handler and any test code in here.
Create a template.yaml
in the project root. For the CodeUri
use the functions folder (i.e. src/{folder}
). Example:
Resources:
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/my-function
Handler: app.handler
Create a package.json
in your projects root folder using npm init
or yarn init
.
Install the development dependencies:
npm install webpack webpack-cli aws-sam-webpack-plugin @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-typescript @babel/plugin-transform-runtime babel-loader --save-dev
or
yarn add webpack webpack-cli aws-sam-webpack-plugin @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-typescript @babel/plugin-transform-runtime babel-loader -D
Install the production dependencies:
npm install aws-sdk source-map-support @babel/runtime --save
or
yarn add aws-sdk source-map-support @babel/runtime --save
Create a webpack.config.js
file in your projects root folder and add this plugin. The entry
points can be set automatically using the .entry()
method from this plugin. The output should go to .aws-sam/build
.
Tip: If you set entry
to () => awsSamPlugin.entry()
it will reload your SAM configuration every time webpack rebuilds. You can disable this by setting entry
to awsSamPlugin.entry()
Example:
const path = require("path");
const AwsSamPlugin = require("aws-sam-webpack-plugin");
const awsSamPlugin = new AwsSamPlugin();
module.exports = {
// Loads the entry object from the AWS::Serverless::Function resources in your
// SAM config. Setting this to a function will
entry: () => awsSamPlugin.entry(),
// Write the output to the .aws-sam/build folder
output: {
filename: (chunkData) => awsSamPlugin.filename(chunkData),
libraryTarget: "commonjs2",
path: path.resolve("."),
},
// Create source maps
devtool: "source-map",
// Resolve .ts and .js extensions
resolve: {
extensions: [".ts", ".js"],
},
// Target node
target: "node",
// AWS recommends always including the aws-sdk in your Lambda package but excluding can significantly reduce
// the size of your deployment package. If you want to always include it then comment out this line. It has
// been included conditionally because the node10.x docker image used by SAM local doesn't include it.
externals: process.env.NODE_ENV === "development" ? [] : ["aws-sdk"],
// Set the webpack mode
mode: process.env.NODE_ENV || "production",
// Add the TypeScript loader
module: {
rules: [
{ test: /\.jsx?$/, loader: "babel-loader" },
{ test: /\.tsx?$/, loader: "babel-loader" },
],
},
// Add the AWS SAM Webpack plugin
plugins: [awsSamPlugin],
};
Create a babel.config.js
file at the project root
module.exports = {
plugins: [
"@babel/proposal-class-properties",
[
"@babel/plugin-transform-runtime",
{
regenerator: true,
},
],
],
presets: ["@babel/env", "@babel/typescript"],
};
To make building simple I like to add some scripts to the package.json
which handle building, building in watch mode and cleaning up.
{
"scripts": {
"build": "webpack-cli",
"clean": "rimraf .aws-sam .vscode",
"prebuild": "rimraf .aws-sam .vscode",
"prewatch": "rimraf .aws-sam .vscode",
"watch": "webpack-cli -w"
}
}
You can set the NODE_ENV
environment variable while executing the commands to change how it's built:
NODE_ENV=development npm run-script build
Create a src
folder with one sub-folder for each function. Place your handler and any test code in here.
Create a template.yaml
in the project root. For the CodeUri
use the functions folder (i.e. src/{folder}
). Example:
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/my-function
Handler: app.handler
To enable source map support on Lambda make sure you set the environment variable NODE_OPTIONS
to --enable-source-maps
for your Lambda.
To debug your Lambda using VS Code add the option -d 5858
when using sam local invoke
to launch the Node debugger then switch to the debugger in VS Code. From the VS Code debugger select the Lambda function you want to debug and click run. As of VS Code version 1.51 and SAM CLI version 1.10.0 the debugger will stop at the bootstrap file. Click the continue button and it will go to the first break point.
You should be able to set breakpoints in your source code, step through the code and view values from the editor.
From v0.5.0 you can build multiple SAM projects from a single webpack.config.js
by using the projects
option. All of the SAM projects need to be located below a common point on the filesystem. This could be the same folder that contains your webpack.config.js
or another folder like services
(any name is ok).
The projects
option accepts a JavaScript object where the key is a shortname for the project and the value can be:
- The path to the root folder for your SAM project. The plugin will look for a
template.yaml
ortemplate.yml
in that folder. - The path to a SAM template. This allows you to use a different a template name. The folder the template is located in will be used as the root folder for that SAM project.
For example: The following will build two projects, projectA
and projectB
. For projectA
the plugin will look for either template.yaml
or template.yml
in the folder ./services/project-a
but for projectB
it will only use project.yaml
in the ./services/project-b
folder.
const awsSamPlugin = new AwsSamPlugin({
projects: {
projectA: "./services/project-a",
projectB: "./services/project-b/project.yaml",
},
});
If you are upgrading from instructions prior to 0.5.0 you also need to modify the output
section of your webpack.config.js
so that Webpack uses the plugins .filename()
method to determine the name of the output file. This will create a .aws-sam/build
folder in correct SAM project root.
module.exports = {
output: {
filename: (chunkData) => awsSamPlugin.filename(chunkData),
libraryTarget: "commonjs2",
path: path.resolve("."),
},
};
Once you have done this you should be able to execute Webpack from the root folder for your project (typically where you have your package.json
, webpack.config.js
, etc). In this example that folder would also contain the services
folder.
Name | Type | Default | Description |
---|---|---|---|
outFile |
{String} |
app |
The name of the Javascript file to output without the .js extension. For example: index will generate index.js . By default it will use app |
projects |
{Object} |
{"default":"."} |
A JavaScript object where the key is the name of the project and the value is the path to the SAM template or a folder containing a template.yaml or template.yml for the project |
vscodeDebug |
{Boolean} |
true |
Also generate a .vscode/launch.json file for debugging Lambda with SAM CLI local S |
Enable/disable automatically generating a .vscode/launch.json
file. This file contains the VS Code debug configuration for all of the Lambdas from your template.yaml
.
Rich Buggy |