Git Product home page Git Product logo

aws-sam-webpack-plugin's Introduction

npm

AWS SAM Webpack Plugin

A Webpack plugin that replaces the sam build step for AWS SAM CLI projects.

IMPORTANT

This project was created before AWS SAM CLI introduced support for building TypeScript projects. Now that AWS SAM CLI includes that support it is no longer required and will be put into maintenance mode. During this time it will be updated to support newer nodejs Lambda runtime versions and bug fixes but no new features will be added. This is to provide time for developers to migrate projects to the offical TypeScript support.

If you are starting a new project it is strongly recommend you follow the instructions in Building TypeScript projects with AWS SAM CLI and use the built-in support.

Background

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 nodejs14.x, nodejs16.x, nodejs18.x or nodejs20.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:

  1. SAM doesn't have good support for TypeScript
  2. SAM build is slow because it runs npm pack and npm install for every function in your project.

The goals for this projects are:

  1. Build your SAM project using Webpack (including support for watch mode)
  2. Support TypeScript and Babel
  3. Compatibility with running sam build
  4. Automatically generate VS Code debugging configuration

Usage with TypeScript

Installation

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

webpack.config.js

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],
};

tsconfig.json

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
  }
}

package.json (optional)

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

src/{function}

Create a src folder with one sub-folder for each function. Place your handler and any test code in here.

template.yaml

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

Usage with Babel

Installation

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

webpack.config.js

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],
};

babel.config.js

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"],
};

package.json (optional)

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

src/{function}

Create a src folder with one sub-folder for each function. Place your handler and any test code in here.

template.yaml

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

Source Map Support

To enable source map support on Lambda make sure you set the environment variable NODE_OPTIONS to --enable-source-maps for your Lambda.

VS Code Debugging

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.

Building Multiple Projects (Experimental)

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:

  1. The path to the root folder for your SAM project. The plugin will look for a template.yaml or template.yml in that folder.
  2. 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.

Options

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

vscodeDebug

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.

Maintainers


Rich Buggy

aws-sam-webpack-plugin's People

Contributors

baxneo avatar buggy avatar dependabot[bot] avatar dmccaffery avatar hsalazr avatar matt-tyler avatar nickcox avatar vadzim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-sam-webpack-plugin's Issues

Can't load custom layers (Module not found)

I recieved an error when i try to require my custom layers:

`ERROR in ./src/maras/reviews.ts
Module not found: Error: Can't resolve '/opt/nodejs/utils' in 'D:\Git\gestios\gestios-lambda\src\maras'
@ ./src/maras/reviews.ts 13:14-42

ERROR in ./src/maras/reviews.ts
Module not found: Error: Can't resolve 'gestios-sdk-js' in 'D:\Git\gestios\gestios-lambda\src\maras'
@ ./src/maras/reviews.ts 12:16-41

ERROR in D:\Git\gestios\gestios-lambda\src\maras\reviews.ts
./src/maras/reviews.ts
[tsl] ERROR in D:\Git\gestios\gestios-lambda\src\maras\reviews.ts(1,17)
TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try npm i @types/node.

ERROR in D:\Git\gestios\gestios-lambda\src\maras\reviews.ts
./src/maras/reviews.ts
[tsl] ERROR in D:\Git\gestios\gestios-lambda\src\maras\reviews.ts(2,15)
TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try npm i @types/node.`

Thats the code:

const GestiOS = require('gestios-sdk-js');
const utils = require('/opt/nodejs/utils');

let response;

export interface Event {
	name: string;
}

export default async (event: Event): Promise<string> => (
	`Hello ${event.name}`
);

The build process breaks double quotes (required by the API Gateway CORS)

I am trying to add CORS for the Serverless API ("AWS::Serverless::Api"). The CORS configuration requires double quotes, for example: "'https://serverless.pub'". However, running the npm build command, breaks these double quotes.

Examples

If I have the following in the template.yaml file:

