Skip to content

Instantly share code, notes, and snippets.

@borgoat
Last active April 25, 2023 20:28
Show Gist options
  • Select an option

  • Save borgoat/718f1650cf6fe7f6fcb6c56a2e783e96 to your computer and use it in GitHub Desktop.

Select an option

Save borgoat/718f1650cf6fe7f6fcb6c56a2e783e96 to your computer and use it in GitHub Desktop.
CDK Construct to find pre-bundled Lambda function - heavily inspired by CDK lambda-nodejs package
import * as lambda from 'aws-cdk-lib/aws-lambda';
import type { CallSite } from 'aws-cdk-lib/aws-lambda-nodejs/lib/util';
import { Construct } from 'constructs';
import fs from 'fs';
import path from 'path';
import process from 'process';
export interface BundledLambdaFunctionProps extends lambda.FunctionOptions {
/**
* The name of the exported handler in the entry file.
*
* The handler is prefixed with `index.` unless the specified handler value contains a `.`,
* in which case it is used as-is.
*
* @default handler
*/
readonly handler?: string;
/**
* The runtime environment. Only runtimes of the Node.js family are
* supported.
*
* @default Runtime.NODEJS_18_X
*/
readonly runtime?: lambda.Runtime;
}
/**
* Inspired to CDK's lambda-nodejs but for pre-bundled code.
*
* @see https://github.com/aws/aws-cdk/blob/v2.70.0/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts
*/
export class BundledLambdaFunction extends lambda.Function {
constructor(scope: Construct, id: string, props: BundledLambdaFunctionProps) {
if (props.runtime && props.runtime.family !== lambda.RuntimeFamily.NODEJS) {
throw new Error('Only `NODEJS` runtimes are supported.');
}
const entry = path.resolve(findEntry(id));
const runtime = props.runtime ?? lambda.Runtime.NODEJS_18_X;
const handler = props.handler ?? 'index.handler';
const code = lambda.Code.fromAsset(entry);
super(scope, id, {
...props,
runtime,
code,
handler,
});
}
}
/**
* Searches for pre-bundled handler file
*/
function findEntry(id: string): string {
// CDK is launcehd from here - the monorepo root
const rootDir = process.cwd();
// The file where the Lambda Construct was created from
const definingFile = path.parse(findDefiningFile());
const relativeDirectory = path.relative(rootDir, definingFile.dir);
// Should be the path to the actual Lambda directory, bundled
const bundledLambdaDirectory = path.join(
rootDir,
'dist',
'lambda',
relativeDirectory,
`${definingFile.name}.${id}`,
);
if (!fs.existsSync(bundledLambdaDirectory)) {
throw new Error(`Cannot find handler directory ${bundledLambdaDirectory}`);
}
return bundledLambdaDirectory;
}
/**
* Finds the name of the file where the `BundledLambdaFunction` is defined
*/
function findDefiningFile(): string {
let definingIndex;
const sites = callsites();
for (const [index, site] of sites.entries()) {
if (site.getFunctionName() === 'BundledLambdaFunction') {
// The next site is the site where the BundledLambdaFunction was created
definingIndex = index + 1;
break;
}
}
if (!definingIndex || !sites[definingIndex]) {
throw new Error('Cannot find defining file.');
}
return sites[definingIndex].getFileName();
}
function callsites(): CallSite[] {
const _prepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const stack = new Error().stack?.slice(1);
Error.prepareStackTrace = _prepareStackTrace;
return stack as unknown as CallSite[];
}
{
"name": "core-cloud",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/core/cloud/src",
"projectType": "library",
"targets": {
"lambda": {
"executor": "@nrwl/esbuild:esbuild",
"outputs": ["{options.outputPath}"],
"options": {
"main": "libs/core/cloud/src/index.ts",
"tsConfig": "libs/core/cloud/tsconfig.lib.json",
"outputPath": "dist/lambda/libs/core/cloud/src",
"skipTypeCheck": true,
"minify": true,
"sourcemap": true,
"bundle": true,
"target": "node18",
"format": ["cjs"],
"esbuildOptions": {
"outExtension": {
".js": ".js"
}
},
"additionalEntryPoints": [
"libs/core/cloud/src/lib/cloud-front.set-cookies.fn/index.ts",
"libs/core/cloud/src/lib/cloud-front.signing-key-rotation.fn/index.ts",
"libs/core/cloud/src/lib/data-neo4j.invoke.fn/index.ts",
"libs/core/cloud/src/lib/identity-management.custom-message.fn/index.ts",
"libs/core/cloud/src/lib/identity-management.post-confirmation.fn/index.ts",
"libs/core/cloud/src/lib/identity-management.pre-sign-up.fn/index.ts"
]
}
}
},
"tags": []
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment