aws / aws/aws-cdk

(aws-lambda-nodejs): export esbuild asset code bundler

Open
#14,215 9 comments 31 reactions 0 assignees View on GitHub
@aws-cdk/aws-lambda-nodejs effort/small feature-request p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
1d 19h
Merged PRs (30d)
71

Description

Can't use aws-lambda-nodejs' capabilities in Lambda@Edge.

### Use Case

If you want to use a NodeJS lambda in edge, you need to bundle the code by yourself. It'd be ideal to export the esbuild bundling functionality so anybody can create the AssetCode with esbuild and use it on any other lambda functions such as Lambda@Edge.

### Proposed Solution

Just exporting the class `Bundling` in `@aws-cdk/aws-lambda-nodejs` would be enough. As a workaround, I did this, which is heavily based on the current implementation but uses esbuild's JS API:

```ts
import * as lambda from "@aws-cdk/aws-lambda";
import * as cdk from "@aws-cdk/core";
import * as esbuild from "esbuild";
import findUp from "find-up";
import * as path from "path";

const findDepsLockFilePath = (input: string) => {
const lockFilePath = findUp.sync(["package-lock.json", "yarn.lock"], {
cwd: input,
});

if (!lockFilePath) {
throw new Error("Couldn't find a lock file (package-lock.json or yarn.lock)");
}

return lockFilePath;
};

/**
* Converts a Lambda runtime to an esbuild node target.
*/
function toTarget(runtime: lambda.Runtime): string {
const match = runtime.name.match(/nodejs(\d+)/);

if (!match) throw new Error("Cannot extract version from runtime.");

return `node${match[1]}`;
}

export interface EsbuildBundlingProps {
input: string;
runtime: lambda.Runtime;
external?: string[];
define?: {
[key: string]: string;
};
}

export class EsbuildBundling {
public static bundle(options: EsbuildBundlingProps): lambda.AssetCode {
const depsLockFilePath = findDepsLockFilePath(options.input);

return lambda.Code.fromAsset(path.dirname(depsLockFilePath), {
assetHashType: cdk.AssetHashType.OUTPUT,
bundling: new EsbuildBundling(options),
});
}

public readonly image: cdk.DockerImage;

public readonly local: cdk.ILocalBundling;

constructor(private readonly props: EsbuildBundlingProps) {
this.image = cdk.DockerImage.fromRegistry("dummy");
this.local = {
tryBundle(outputDir) {
console.log({ outputDir, input: props.input });
esbuild.buildSync({
entryPoints: [props.input],
bundle: true,
platform: "node",
target: toTarget(props.runtime),
outfile: `${outputDir}/index.js`,
external: ["aws-sdk", ...(props.external || [])],
define: props.define,
// minify: true,
});
return true;
},
};
}
}
```

### Other

* [x] :wave: I may be able to implement this feature request
* [ ] :warning: This feature might incur a breaking change

---

This is a :rocket: Feature Request

Contributor guide

Open the contributing guide

Research direction

Start by locating the existing Bundling class and the public exports for @aws-cdk/aws-lambda-nodejs, then inspect how its current implementation is used. Done means the bundling functionality can be imported publicly and used to create AssetCode for Lambda@Edge or other Lambda functions.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
backend, cloud
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.