Api:
  Type: AWS::Serverless::Api
  Properties:
    StageName: prod
    Cors:
      AllowHeaders: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
      AllowOrigin: "'*'"
      MaxAge: "'3600'"
      AllowMethods: "'OPTIONS,POST,GET,PUT,DELETE'"

The build command transforms this into:

Api:
  Type: 'AWS::Serverless::Api'
  Properties:
    StageName: prod
    Cors:
      AllowHeaders: '''Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'''
      AllowOrigin: '''*'''
      MaxAge: '''3600'''
      AllowMethods: '''OPTIONS,POST,GET,PUT,DELETE'''

Inverting these quotes works, but CloudFormation throws an error if I try to build the following example:

Api:
  Type: AWS::Serverless::Api
  Properties:
    StageName: prod
    Cors:
      AllowHeaders: '"Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token"'
      AllowOrigin: '"*"'
      MaxAge: '"3600"'
      AllowMethods: '"OPTIONS,POST,GET,PUT,DELETE"'

This is the CloudFormation error:

[Invalid mapping expression specified: "3600"]

Even with the following workaround, the error is the same:

MaxAge: "\"3600\""

build.toml

Hello, i tried this library with build.I have a question about the build.toml file.When i was building with sam-cli .aws-sam include build.toml file but i cant see with webpack plugin.Is it critical or not ?

Support for nested applications

Standard sam build seems to have pretty bad support for nested applications. It would be really good if this plugin could build all of the stacks at once.

async webpack wrap

I have a very simple sam-init-generated async lambda:
exports.lambdaHandler = async (event, context) => {
var response;
try {
// const ret = await axios(url);
response = {
'statusCode': 200,
'body': JSON.stringify({
message: 'hello world',
// location: ret.data.trim()
})
}
} catch (err) {
console.log(err);
return err;
}

return response

};

One issue I've noticed is how comments are handled. Running npm run build removes the comma before the comments in the object being converted to json. The web-pack processed version:
'statusCode': 200,
'body': JSON.stringify({
message: 'hello world' // location: ret.data.trim()

          })

When running the code Node returns:
Lambda returned empty body!
Invalid API Gateway Response Keys: {'errorType', 'errorMessage'} in {'errorType': 'TypeError', 'errorMessage': "Cannot set property 'wrap' of undefined"}

Another issue is that if I copy over the app.js in the build directory, the function returns 'hello world', so something is getting lost in the webpack process.

Steve

Debugger doesn't stop at breakpoints in VScode

Hey, I followed few guides, all of them are basically like the one below.
https://github.com/vincedgy/aws-sam-webpack-typescript

and I also cloned the finished project to try out to debug
https://github.com/vincedgy/aws-sam-webpack-typescript/tree/master/demo

I have also tried to follow your instructions to run debugger for vscode/typescript.
None of which I got the debugger to stop at the breakpoints.

I can see in the console log that debugger got attached. It initially stop at the bootstrap file, but after that it just runs through without stopping on any breakpoints which I've set.

$ sam local invoke -d 5858 -e events/event.json HelloWorldFunction
C:\Program Files\Amazon\AWSSAMCLI\runtime\lib\site-packages\chevron\renderer.py:73: SyntaxWarning: "is" with a literal. Did you mean "=="?
if scope is 0:
Invoking app.lambdaHandler (nodejs12.x)
Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.9.0.

