Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f5ee4da

Browse files
conico974khuezy
authored andcommitted
fix ISR not working reliably
1 parent f16b50f commit f5ee4da

File tree

5 files changed

+41
-18
lines changed

5 files changed

+41
-18
lines changed

packages/open-next/src/adapters/http/responseStreaming.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class StreamingServerResponse extends http.ServerResponse {
99
[HEADERS]: Record<string, string> = {};
1010
responseStream: ResponseStream;
1111
fixHeaders: (headers: Record<string, string>) => void;
12+
onEnd: (headers: Record<string, string>) => Promise<void>;
1213
private _wroteHeader = false;
1314
private _hasWritten = false;
1415

@@ -54,8 +55,12 @@ export class StreamingServerResponse extends http.ServerResponse {
5455
statusCode: statusCode as number,
5556
headers: this[HEADERS],
5657
});
57-
this.internalWrite(prelude);
58-
this.internalWrite(new Uint8Array(8));
58+
process.nextTick(() => {
59+
this.responseStream.write(prelude);
60+
});
61+
process.nextTick(() => {
62+
this.responseStream.write(new Uint8Array(8));
63+
});
5964
// this.responseStream = awslambda.HttpResponseStream.from(
6065
// this.responseStream,
6166
// {
@@ -96,9 +101,10 @@ export class StreamingServerResponse extends http.ServerResponse {
96101
}
97102

98103
process.nextTick(() => {
99-
this.responseStream.end(() => {
104+
this.responseStream.end(async () => {
100105
// The callback seems necessary here
101106
debug("stream end", chunk);
107+
await this.onEnd(this[HEADERS]);
102108
});
103109
});
104110
// debug("stream end", chunk);
@@ -116,13 +122,15 @@ export class StreamingServerResponse extends http.ServerResponse {
116122
{ method, headers }: { method?: string; headers?: Record<string, string> },
117123
responseStream: ResponseStream,
118124
fixHeaders: (headers: Record<string, string>) => void,
125+
onEnd: (headers: Record<string, string>) => Promise<void>,
119126
) {
120127
//@ts-ignore
121128
super({ method });
122129

123130
this[HEADERS] = headers || {};
124131

125132
this.fixHeaders = fixHeaders;
133+
this.onEnd = onEnd;
126134
this.responseStream = responseStream;
127135

128136
this.useChunkedEncodingByDefault = false;

packages/open-next/src/adapters/plugins/routing/default.replacement.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { loadBuildId, loadConfigHeaders, loadRoutesManifest } from "../../util";
1919
import {
2020
addOpenNextHeader,
2121
fixCacheHeaderForHtmlPages,
22+
fixISRHeaders,
2223
fixSWRCacheHeader,
2324
revalidateIfRequired,
2425
} from "./util";
@@ -129,6 +130,7 @@ export async function postProcessResponse({
129130
fixCacheHeaderForHtmlPages(internalEvent.rawPath, headers);
130131
fixSWRCacheHeader(headers);
131132
addOpenNextHeader(headers);
133+
fixISRHeaders(headers);
132134

133135
await revalidateIfRequired(
134136
internalEvent.headers.host,

packages/open-next/src/adapters/plugins/routing/default.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ServerResponse } from "../../http/response";
1111
import {
1212
addOpenNextHeader,
1313
fixCacheHeaderForHtmlPages,
14+
fixISRHeaders,
1415
fixSWRCacheHeader,
1516
revalidateIfRequired,
1617
} from "./util";
@@ -58,6 +59,7 @@ export async function postProcessResponse({
5859
fixCacheHeaderForHtmlPages(internalEvent.rawPath, headers);
5960
fixSWRCacheHeader(headers);
6061
addOpenNextHeader(headers);
62+
fixISRHeaders(headers);
6163

6264
await revalidateIfRequired(
6365
internalEvent.headers.host,

packages/open-next/src/adapters/plugins/routing/util.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,25 +73,33 @@ export function addOpenNextHeader(headers: Record<string, string | undefined>) {
7373
headers["X-OpenNext"] = process.env.OPEN_NEXT_VERSION;
7474
}
7575

76-
export async function revalidateIfRequired(
77-
host: string,
78-
rawPath: string,
79-
headers: Record<string, string | undefined>,
80-
req: IncomingMessage,
81-
) {
76+
export function fixISRHeaders(headers: Record<string, string | undefined>) {
77+
if (headers["x-nextjs-cache"] === "REVALIDATED") {
78+
headers["cache-control"] =
79+
"private, no-cache, no-store, max-age=0, must-revalidate";
80+
return;
81+
}
8282
if (headers["x-nextjs-cache"] !== "STALE") return;
8383

8484
// If the cache is stale, we revalidate in the background
8585
// In order for CloudFront SWR to work, we set the stale-while-revalidate value to 2 seconds
8686
// This will cause CloudFront to cache the stale data for a short period of time while we revalidate in the background
8787
// Once the revalidation is complete, CloudFront will serve the fresh data
8888
headers["cache-control"] = "s-maxage=2, stale-while-revalidate=2592000";
89+
}
8990

91+
export async function revalidateIfRequired(
92+
host: string,
93+
rawPath: string,
94+
headers: Record<string, string | undefined>,
95+
req?: IncomingMessage,
96+
) {
97+
if (headers["x-nextjs-cache"] !== "STALE") return;
9098
// If the URL is rewritten, revalidation needs to be done on the rewritten URL.
9199
// - Link to Next.js doc: https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#on-demand-revalidation
92100
// - Link to NextInternalRequestMeta: https://github.com/vercel/next.js/blob/57ab2818b93627e91c937a130fb56a36c41629c3/packages/next/src/server/request-meta.ts#L11
93101
// @ts-ignore
94-
const internalMeta = req[Symbol.for("NextInternalRequestMeta")];
102+
const internalMeta = req?.[Symbol.for("NextInternalRequestMeta")];
95103

96104
// When using Pages Router, two requests will be received:
97105
// 1. one for the page: /foo

packages/open-next/src/adapters/plugins/streaming.replacement.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { processInternalEvent } from "./routing/default.js";
1515
import {
1616
addOpenNextHeader,
1717
fixCacheHeaderForHtmlPages,
18+
fixISRHeaders,
1819
fixSWRCacheHeader,
1920
revalidateIfRequired,
2021
} from "./routing/util";
@@ -51,10 +52,19 @@ export const lambdaHandler = awslambda.streamifyResponse(async function (
5152
{ method, headers },
5253
responseStream,
5354
// We need to fix the cache header before sending any response
54-
async (headers) => {
55+
(headers) => {
5556
fixCacheHeaderForHtmlPages(internalEvent.rawPath, headers);
5657
fixSWRCacheHeader(headers);
5758
addOpenNextHeader(headers);
59+
fixISRHeaders(headers);
60+
},
61+
// This run in the callback of the response stream end
62+
async (headers) => {
63+
await revalidateIfRequired(
64+
internalEvent.headers.host,
65+
internalEvent.rawPath,
66+
headers,
67+
);
5868
},
5969
);
6070

@@ -86,13 +96,6 @@ export const lambdaHandler = awslambda.streamifyResponse(async function (
8696

8797
//@ts-expect-error - processRequest is already defined in serverHandler.ts
8898
await processRequest(req, res, overwrittenInternalEvent, isExternalRewrite);
89-
90-
await revalidateIfRequired(
91-
internalEvent.headers.host,
92-
internalEvent.rawPath,
93-
res.headers,
94-
req,
95-
);
9699
}
97100
});
98101
//#endOverride

0 commit comments

Comments
 (0)