Skip to content

Commit

Permalink
patch asyncStorage for ISR and fetch (#503)
Browse files Browse the repository at this point in the history
* patch asyncStorage for ISR and fetch

* Create mighty-elephants-design.md
  • Loading branch information
conico974 authored Sep 5, 2024
1 parent a7540fd commit 1b87222
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/mighty-elephants-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"open-next": patch
---

patch asyncStorage for ISR and fetch
13 changes: 13 additions & 0 deletions packages/open-next/src/build/copyTracedFiles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import url from "node:url";

import {
copyFileSync,
existsSync,
Expand All @@ -14,6 +16,14 @@ import { NextConfig, PrerenderManifest } from "types/next-types";

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

const __dirname = url.fileURLToPath(new URL(".", import.meta.url));

function copyPatchFile(outputDir: string) {
const patchFile = path.join(__dirname, "patch", "patchedAsyncStorage.js");
const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
copyFileSync(patchFile, outputPatchFile);
}

export async function copyTracedFiles(
buildOutputPath: string,
packagePath: string,
Expand Down Expand Up @@ -205,6 +215,9 @@ See the docs for more information on how to bundle edge runtime functions.
}
});

// Copy patch file
copyPatchFile(path.join(outputDir, packagePath));

// TODO: Recompute all the files.
// vercel doesn't seem to do it, but it seems wasteful to have all those files
// we replace the pages-manifest.json with an empty one if we don't have a pages dir so that
Expand Down
19 changes: 19 additions & 0 deletions packages/open-next/src/build/patch/patchedAsyncStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ts-nocheck

const asyncStorage = require("next/dist/client/components/static-generation-async-storage.external.original");

const staticGenerationAsyncStorage = {
run: (store, cb, ...args) =>
asyncStorage.staticGenerationAsyncStorage.run(store, cb, ...args),
getStore: () => {
const store = asyncStorage.staticGenerationAsyncStorage.getStore();
if (store) {
store.isOnDemandRevalidate =
store.isOnDemandRevalidate &&
!globalThis.__als.getStore().isISRRevalidation;
}
return store;
},
};

exports.staticGenerationAsyncStorage = staticGenerationAsyncStorage;
1 change: 1 addition & 0 deletions packages/open-next/src/core/createMainHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ declare global {
var __als: AsyncLocalStorage<{
requestId: string;
pendingPromiseRunner: DetachedPromiseRunner;
isISRRevalidation?: boolean;
}>;
}

Expand Down
39 changes: 39 additions & 0 deletions packages/open-next/src/core/patchAsyncStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const mod = require("module");

const resolveFilename = mod._resolveFilename;

export function patchAsyncStorage() {
mod._resolveFilename = function (
originalResolveFilename: typeof resolveFilename,
request: string,
parent: any,
isMain: boolean,
options: any,
) {
if (
request.endsWith("static-generation-async-storage.external") ||
request.endsWith("static-generation-async-storage.external.js")
) {
return require.resolve("./patchedAsyncStorage.cjs");
} else if (
request.endsWith("static-generation-async-storage.external.original")
) {
return originalResolveFilename.call(
mod,
request.replace(".original", ".js"),
parent,
isMain,
options,
);
} else
return originalResolveFilename.call(
mod,
request,
parent,
isMain,
options,
);

// We use `bind` here to avoid referencing outside variables to create potential memory leaks.
}.bind(null, resolveFilename);
}
7 changes: 6 additions & 1 deletion packages/open-next/src/core/requestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { InternalEvent, InternalResult } from "types/open-next";
import { DetachedPromiseRunner } from "utils/promise";

import { debug, error, warn } from "../adapters/logger";
import { patchAsyncStorage } from "./patchAsyncStorage";
import { convertRes, createServerResponse, proxyRequest } from "./routing/util";
import routingHandler, { MiddlewareOutputEvent } from "./routingHandler";
import { requestHandler, setNextjsPrebundledReact } from "./util";
Expand All @@ -17,8 +18,11 @@ import { requestHandler, setNextjsPrebundledReact } from "./util";
globalThis.__als = new AsyncLocalStorage<{
requestId: string;
pendingPromiseRunner: DetachedPromiseRunner;
isISRRevalidation?: boolean;
}>();

patchAsyncStorage();

export async function openNextHandler(
internalEvent: InternalEvent,
responseStreaming?: StreamCreator,
Expand Down Expand Up @@ -98,8 +102,9 @@ export async function openNextHandler(
const requestId = Math.random().toString(36);
const pendingPromiseRunner: DetachedPromiseRunner =
new DetachedPromiseRunner();
const isISRRevalidation = headers["x-isr"] === "1";
const internalResult = await globalThis.__als.run(
{ requestId, pendingPromiseRunner },
{ requestId, pendingPromiseRunner, isISRRevalidation },
async () => {
const preprocessedResult = preprocessResult as MiddlewareOutputEvent;
const req = new IncomingMessage(reqProps);
Expand Down

0 comments on commit 1b87222

Please sign in to comment.