Mounting E:\Documents\Development\aws\aws-typescript.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated inside runtime container
Debugger attached.
←[32mSTART RequestId: e0624f01-7b96-148c-27d4-d8c700e91db3 Version: $LATEST←[0m
2020-11-18T22:51:38.640Z e0624f01-7b96-148c-27d4-d8c700e91db3 INFO Hello World
2020-11-18T22:51:38.641Z e0624f01-7b96-148c-27d4-d8c700e91db3 INFO { statusCode: 200, body: '{"message":"hello world"}' }
←[32mEND RequestId: e0624f01-7b96-148c-27d4-d8c700e91db3←[0m
←[32mREPORT RequestId: e0624f01-7b96-148c-27d4-d8c700e91db3 Init Duration: 355278.73 ms Duration: 4.00 ms Billed Duration:
100 ms Memory Size: 128 MB Max Memory Used: 51 MB ←[0m

{"statusCode":200,"body":"{"message":"hello world"}"}

I'm using
sam-cli 1.9.0
vscode 1.51

I'm not sure if I perhaps missing something. Maybe the following part where you mentioned source map support
https://github.com/graphboss/aws-sam-webpack-plugin#source-map-support

I'm not entirely sure how to set it, so I just applied it as global environment variable.

Any advice or suggestion would be really helpful.

Best way of building source code when other runtimes exist in the project

Wondering what exactly is the best way to use the plugin, and maintain the same file directory of "src/", but where not all functions are in the node runtime?

My project has a mix of lambda that are written in node, while others are written in python. Is there a better alternative than just building them as separate projects?

Possible Bug with compiling the webpack code

Hi,

I've been having an issue for a few days and I can't figure it out . I am convinced that it might be due to webpack plugin but have no idea what can be causing it.

So I have the following code:
image

Now this code when I run it simply node app it works and I get the correct result:
image

However, after compiling (via using the webpack-cli + sam local start-api) I always get 404 not found and I don't get the request I am expected to get via the data client. Somehow after the code runs through the webpack plugin it "breaks" it?

I have the following configuration for webpack:
image

Now I know the problem is not the database itself, because when I run it without the plugin it works.

Things that I've tried:

  • I've used with Typescript, the answer was the same.
  • Used several libs to access this database, Typeorm, data client api, native AWS RDS. With everytime the same issue.
    -Used node v14 and node v12

I've been strugling with this problem for a few days so any help is much appreciated.

Thanks

Fail early if lambda source isn't available

If there is an mistype in template.yaml and the function referenced there does not exist then plugin just silently does nothing.

I think it could be useful to emit errors in such a case.

Why is @types/aws-lambda dependency required as devDependency?

Thank you @buggy for creating this helpful plugin.
We're currently using it in aws-samples/aws-sdk-js-v3-workshop

Question: Why is @types/aws-lambda devDependency required as mentioned in tutorials https://github.com/SnappyTutorials/aws-sam-webpack-plugin/blob/master/README.md?
I built my workshop code without that dependency, and it worked fine.

The only place where aws-lambda is mentioned in this repo is in README.
Search link: https://github.com/SnappyTutorials/aws-sam-webpack-plugin/search?q=aws-lambda&unscoped_q=aws-lambda

Support dynamic import

Currently this is not possible:

const name:string = "my-module"; const mod = await import("./path_to_my_modules" + name);

Webpack chunks are generated outside lambda function directory.

Support for PackageType 'Image

AWS recently added a new PackageType Image, here is an example:

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      PackageType: Image
      # ImageConfig:
        # Uncomment this to override command here from the Dockerfile
        # Command: ["app.lambdaHandler"]
      Events:
        HelloWorld:
          Type: Api
          Properties:
            RestApiId: !Ref Api
            Path: /hello
            Method: get
    Metadata:
      DockerTag: nodejs12.x-v1
      DockerContext: ./src/hello-world
      Dockerfile: Dockerfile

aws-sam-webpack-plugin currently does not support image type and throws Error: Error: HelloWorldFunction has an unsupport Runtime. Must be nodejs10.x or nodejs12.x

Is it possible to hot-reload `template.yaml`?

Hot reloading source files with aws-sam-webpack-plugin is such a wonderfull and convenient thing that it's hard to remember why things stopped to work after adding another lambda to template.yaml :)

So the question is is it really possible to hot-reload template.yaml when it's been changed?

configure sam build --watch support

I use aws-sam-webpack-plugin with webpack to build the files.

webpack.config.js

const AwsSamPlugin = require("aws-sam-webpack-plugin");
const awsSamPlugin = new AwsSamPlugin();
const path = require('path');

module.exports = {
    //entry: './app.js',
    entry: () => awsSamPlugin.entry(),
    output: {
      path: path.resolve("."),
      filename: (chunkData) => awsSamPlugin.filename(chunkData),
      libraryTarget: 'commonjs'
    },
    target: 'node',
    mode: 'production',

      // Add the AWS SAM Webpack plugin
    plugins: [awsSamPlugin]

}

instead of using sam buld I use npm run build
in package.json

....
 "scripts": {
    "test": "mocha tests/unit/",
    "build": "webpack --watch "
  },
.....

although webpack rebuild the changes, it does not appear when sam local start-api
is running,
I am looking help for configure to appear changes

Cannnot debug TypeScript files

It seems that debugging TypeScript files is not possible.
My simplified project structure looks as follows:

│   package.json
│   template.yml
│   tsconfig.json
│   webpack.config.js
│
├───.aws-sam
│   └───build
│       │   template.yaml
│       │
│       └───MyFunction
│               app.js
│               app.js.map
│
├───.vscode
│       launch.json
│
└───src
    └───my-function
        │   app.ts

tsconfig.json:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "allowJs": true,
    "checkJs": true,
    "sourceMap": true,
    "noImplicitAny": false,
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*.ts", "src/**/*.js"]
}

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "MyFunction",
      "type": "node",
      "request": "attach",
      "address": "localhost",
      "port": 5858,
      "localRoot": "${workspaceRoot}/.aws-sam/build/MyFunction",
      "remoteRoot": "/var/task",
      "protocol": "inspector",
      "stopOnEntry": false,
      "outFiles": ["${workspaceRoot}/.aws-sam/build/MyFunction/app.js"],
      "sourceMaps": true,
      "sourceMapPathOverrides": {
        "webpack:///./~/*": "${workspaceRoot}/node_modules/*",
        "webpack:///./*": "${workspaceRoot}/src/my-function/*",
        "webpack:///*": "*"
      }
    }
  ]
}

In my app.ts file I have appropriate import import "source-map-support/register";
With this configuration, setting a breakpoint in app.ts results with nothing during debugging session. What can be an issue?

Feature request: Template location

It would be great if you could pass in as an option the location of the template, rather than it currently requiring template.yaml in the root.

If no option is passed it would still default to a root template.yaml file but otherwise it would use the passed template path. This would also allow you to instantiate multiple instances of the plugin, one per template if you happened to have more than one template in a project but all using a single webpack config.

Generated template file should always be `template.yaml`

Hi,
I had a hard time tracking down a strange "module not found" error when starting my lambda with sam local invoke or using the deployed lambda. After some investigation I found, that SAM was bundling and starting/deploying the *.ts-files instead of the files in .aws-sam/build/.../.
After some further investigation I found that my template-file is named template.yml (which is valid for SAM and for the plugin). Prior to commit a7d3d5d (line 207) this was converted to .aws-sam/build/template.y**a**ml (similar to the behavior of sam-cli). In this commit the generated template use the same extension as the source one. Because of this it looks like sam-cli doesn't recognize it and uses the original one pointing to the source folder containing the TypeScript files.
As soon as I rename the generated file to template.yaml, everything works again...

Can't use ES6 import/export

Hi there,

I had high hopes when I found that plugin because I wanted to develop my NodeJs Lambda's using the ES6 syntax.

I followed all the steps described in the README.md under the Usage with Babel section.

After I completed the setup I can successfully build and run the app in Docker by invoking sam local invoke with this demo handler:

exports.helloFromLambdaHandler = async (event, context) => {
  try {
    response = {
      statusCode: 200,
      body: JSON.stringify({
        message: "hello world",
      }),
    };
  } catch (err) {
    console.log(err);
    return err;
  }
  return response;
};

which gives me the expected output

START RequestId: 6c8eca3c-36ee-4dac-8e0e-fffb00f1d256 Version: $LATEST
END RequestId: 6c8eca3c-36ee-4dac-8e0e-fffb00f1d256
REPORT RequestId: 6c8eca3c-36ee-4dac-8e0e-fffb00f1d256	Init Duration: 0.33 ms	Duration: 172.13 ms	Billed Duration: 200 ms	Memory Size: 128 MB	Max Memory Used: 128 MB	
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}% 

but as soon I refactor the handler like that

export const helloFromLambdaHandler = async (event, context) => {
  try {
    response = {
      statusCode: 200,
      body: JSON.stringify({
        message: "hello world",
      }),
    };
  } catch (err) {
    console.log(err);
    return err;
  }
  return response;
};

I get this response

{
    "errorType": "Runtime.UserCodeSyntaxError",
    "errorMessage": "SyntaxError: Unexpected token 'export'",
    "stack": ["Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token 'export'", "    at _loadUserApp (/var/runtime/UserFunction.js:98:13)", "    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)", "    at Object.<anonymous> (/var/runtime/index.js:43:30)", "    at Module._compile (internal/modules/cjs/loader.js:1063:30)", "    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)", "    at Module.load (internal/modules/cjs/loader.js:928:32)", "    at Function.Module._load (internal/modules/cjs/loader.js:769:14)", "    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)", "    at internal/main/run_main_module.js:17:47"]
}

Which means that Babel didn't compile the code back to ES5 I guess?

Here the content of babel.config.js

module.exports = {
  plugins: [
    "@babel/proposal-class-properties",
    [
      "@babel/plugin-transform-runtime",
      {
        regenerator: true,
      },
    ],
  ],
  presets: ["@babel/env", "@babel/typescript"],
};

and the content of my package.json

{
  "name": "demo",
  "description": "demo",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "test": "jest",
    "build": "webpack-cli",
    "clean": "rimraf .aws-sam .vscode",
    "prebuild": "rimraf .aws-sam .vscode",
    "prewatch": "rimraf .aws-sam .vscode",
    "watch": "webpack-cli -w"
  },
  "dependencies": {
    "@babel/runtime": "^7.13.10",
    "aws-sdk": "^2.863.0",
    "mysql": "^2.18.1",
    "source-map-support": "^0.5.19"
  },
  "devDependencies": {
    "@babel/cli": "^7.13.10",
    "@babel/core": "^7.13.10",
    "@babel/plugin-proposal-class-properties": "^7.13.0",
    "@babel/plugin-transform-runtime": "^7.13.10",
    "@babel/preset-env": "^7.13.10",
    "@babel/preset-typescript": "^7.13.0",
    "aws-sam-webpack-plugin": "^0.9.0",
    "babel-loader": "^8.2.2",
    "jest": "^26.6.3",
    "webpack": "^5.25.0",
    "webpack-cli": "^4.5.0"
  }
}

