Skip to content

Commit 1b87222

Browse files
authored
patch asyncStorage for ISR and fetch (#503)
* patch asyncStorage for ISR and fetch * Create mighty-elephants-design.md
1 parent a7540fd commit 1b87222

File tree

6 files changed

+83
-1
lines changed

6 files changed

+83
-1
lines changed

.changeset/mighty-elephants-design.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"open-next": patch
3+
---
4+
5+
patch asyncStorage for ISR and fetch

packages/open-next/src/build/copyTracedFiles.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import url from "node:url";
2+
13
import {
24
copyFileSync,
35
existsSync,
@@ -14,6 +16,14 @@ import { NextConfig, PrerenderManifest } from "types/next-types";
1416

1517
import logger from "../logger.js";
1618

19+
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
20+
21+
function copyPatchFile(outputDir: string) {
22+
const patchFile = path.join(__dirname, "patch", "patchedAsyncStorage.js");
23+
const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
24+
copyFileSync(patchFile, outputPatchFile);
25+
}
26+
1727
export async function copyTracedFiles(
1828
buildOutputPath: string,
1929
packagePath: string,
@@ -205,6 +215,9 @@ See the docs for more information on how to bundle edge runtime functions.
205215
}
206216
});
207217

218+
// Copy patch file
219+
copyPatchFile(path.join(outputDir, packagePath));
220+
208221
// TODO: Recompute all the files.
209222
// vercel doesn't seem to do it, but it seems wasteful to have all those files
210223
// we replace the pages-manifest.json with an empty one if we don't have a pages dir so that
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ts-nocheck
2+
3+
const asyncStorage = require("next/dist/client/components/static-generation-async-storage.external.original");
4+
5+
const staticGenerationAsyncStorage = {
6+
run: (store, cb, ...args) =>
7+
asyncStorage.staticGenerationAsyncStorage.run(store, cb, ...args),
8+
getStore: () => {
9+
const store = asyncStorage.staticGenerationAsyncStorage.getStore();
10+
if (store) {
11+
store.isOnDemandRevalidate =
12+
store.isOnDemandRevalidate &&
13+
!globalThis.__als.getStore().isISRRevalidation;
14+
}
15+
return store;
16+
},
17+
};
18+
19+
exports.staticGenerationAsyncStorage = staticGenerationAsyncStorage;

packages/open-next/src/core/createMainHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ declare global {
2424
var __als: AsyncLocalStorage<{
2525
requestId: string;
2626
pendingPromiseRunner: DetachedPromiseRunner;
27+
isISRRevalidation?: boolean;
2728
}>;
2829
}
2930

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const mod = require("module");
2+
3+
const resolveFilename = mod._resolveFilename;
4+
5+
export function patchAsyncStorage() {
6+
mod._resolveFilename = function (
7+
originalResolveFilename: typeof resolveFilename,
8+
request: string,
9+
parent: any,
10+
isMain: boolean,
11+
options: any,
12+
) {
13+
if (
14+
request.endsWith("static-generation-async-storage.external") ||
15+
request.endsWith("static-generation-async-storage.external.js")
16+
) {
17+
return require.resolve("./patchedAsyncStorage.cjs");
18+
} else if (
19+
request.endsWith("static-generation-async-storage.external.original")
20+
) {
21+
return originalResolveFilename.call(
22+
mod,
23+
request.replace(".original", ".js"),
24+
parent,
25+
isMain,
26+
options,
27+
);
28+
} else
29+
return originalResolveFilename.call(
30+
mod,
31+
request,
32+
parent,
33+
isMain,
34+
options,
35+
);
36+
37+
// We use `bind` here to avoid referencing outside variables to create potential memory leaks.
38+
}.bind(null, resolveFilename);
39+
}

packages/open-next/src/core/requestHandler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { InternalEvent, InternalResult } from "types/open-next";
99
import { DetachedPromiseRunner } from "utils/promise";
1010

1111
import { debug, error, warn } from "../adapters/logger";
12+
import { patchAsyncStorage } from "./patchAsyncStorage";
1213
import { convertRes, createServerResponse, proxyRequest } from "./routing/util";
1314
import routingHandler, { MiddlewareOutputEvent } from "./routingHandler";
1415
import { requestHandler, setNextjsPrebundledReact } from "./util";
@@ -17,8 +18,11 @@ import { requestHandler, setNextjsPrebundledReact } from "./util";
1718
globalThis.__als = new AsyncLocalStorage<{
1819
requestId: string;
1920
pendingPromiseRunner: DetachedPromiseRunner;
21+
isISRRevalidation?: boolean;
2022
}>();
2123

24+
patchAsyncStorage();
25+
2226
export async function openNextHandler(
2327
internalEvent: InternalEvent,
2428
responseStreaming?: StreamCreator,
@@ -98,8 +102,9 @@ export async function openNextHandler(
98102
const requestId = Math.random().toString(36);
99103
const pendingPromiseRunner: DetachedPromiseRunner =
100104
new DetachedPromiseRunner();
105+
const isISRRevalidation = headers["x-isr"] === "1";
101106
const internalResult = await globalThis.__als.run(
102-
{ requestId, pendingPromiseRunner },
107+
{ requestId, pendingPromiseRunner, isISRRevalidation },
103108
async () => {
104109
const preprocessedResult = preprocessResult as MiddlewareOutputEvent;
105110
const req = new IncomingMessage(reqProps);

0 commit comments

Comments
 (0)