SsrSite with Lambda@Edge on VIEWER_REQUEST event not deployable
alexbricepalo opened this issue · comments
I tried to add a Lambda@Edge function to a SsrSite construct using the VIEWER_REQUEST event trigger to intercept requests to the Cloudfront Distribution:
const site = new SsrSite(stack, "Site", {
path: "www/",
edge: true,
cdk: {
distribution: {
defaultBehavior: {
edgeLambdas: [
{
functionVersion: rewriteLambdaEdgeFunction.currentVersion,
eventType: cloudfront.LambdaEdgeEventType.VIEWER_REQUEST
}
]
}
}
}
});
Error: Site/Distribution: Resource handler returned message: "Invalid request provided: The event type of a function association must be unique in the cache behavior. Event type viewer-request cannot be associated with two functions
How to Reproduce
- Create a clean sst app
- Create a frontend stack and add following code:
const rewriteLambdaEdgeFunction = new cloudfront.experimental.EdgeFunction(stack, 'RewriteLambdaEdgeFunction', { runtime: lambda.Runtime.NODEJS_LATEST, handler: 'index.handler', code: lambda.Code.fromInline(` exports.handler = function() { return { status: "200", body: "Hello, World!" } } `), }); const site = new SsrSite(stack, "Site", { path: "www/", edge: true, cdk: { distribution: { defaultBehavior: { edgeLambdas: [ { functionVersion: rewriteLambdaEdgeFunction.currentVersion, eventType: cloudfront.LambdaEdgeEventType.VIEWER_REQUEST } ] } } } });
Expected Behavior
The VIEWER_REQUEST event with Lambda@Edge can be set in the cdk distribution default behavior without a conflict with the CloudFront function.
@alexbricepalo the recommended way is to use the cdk.transform
prop to prevent the creation of the Cloudfront function. The code would look something like this:
const site = new NextjsSite(stack, "Site", {
cdk: {
transform: (plan) => {
// This tells planning to not create the CF function
delete plan.cloudFrontFunctions.serverCfFunction;
// This tells planning to not use CF function in behaviors
Object.values(plan.behaviors).forEach((behavior) => {
if (behavior.cfFunction === "serverCfFunction") {
delete behavior.cfFunction;
}
});
}
}
});
Ideally, you can create the edge function and hook it up to the behaviors thru plan
as well. But there are some limitations w/ plan
at the moment. ie. u can't create an edge function with inline code. Reference the code from a file should work instead:
const site = new NextjsSite(stack, "Site", {
cdk: {
transform: (plan) => {
// This tells planning to not create the CF function
delete plan.cloudFrontFunctions.serverCfFunction;
// This tells planning to not use CF function in behaviors
Object.values(plan.behaviors).forEach((behavior) => {
if (behavior.cfFunction === "serverCfFunction") {
delete behavior.cfFunction;
}
});
+ // This tells planning to create the rewrite Edge function
+ plan.edgeFunctions = {
+ ...plan.edgeFunctions,
+ rewriteFunction: {
+ constructId: "rewriteFunction",
+ function: {
+ runtime: "nodejs20.x",
+ handler: 'index.handler',
+ bundle: "path/to/handler/folder",
+ }
+ }
+ };
}
}
});
Excellent, thank you! I updated it a bit for typescript, but it worked for me.