What is the CLI usage for this plugin?

Sorry, I'm not as familiar with SAM as I am with SLS and so not having the CLI usage leaves a bit to the imagination.

I have the plugin working and it generates a .aws-sam folder with the functions and a refactored template point to the new built function code.

At this point... Are we supposed to deploy like this...

sam package \
--template-file ./aws-sam/template.yaml \
--s3-bucket my-bucket \
--output-template-file ./aws-sam/packaged.yaml

sam deploy \
--template-file ./aws-sam/packaged.yaml \
--stack-name my-stack \
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND

Keep the original template name

If the template name is template.yml the plugin has to generate .aws-sam/build/template.yml instead of .aws-sam/build/template.yaml

Note: This was originally raised by @fayezgb in PR #38 but the solution had problems so I've created an issue to track it.

No working proof of concept samples

Do you have a working example of either:

  • TypeScript
  • Babel

Personally i'm more interested in the Babel implementation, but i've not been able to piece this together yet.

Upgrading to 0.7.0 causing issues with require

I'm not quite sure what has changed, I've had a look through the commit and can't see anything obvious.

Whenever hitting my function after upgrading from 0.6.0 to 0.7.0 I get the following:

"Error: Cannot find module '../helpers/tenantHelper'\nRequire stack:\n- /var/task/listTenants.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",

