Skip to content
This repository was archived by the owner on Jan 28, 2025. It is now read-only.

Commit 7fcdc7f

Browse files
authored
feat(core, lambda-at-edge, nextjs-component): experimental - allow serving static pages/data from origin request handler only (and disable origin response handler) (#1696)
1 parent 70a0c37 commit 7fcdc7f

File tree

12 files changed

+371
-50
lines changed

12 files changed

+371
-50
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@
9696
"babel.config.js",
9797
"jest.config.js",
9898
"<rootDir>/packages/serverless-components/aws-s3",
99-
"<rootDir>/packages/libs/serverless-patched"
99+
"<rootDir>/packages/libs/serverless-patched",
100+
"<rootDir>/packages/libs/lambda-at-edge/src/render/renderStaticPage.ts"
100101
],
101102
"watchPathIgnorePatterns": [
102103
"/fixture/",

packages/compat-layers/lambda-at-edge-compat/next-aws-cloudfront.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,20 @@ const toCloudFrontHeaders = (headers, headerNames, originalHeaders) => {
109109

110110
if (headerValue instanceof Array) {
111111
headerValue.forEach((val) => {
112+
if (val) {
113+
result[headerKey].push({
114+
key: headerName,
115+
value: val.toString()
116+
});
117+
}
118+
});
119+
} else {
120+
if (headerValue) {
112121
result[headerKey].push({
113122
key: headerName,
114-
value: val.toString()
123+
value: headerValue.toString()
115124
});
116-
});
117-
} else {
118-
result[headerKey].push({
119-
key: headerName,
120-
value: headerValue.toString()
121-
});
125+
}
122126
}
123127
});
124128

packages/e2e-tests/next-app-experimental/serverless.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ next-app-experimental:
66
foo: bar
77
build:
88
separateApiLambda: false
9+
disableOriginResponseHandler: true
910
postBuildCommands: ["node scripts/post-build-test.js"]
1011
assetIgnorePatterns:
1112
- "**/public/ignored.txt"

packages/libs/core/src/build/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type BuildOptions = {
88
[key: string]: string;
99
};
1010
separateApiLambda?: boolean;
11+
disableOriginResponseHandler?: boolean;
1112
};
1213

