Projen component to generate AWS CDK Lambda Function Constructs and bundle their Code Assets
npm install @nikovirtala/projen-lambda-function-construct-generatorA projen component to generate AWS CDK Lambda Function constructs and bundle their code assets using esbuild.
- Automatically discovers Lambda Function handlers in a specified directory
- Generates CDK Construct for each Lambda Function handler
- Bundles Lambda code assets using esbuild during projen execution (not during CDK synth)
- Supports customization of esbuild bundling options
- Enables "build once, deploy many" pattern for Lambda Functions
- Allows customizing the base construct class for generated Lambda functions
- Supports multiple generator instances with different configurations
``bash`
npm install @nikovirtala/projen-lambda-function-construct-generatoror
yarn add @nikovirtala/projen-lambda-function-construct-generatoror
pnpm add @nikovirtala/projen-lambda-function-construct-generator
In your .projenrc.ts file:
`typescript
import { awscdk } from "projen";
import { LambdaFunctionConstructGenerator } from "@nikovirtala/projen-lambda-function-construct-generator";
const project = new awscdk.AwsCdkTypeScriptApp({
// ... your project configuration
});
new LambdaFunctionConstructGenerator(project, {
// Optional: customize the source directory where Lambda Function handlers are located
sourceDir: "src/handlers",
// Optional: customize the output directory where Lambda Function constructs will be generated
outputDir: "src/constructs/lambda",
// Optional: customize the file pattern to identify Lambda Function handlers
filePattern: "*.lambda.ts",
// Optional: customize the base construct to extend
baseConstructImport: "import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';",
baseConstructClass: "NodejsFunction",
baseConstructPackage: "aws-cdk-lib", // Only needed if it's a separate package
// Optional: customize esbuild options
esbuildOptions: {
minify: true,
sourcemap: true,
// Any other esbuild options
},
});
// You can add multiple generators with different configurations
new LambdaFunctionConstructGenerator(project, {
sourceDir: "src/api-handlers",
outputDir: "src/constructs/api-lambda",
filePattern: "*.api.ts",
baseConstructImport: "import { ApiFunction } from '../lib/api-function';",
baseConstructClass: "ApiFunction",
});
project.synth();
`
Create a Lambda Function handler file in your source directory (e.g., src/handlers/hello.lambda.ts):
`typescript
export async function handler(event: any, context: any) {
console.log("Event:", JSON.stringify(event, null, 2));
return {
statusCode: 200,
body: JSON.stringify({
message: "Hello from Lambda!",
event,
}),
};
}
`
Create an API Lambda handler file (e.g., src/api-handlers/user.api.ts):
`typescript
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
export async function handler(event: APIGatewayProxyEvent): Promise
console.log("API Event:", JSON.stringify(event, null, 2));
return {
statusCode: 200,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
message: "User API endpoint",
path: event.path,
method: event.httpMethod,
}),
};
}
`
The component will generate a CDK construct for each Lambda Function handler (e.g., src/constructs/lambda/hello.ts):
`typescript
// ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
import * as path from "path";
import { fileURLToPath } from "url";
import { aws_lambda } from "aws-cdk-lib";
import { Construct } from "constructs";
// ES Module compatibility
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Properties for HelloFunction
*/
export interface HelloFunctionProps extends Omit
/**
* Override the default runtime
* @default nodejs22.x
*/
readonly runtime?: aws_lambda.Runtime;
}
/**
* HelloFunction - Lambda Function Construct for hello.lambda.ts
*/
export class HelloFunction extends aws_lambda.Function {
constructor(scope: Construct, id: string, props: HelloFunctionProps = {}) {
super(scope, id, {
...props,
runtime: props.runtime ?? aws_lambda.Runtime.NODEJS_22_X,
handler: "index.handler",
code: aws_lambda.Code.fromAsset(path.join(__dirname, "../../../assets/handlers/hello")),
});
}
}
`
For API handlers, it will generate constructs that extend your custom ApiFunction class (e.g., src/constructs/api-lambda/user.ts):
`typescript
// ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
import * as path from "path";
import { fileURLToPath } from "url";
import { ApiFunction } from "../lib/api-function";
import { aws_lambda } from "aws-cdk-lib";
import { Construct } from "constructs";
// ES Module compatibility
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Properties for UserApiFunction
*/
export interface UserApiFunctionProps extends Omit
// No runtime property since ApiFunction handles that
}
/**
* UserApiFunction - Lambda Function Construct for user.api.ts
*/
export class UserApiFunction extends ApiFunction {
constructor(scope: Construct, id: string, props: UserApiFunctionProps = {}) {
super(scope, id, {
...props,
handler: "index.handler",
code: aws_lambda.Code.fromAsset(path.join(__dirname, "../../../assets/handlers/user")),
});
}
}
`
In your CDK stack:
`typescript
import { Stack, StackProps, Duration } from "aws-cdk-lib";
import { Construct } from "constructs";
import { HelloFunction } from "../constructs/lambda/hello";
export class MyStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const helloFunction = new HelloFunction(this, "HelloFunction", {
memorySize: 256,
timeout: Duration.seconds(30),
environment: {
EXAMPLE_VAR: "example-value",
},
});
}
}
`
If you've specified a custom base construct:
`typescript
import { Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { HelloFunction } from "../constructs/lambda/hello";
import { UserApiFunction } from "../constructs/api-lambda/user";
export class MyStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Using the NodejsFunction-based construct
const helloFunction = new HelloFunction(this, "HelloFunction", {
// Properties specific to the NodejsFunction type
entry: "src/handlers/hello.lambda.ts",
bundling: {
minify: true,
},
});
// Using the ApiFunction-based construct
const userApiFunction = new UserApiFunction(this, "UserApiFunction", {
// Properties specific to the ApiFunction type
apiId: "my-api-id",
routeKey: "GET /users",
authorizationType: "JWT",
});
}
}
``
MIT