Am I missing something here? Sorry if an obvious question.

Can not evaluate variables in debug mode for typescript

Hi @buggy

I've found a problem occurring when debugging typescript files I can not inspect any variables.

I've attached a screen shot of what I see in debug mode.

Screenshot from 2019-09-28 22-06-45

I use the same webpack.config.js and tsconfig.json as recommended in the readme.

I suspect something is missing with the source map generated?

Debugging on VSCode: payload and env vars?

Before migrating to aws-sam-webpack-plugin, our project had something like the example below in .vscode/launch.json (these configurations were all created by AWS Toolkit extension, and then we added custom values by hand):

{
  "version": "0.2.0",
    "configurations": [
      {
        "type": "aws-sam",
        "request": "direct-invoke",
        "name": "my-app:updateState (nodejs14.x)",
        "invokeTarget": {
          "target": "template",
          "templatePath": "${workspaceFolder}/template.yml",
          "logicalId": "updateState"
        },
        "lambda": {
          "runtime": "nodejs14.x",
          "environmentVariables": {
            "FOO": "abc",
            "BAR": "123",
            "BAZ": "xyz",
          },
          "payload": {
            "json": {
              "pathParameters": {
                "paramOne": "123456"
              },
              "headers": {
                "Authorization": "Bearer bar123baz"
              },
              "body": "{\"state\":\"new state\"}"
            }
          }
        }
      },
      {
        // another function here etc.
      }
    ]
}

As you can see we added all the environmentVariables, and inside payload we customised pathParameters, headers and body.

After migrating to aws-sam-webpack-plugin, we have:

    {
      "name": "updateState",
      "type": "node",
      "request": "attach",
      "address": "localhost",
      "port": 5858,
      "localRoot": "${workspaceFolder}/.aws-sam/build/updateState",
      "remoteRoot": "/var/task",
      "protocol": "inspector",
      "stopOnEntry": false,
      "outFiles": [
        "${workspaceFolder}/.aws-sam/build/updateState/**/*.js"
      ],
      "sourceMaps": true,
      "skipFiles": [
        "/var/runtime/**/*.js",
        "<node_internals>/**/*.js"
      ]
    },

How do we set environmentVariables and payload?

Also, when attempting to launch the debugger, we get Error: Could not connect to debug target at http://localhost:5858, so how do we change the port from 5858 to something else?

Not using webpack-node-externals can be a problem

I don't have any specify recommendation on how to solve this but not using webpack-node-externals as you did in your article (http://www.goingserverless.com/blog/building-apps-with-sam-typescript-and-vscode-debugging) can be a problem. I use sequelize and it doesn't like being webpacked. After a few hours of googling and some trail-and-error I finally landed on adding sequelize to webpack config's externals array:

  externals: process.env.NODE_ENV === "development" ? ["sequelize"] : ["aws-sdk", "sequelize"],

This solved my problem just fine, but I'm not sure what a generalized solution might be. I was thinking about adding webpack-node-externals and calling nodeExternals() for each subdirectory in src but that would not have worked for me because I use symlinks to a couple of local packages which get nicely included in the bundle. Adding sequelize to externals was my solution... not sure if there's something better. Sharing as an FYI in case you have ideas or thoughts...

Thanks for the great work on this. It's working very well so far.

Files not transpiled when "sam build" in .aws-sam/build

I'm sure this is some error on my part but I'm stumped. I have followed your README (or so I think) verbatim. When I sam build everything is copied correctly into .aws-sam/build but the Typescript files are not compiled to JS files. If I run npm run build (i.e. webpack-cli) then everything is built correctly. Should sam build transpile my TS files? If so, any ideas what I've done wrong?