1314
export type NextConfig = {

packages/libs/lambda-at-edge/src/build.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type BuildOptions = {
5050
assetIgnorePatterns?: string[];
5151
regenerationQueueName?: string;
5252
separateApiLambda?: boolean;
53+
disableOriginResponseHandler?: boolean;
5354
};
5455

5556
const defaultBuildOptions = {
@@ -767,7 +768,8 @@ class Builder {
767768
const {
768769
enableHTTPCompression,
769770
logLambdaExecutionTimes,
770-
regenerationQueueName
771+
regenerationQueueName,
772+
disableOriginResponseHandler
771773
} = this.buildOptions;
772774

773775
const apiBuildManifest = {
@@ -778,7 +780,8 @@ class Builder {
778780
...pageManifest,
779781
enableHTTPCompression,
780782
logLambdaExecutionTimes,
781-
regenerationQueueName
783+
regenerationQueueName,
784+
disableOriginResponseHandler
782785
};
783786
const imageBuildManifest = {
784787
...imageManifest,

packages/libs/lambda-at-edge/src/default-handler.ts

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Manifest from "./manifest.json";
66
import RoutesManifestJson from "./routes-manifest.json";
77
// @ts-ignore
88
import lambdaAtEdgeCompat from "@sls-next/next-aws-cloudfront";
9+
import { renderStaticPage } from "./render/renderStaticPage";
910
import {
1011
ExternalRoute,
1112
getCustomHeaders,
@@ -15,6 +16,7 @@ import {
1516
handleFallback,
1617
handlePublicFiles,
1718
PublicFileRoute,
19+
Route,
1820
routeDefault,
1921
StaticRoute
2022
} from "@sls-next/core";
@@ -122,18 +124,48 @@ export const handler = async (
122124
return response;
123125
};
124126

125-
const staticRequest = (
126-
request: CloudFrontRequest,
127+
const staticRequest = async (
128+
event: OriginRequestEvent,
127129
file: string,
128-
path: string
130+
path: string,
131+
route: Route,
132+
manifest: OriginRequestDefaultHandlerManifest,
133+
routesManifest: RoutesManifest
129134
) => {
130-
const s3Origin = request.origin?.s3 as CloudFrontS3Origin;
131-
const s3Domain = normaliseS3OriginDomain(s3Origin);
132-
s3Origin.domainName = s3Domain;
133-
s3Origin.path = path;
134-
request.uri = file;
135-
addS3HostHeader(request, s3Domain);
136-
return request;
135+
const request = event.Records[0].cf.request;
136+
if (manifest.disableOriginResponseHandler) {
137+
const { req, res, responsePromise } = lambdaAtEdgeCompat(
138+
event.Records[0].cf,
139+
{
140+
enableHTTPCompression: manifest.enableHTTPCompression
141+
}
142+
);
143+
144+
const bucketName = s3BucketNameFromEventRequest(request) ?? "";
145+
const s3Key = (path + file).slice(1); // need to remove leading slash from path for s3 key
146+
147+
return await renderStaticPage({
148+
route: route,
149+
request: request,
150+
req: req,
151+
res: res,
152+
responsePromise: responsePromise,
153+
manifest: manifest,
154+
routesManifest: routesManifest,
155+
bucketName: bucketName,
156+
s3Key: s3Key,
157+
s3Uri: file,
158+
basePath: basePath
159+
});
160+
} else {
161+
const s3Origin = request.origin?.s3 as CloudFrontS3Origin;
162+
const s3Domain = normaliseS3OriginDomain(s3Origin);
163+
s3Origin.domainName = s3Domain;
164+
s3Origin.path = path;
165+
request.uri = file;
166+
addS3HostHeader(request, s3Domain);
167+
return request;
168+
}
137169
};
138170

139171
const reconstructOriginalRequestUri = (
@@ -205,7 +237,14 @@ const handleOriginRequest = async ({
205237

206238
if (route.isPublicFile) {
207239
const { file } = route as PublicFileRoute;
208-
return staticRequest(request, file, `${routesManifest.basePath}/public`);
240+
return await staticRequest(
241+
event,
242+
file,
243+
`${routesManifest.basePath}/public`,
244+
route,
245+
manifest,
246+
routesManifest
247+
);
209248
}
210249
if (route.isStatic) {
211250
const { file, isData } = route as StaticRoute;
@@ -214,7 +253,14 @@ const handleOriginRequest = async ({
214253
: `${routesManifest.basePath}/static-pages/${manifest.buildId}`;
215254

216255
const relativeFile = isData ? file : file.slice("pages".length);
217-
return staticRequest(request, relativeFile, path);
256+
return await staticRequest(
257+
event,
258+
relativeFile,
259+
path,
260+
route,
261+
manifest,
262+
routesManifest
263+
);
218264
}
219265

220266
const external: ExternalRoute = route;
@@ -311,7 +357,8 @@ const handleOriginResponse = async ({
311357
const { throttle } = await triggerStaticRegeneration({
312358
basePath,
313359
request,
314-
response,
360+
eTag: response.headers["etag"]?.[0].value,
361+
lastModified: response.headers["etag"]?.[0].value,
315362
pagePath: staticRoute.page,
316363
queueName: regenerationQueueName
317364
});

packages/libs/lambda-at-edge/src/lib/triggerStaticRegeneration.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import * as crypto from "crypto";
44

55
interface TriggerStaticRegenerationOptions {
66
request: AWSLambda.CloudFrontRequest;
7-
response: AWSLambda.CloudFrontResponse;
7+
eTag: string | undefined;
8+
lastModified: string | undefined;
89
basePath: string | undefined;
910
pagePath: string;
1011
queueName: string;
@@ -55,10 +56,10 @@ export const triggerStaticRegeneration = async (
5556
// update. This will prevent the case where this page is being
5657
// requested again whilst its already started to regenerate.
5758
MessageDeduplicationId:
58-
options.response.headers["etag"]?.[0].value ||
59-
new Date(options.response.headers["last-modified"]?.[0].value)
60-
.getTime()
61-
.toString(),
59+
options.eTag ??
60+
(options.lastModified
61+
? new Date(options.lastModified).getTime().toString()
62+
: new Date().getTime().toString()),
6263
// Only deduplicate based on the object, i.e. we can generate
6364
// different pages in parallel, just not the same one
6465
MessageGroupId: hashedUri

0 commit comments

Comments
 (0)