PS. I'm new to SAM. Your write-ups are outstanding. Thanks for the great work and sharing!!

Deploys always cause new function versions even with no changes

Isn't sam deploy supposed to only upload lambdas if something in the lambda changed?
It seems like any time I change any function it creates new function versions for all functions.

image

Is there a way to only have it update functions with changes? Perhaps my babel or webpack config is wrong?

Running yarn build twice and then using ...
cmp --silent $old $new || echo "files are different"
shows files as identical. Maybe something wrong with how I'm running sam deploy?

Stop at the first line of index.js when debugging.

When running the debug, it stops at the first line of index.js. Previously, it was running to the breakpoint.

The following process is used for debugging.

  1. 'webpack watch'
  2. 'sam local invoke -d 5858 testFunction'
  3. Set to the target function from the VScode debug sidebar.
  4. tell the F5 key to run the debug
  5. stop on the first line of index.js.

スクリーンショット 2020-10-06 11 39 40

Do you have any solutions for this?

Build process is breaking GraphQL endpoint when running SAM Local

I started a project with this plugin, it works great with normal routes but when i added apollo-server-lambda to the project firstly i got a whole bunch of warnings during the build process.

asset ./.aws-sam/build/myFunction/app.js 1.68 MiB [emitted] [minimized] (name: myFunction) 2 related assets
orphan modules 457 KiB [orphan] 121 modules
runtime modules 1.04 KiB 5 modules
cacheable modules 3.29 MiB
  javascript modules 2.78 MiB 429 modules
  json modules 516 KiB
    modules by path ./node_modules/iconv-lite/ 86.7 KiB 8 modules
    ./node_modules/apollo-server-core/package.json 1.29 KiB [built] [code generated]
    ./node_modules/statuses/codes.json 1.54 KiB [built] [code generated]
    ./node_modules/mime-db/db.json 142 KiB [built] [code generated]
    ./node_modules/mime/types.json 30.8 KiB [built] [code generated]
    ./node_modules/node-fetch/node_modules/tr46/lib/mappingTable.json 254 KiB [built] [code generated]
18 modules

WARNING in ./node_modules/express/lib/view.js 81:13-25
Critical dependency: the request of a dependency is an expression
 @ ./node_modules/express/lib/application.js 22:11-28
 @ ./node_modules/express/lib/express.js 18:12-36
 @ ./node_modules/express/index.js 11:0-41
 @ ./node_modules/apollo-server-lambda/dist/ApolloServer.js 27:34-52
 @ ./node_modules/apollo-server-lambda/dist/index.js 13:21-46
 @ ./src/my-function/app.js 1:30-61

1 warning has detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.

webpack 5.64.0 compiled with 1 warning in 10672 ms

secondly when i run sam local start-api to access the endpoint i get these errors

2021-11-15T04:41:49.872Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Error","errorMessage":"Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: \"SchemaDefinition\", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.","stack":["Error: Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: \"SchemaDefinition\", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.","    at t.assertSchema (/var/task/app.js:16:286088)","    at h (/var/task/app.js:16:291337)","    at t.assertValidSchema (/var/task/app.js:16:291027)","    at O (/var/task/app.js:16:172522)","    at _ (/var/task/app.js:16:171621)","    at t.execute (/var/task/app.js:16:170733)","    at t.generateSchemaHash (/var/task/app.js:16:36413)","    at u.generateSchemaDerivedData (/var/task/app.js:2:274813)","    at Object.schemaDerivedDataProvider (/var/task/app.js:2:270181)","    at new t.SchemaManager (/var/task/app.js:16:39283)"]}
time="2021-11-15T04:41:49.899" level=error msg="Init failed" InvokeID= error="Runtime exited with error: exit status 129"
2021-11-15T04:41:50.172Z	undefined	ERROR	Uncaught Exception 	{"errorType":"Error","errorMessage":"Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: \"SchemaDefinition\", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.","stack":["Error: Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: \"SchemaDefinition\", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.","    at t.assertSchema (/var/task/app.js:16:286088)","    at h (/var/task/app.js:16:291337)","    at t.assertValidSchema (/var/task/app.js:16:291027)","    at O (/var/task/app.js:16:172522)","    at _ (/var/task/app.js:16:171621)","    at t.execute (/var/task/app.js:16:170733)","    at t.generateSchemaHash (/var/task/app.js:16:36413)","    at u.generateSchemaDerivedData (/var/task/app.js:2:274813)","    at Object.schemaDerivedDataProvider (/var/task/app.js:2:270181)","    at new t.SchemaManager (/var/task/app.js:16:39283)"]}
END RequestId: 97ac0299-a32b-4254-a9ad-d2e8fe665e72
REPORT RequestId: 97ac0299-a32b-4254-a9ad-d2e8fe665e72	Init Duration: 0.21 ms	Duration: 601.23 ms	Billed Duration: 602 ms	Memory Size: 128 MB	Max Memory Used: 128 MB
Lambda returned empty body!
Invalid lambda response received: Invalid API Gateway Response Keys: {'errorType', 'trace', 'errorMessage'} in {'errorType': 'Error', 'errorMessage': 'Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: "SchemaDefinition", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.', 'trace': ['Error: Expected { __validationErrors: undefined, description: undefined, extensions: undefined, astNode: { kind: "SchemaDefinition", operationTypes: [Array] }, extensionASTNodes: [], _queryType: Query, _mutationType: undefined, _subscriptionType: undefined, _directives: [@include, @skip, @deprecated, @specifiedBy], _typeMap: { Query: Query, String: String, Boolean: Boolean, __Schema: __Schema, __Type: __Type, __TypeKind: __TypeKind, __Field: __Field, __InputValue: __InputValue, __EnumValue: __EnumValue, __Directive: __Directive, __DirectiveLocation: __DirectiveLocation }, _subTypeMap: {}, _implementationsMap: {} } to be a GraphQL schema.', '    at t.assertSchema (/var/task/app.js:16:286088)', '    at h (/var/task/app.js:16:291337)', '    at t.assertValidSchema (/var/task/app.js:16:291027)', '    at O (/var/task/app.js:16:172522)', '    at _ (/var/task/app.js:16:171621)', '    at t.execute (/var/task/app.js:16:170733)', '    at t.generateSchemaHash (/var/task/app.js:16:36413)', '    at u.generateSchemaDerivedData (/var/task/app.js:2:274813)', '    at Object.schemaDerivedDataProvider (/var/task/app.js:2:270181)', '    at new t.SchemaManager (/var/task/app.js:16:39283)']}
2021-11-15 12:41:50 127.0.0.1 - - [15/Nov/2021 12:41:50] "POST /graphql HTTP/1.1" 502 -

OS: Mac OS 12.0.1
Node: 14.17.6

i've attached the project here

When i start a SAM , SAM build, etc. project i don't get these issues.
app.zip

webpack dll plugin support?

are there any plans for this plugin to support webpack-dll-plugin out of the box? or is the recommended approach to use a plugin like copy-webpack-plugin to copy the "vendor.dll.js" file to each lambda function's .aws-sam/build/[function name] folder?

Creating lamba layers in typescript

Hi, thank you so much for creating this plugin!

I'm very new to typescript and sam in general but was wondering how I would go about creating a lambda layer written in typescript.

For example, I want to be able to share code between many different lambda functions (spread across multiple sam templates).

Some advice on how to do this would be highly appreciated!

Thanks

NodeJS14 Support

Getting:

...has an unsupport Runtime. Must be nodejs10.x or nodejs12.x

I noticed that master has support for nodejs14. Is this planned for release? Would be great to have it since Lambdas are now commonly on the Nodejs14.x runtime.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.