From 546e78cb0f4e55dc5f040b9bd3c96f709f98a819 Mon Sep 17 00:00:00 2001 From: Janka Uryga Date: Wed, 7 May 2025 14:05:19 +0200 Subject: [PATCH] patch react via recast instead of string replacements --- packages/next/package.json | 1 + .../cjs/react-dom-server.edge.development.js | 26 +- .../cjs/react-dom-server.edge.production.js | 26 +- .../cjs/react-dom-server.edge.development.js | 26 +- .../cjs/react-dom-server.edge.production.js | 26 +- ...r-dom-turbopack-server.edge.development.js | 26 +- ...er-dom-turbopack-server.edge.production.js | 26 +- ...r-dom-turbopack-server.edge.development.js | 26 +- ...er-dom-turbopack-server.edge.production.js | 26 +- ...ver-dom-webpack-server.edge.development.js | 26 +- ...rver-dom-webpack-server.edge.production.js | 26 +- ...ver-dom-webpack-server.edge.development.js | 26 +- ...rver-dom-webpack-server.edge.production.js | 26 +- packages/next/taskfile.js | 260 ++++++++++++++---- pnpm-lock.yaml | 18 +- 15 files changed, 361 insertions(+), 230 deletions(-) diff --git a/packages/next/package.json b/packages/next/package.json index d57fedd7033ff..be5da70812d07 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -304,6 +304,7 @@ "querystring-es3": "0.2.1", "raw-body": "2.4.1", "react-refresh": "0.12.0", + "recast": "0.23.11", "regenerator-runtime": "0.13.4", "sass-loader": "15.0.0", "schema-utils2": "npm:schema-utils@2.7.1", diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js index 01da5da5d6bf4..0990d97633b0b 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js @@ -35,6 +35,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function styleReplacer(match, prefix, s, suffix) { return "" + prefix + ("s" === s ? "\\73 " : "\\53 ") + suffix; } @@ -4903,7 +4912,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createSuspenseBoundary( request, @@ -8473,7 +8482,7 @@ request ) : enqueueEarlyPreloadsAfterInitialWork(request)); - }, 0); + }); } function enqueueEarlyPreloadsAfterInitialWork(request) { safelyEmitEarlyPreloads(request, 0 === request.pendingRootTasks); @@ -8488,7 +8497,7 @@ destination ? flushCompletedQueues(request, destination) : (request.flushScheduled = !1); - }, 0)); + })); } function startFlowing(request, destination) { if (13 === request.status) @@ -10392,16 +10401,5 @@ startWork(request); }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.version = "19.2.0-experimental-197d6a04-20250424"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js index 117b5dd7753bd..8d3fe9168ca2d 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-dom-server.edge.production.js @@ -4411,7 +4420,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createSuspenseBoundary( request, @@ -6936,7 +6945,7 @@ function startWork(request) { request ) : enqueueEarlyPreloadsAfterInitialWork(request)); - }, 0); + }); } function enqueueEarlyPreloadsAfterInitialWork(request) { safelyEmitEarlyPreloads(request, 0 === request.pendingRootTasks); @@ -6951,7 +6960,7 @@ function enqueueFlush(request) { destination ? flushCompletedQueues(request, destination) : (request.flushScheduled = !1); - }, 0)); + })); } function startFlowing(request, destination) { if (13 === request.status) @@ -7305,15 +7314,4 @@ exports.resumeAndPrerender = function (children, postponedState, options) { startWork(request); }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.version = "19.2.0-experimental-197d6a04-20250424"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js index 444136a74fb13..14ab76a210586 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js @@ -35,6 +35,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function styleReplacer(match, prefix, s, suffix) { return "" + prefix + ("s" === s ? "\\73 " : "\\53 ") + suffix; } @@ -4565,7 +4574,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createSuspenseBoundary( request, @@ -7704,7 +7713,7 @@ request ) : enqueueEarlyPreloadsAfterInitialWork(request)); - }, 0); + }); } function enqueueEarlyPreloadsAfterInitialWork(request) { safelyEmitEarlyPreloads(request, 0 === request.pendingRootTasks); @@ -7719,7 +7728,7 @@ destination ? flushCompletedQueues(request, destination) : (request.flushScheduled = !1); - }, 0)); + })); } function startFlowing(request, destination) { if (13 === request.status) @@ -9439,16 +9448,5 @@ startWork(request); }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.version = "19.2.0-canary-197d6a04-20250424"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js index 1c0ddceb10674..9a68913b21de9 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-dom-server.edge.production.js @@ -4078,7 +4087,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createSuspenseBoundary( request, @@ -6262,7 +6271,7 @@ function startWork(request) { request ) : enqueueEarlyPreloadsAfterInitialWork(request)); - }, 0); + }); } function enqueueEarlyPreloadsAfterInitialWork(request) { safelyEmitEarlyPreloads(request, 0 === request.pendingRootTasks); @@ -6277,7 +6286,7 @@ function enqueueFlush(request) { destination ? flushCompletedQueues(request, destination) : (request.flushScheduled = !1); - }, 0)); + })); } function startFlowing(request, destination) { if (13 === request.status) @@ -6468,15 +6477,4 @@ exports.renderToReadableStream = function (children, options) { startWork(request); }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.version = "19.2.0-canary-197d6a04-20250424"; diff --git a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.development.js b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.development.js index ad8c0650ffbaf..8b8739ab0e141 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.development.js +++ b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.development.js @@ -11,6 +11,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function voidHandler() {} function getIteratorFn(maybeIterable) { if (null === maybeIterable || "object" !== typeof maybeIterable) @@ -1445,7 +1454,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask( request, @@ -2826,7 +2835,7 @@ }); setTimeoutOrImmediate(function () { request.status === OPENING && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -2837,7 +2846,7 @@ request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if ( @@ -4303,17 +4312,6 @@ bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, turbopackMap, options) { var request = createRequest( model, diff --git a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.production.js b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.production.js index 4ca23bd6c40d6..620dc0df307c0 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.production.js +++ b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-server-dom-turbopack-server.edge.production.js @@ -1144,7 +1153,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask(request, model, keyPath, implicitSlot, abortSet) { request.pendingChunks++; @@ -1949,7 +1958,7 @@ function startWork(request) { }); setTimeoutOrImmediate(function () { 10 === request.status && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -1960,7 +1969,7 @@ function enqueueFlush(request) { request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if (0 === request.abortableTasks.size && 0 === request.abortListeners.size) @@ -2881,17 +2890,6 @@ exports.registerServerReference = function (reference, id, exportName) { bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, turbopackMap, options) { var request = new RequestInstance( 20, diff --git a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js index 51d557f2add18..04a09df7a494c 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js +++ b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.development.js @@ -11,6 +11,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function voidHandler() {} function getIteratorFn(maybeIterable) { if (null === maybeIterable || "object" !== typeof maybeIterable) @@ -1415,7 +1424,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask( request, @@ -2667,7 +2676,7 @@ }); setTimeoutOrImmediate(function () { request.status === OPENING && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -2678,7 +2687,7 @@ request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if ( @@ -4102,17 +4111,6 @@ bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, turbopackMap, options) { var request = createRequest( model, diff --git a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js index de7961ef413a4..feec70823829e 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js +++ b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-server-dom-turbopack-server.edge.production.js @@ -1112,7 +1121,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask(request, model, keyPath, implicitSlot, abortSet) { request.pendingChunks++; @@ -1840,7 +1849,7 @@ function startWork(request) { }); setTimeoutOrImmediate(function () { 10 === request.status && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -1851,7 +1860,7 @@ function enqueueFlush(request) { request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if (0 === request.abortableTasks.size && 0 === request.abortListeners.size) @@ -2754,17 +2763,6 @@ exports.registerServerReference = function (reference, id, exportName) { bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, turbopackMap, options) { var request = new RequestInstance( 20, diff --git a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js index 6d49aff71eb04..54989fa74bfdb 100644 --- a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js +++ b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.development.js @@ -11,6 +11,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function voidHandler() {} function getIteratorFn(maybeIterable) { if (null === maybeIterable || "object" !== typeof maybeIterable) @@ -1445,7 +1454,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask( request, @@ -2826,7 +2835,7 @@ }); setTimeoutOrImmediate(function () { request.status === OPENING && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -2837,7 +2846,7 @@ request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if ( @@ -4306,17 +4315,6 @@ bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, webpackMap, options) { var request = createRequest( model, diff --git a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.production.js b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.production.js index be86d67e39011..c917a9c618b98 100644 --- a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.production.js +++ b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-server-dom-webpack-server.edge.production.js @@ -1144,7 +1153,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask(request, model, keyPath, implicitSlot, abortSet) { request.pendingChunks++; @@ -1949,7 +1958,7 @@ function startWork(request) { }); setTimeoutOrImmediate(function () { 10 === request.status && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -1960,7 +1969,7 @@ function enqueueFlush(request) { request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if (0 === request.abortableTasks.size && 0 === request.abortListeners.size) @@ -2884,17 +2893,6 @@ exports.registerServerReference = function (reference, id, exportName) { bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, webpackMap, options) { var request = new RequestInstance( 20, diff --git a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js index 5c6a6514b9d9d..08c37d2f1cb68 100644 --- a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js +++ b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js @@ -11,6 +11,15 @@ "use strict"; "production" !== process.env.NODE_ENV && (function () { + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); function voidHandler() {} function getIteratorFn(maybeIterable) { if (null === maybeIterable || "object" !== typeof maybeIterable) @@ -1415,7 +1424,7 @@ }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask( request, @@ -2667,7 +2676,7 @@ }); setTimeoutOrImmediate(function () { request.status === OPENING && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -2678,7 +2687,7 @@ request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if ( @@ -4105,17 +4114,6 @@ bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, webpackMap, options) { var request = createRequest( model, diff --git a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js index 0aa53bfb1f096..6470f6ba70bd5 100644 --- a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js +++ b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.production.js @@ -1,3 +1,12 @@ +// This is a patch added by Next.js +const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); /** * @license React * react-server-dom-webpack-server.edge.production.js @@ -1112,7 +1121,7 @@ function pingTask(request, task) { }) : setTimeoutOrImmediate(function () { return performWork(request); - }, 0)); + })); } function createTask(request, model, keyPath, implicitSlot, abortSet) { request.pendingChunks++; @@ -1840,7 +1849,7 @@ function startWork(request) { }); setTimeoutOrImmediate(function () { 10 === request.status && (request.status = 11); - }, 0); + }); } function enqueueFlush(request) { !1 === request.flushScheduled && @@ -1851,7 +1860,7 @@ function enqueueFlush(request) { request.flushScheduled = !1; var destination = request.destination; destination && flushCompletedChunks(request, destination); - }, 0)); + })); } function callOnAllReadyIfReady(request) { if (0 === request.abortableTasks.size && 0 === request.abortListeners.size) @@ -2757,17 +2766,6 @@ exports.registerServerReference = function (reference, id, exportName) { bind: { value: bind, configurable: !0 } }); }; - -// This is a patch added by Next.js -const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - exports.renderToReadableStream = function (model, webpackMap, options) { var request = new RequestInstance( 20, diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 5bffe54540269..90cdbb3de2b4f 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -8,6 +8,7 @@ const fs = require('fs/promises') const resolveFrom = require('resolve-from') const execa = require('execa') const process = require('process') +const recast = require('recast') export async function next__polyfill_nomodule(task, opts) { await task @@ -1633,11 +1634,11 @@ export async function copy_vendor_react(task_) { filepath ) ) { - newSource = replaceSetTimeout({ - code: newSource, - file: filepath, - insertBefore: /\n\s*exports\.version =/, + const ast = parseFile(newSource, { + sourceFileName: filepath, }) + replaceSetTimeoutInAst(ast, filepath) + newSource = recast.print(ast).code } file.data = newSource @@ -1647,11 +1648,10 @@ export async function copy_vendor_react(task_) { }) .target(`src/compiled/react-dom${packageSuffix}/cjs`) - function replaceSetTimeout({ - code, - file, - insertBefore: insertBeforePattern, - }) { + function replaceSetTimeoutInAst( + /** @type {recast.types.namedTypes.File} */ ast, + /** @type {string} */ filepath + ) { // FIXME: we need this hack until we can use the Node build of 'react-dom/server' // // We're currently using the Edge builds of 'react-dom/server' and 'react-server-dom-{webpack,turbopack}' everywhere. @@ -1665,41 +1665,166 @@ export async function copy_vendor_react(task_) { // setTimeout(() => ..., 0) // into this: // setImmediate(() => ...) - // - // ReactDOM only ever calls `setTimeout` with `0` (and no further arguments), - // so we can just naively replace `setTimeout` with `setImmediate`. - // Technically the `0` will then be passed to the callback as an argument, - // but the callbacks will always ignore it anyway. - // NOTE: we have to replace these before inserting the definition of `setTimeoutOrImmediate`, - // otherwise we'd break it! - code = code.replaceAll(`setTimeout`, `setTimeoutOrImmediate`) + recast.types.namedTypes.File.assert(ast) + const definitionStr = outdent` + // This is a patch added by Next.js + const setTimeoutOrImmediate = + typeof globalThis["set" + "Immediate"] === "function" && + // edge runtime sandbox defines a stub for setImmediate + // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) + // but it's made non-enumerable, so we can detect it + globalThis.propertyIsEnumerable("setImmediate") + ? globalThis["set" + "Immediate"] + : (callback, ...args) => setTimeout(callback, 0, ...args); + + ` + const getDefinitionStmt = () => { + const fileAst = /** @type {recast.types.namedTypes.File} */ ( + recast.parse(definitionStr) + ) + return fileAst.program.body[0] + } + + let needsDefinition = false + recast.visit(ast, { + visitCallExpression(path) { + const { callee, arguments: args } = path.node + + if (callee.type === 'Identifier' && callee.name === 'setTimeout') { + const durationArg = args.length >= 2 ? args[1] : undefined + if ( + // `setTimeout(fn)` + !durationArg || + // `setTimeout(fn, 0, ...)` + (durationArg.type === 'Literal' && durationArg.value === 0) || + // `setTimeout(fn, undefined, ...)` + (durationArg.type === 'Identifier' && + durationArg.name === 'undefined') + ) { + needsDefinition = true + // setTimeout(fn, 0, ...) -> + // setTimeoutOrImmediate(fn, ...) + callee.name = 'setTimeoutOrImmediate' + path.node.arguments = [args[0], ...args.slice(2)] + } + } + this.traverse(path) + }, + }) + + if (!needsDefinition) { + return + } - const insertionPoint = code.search(insertBeforePattern) - if (insertionPoint === -1) { + let didInsertDefinition = false + recast.visit(ast, { + visitAssignmentExpression(path) { + // we should only insert the definition of `setTimeoutOrImmediate` once. + if (didInsertDefinition) { + return false + } + + // Find the first `exports.NAME = ...` assignment + const { left: target } = path.node + if ( + target.type === 'MemberExpression' && + target.object.type === 'Identifier' && + target.object.name === 'exports' && + // we don't care about which export is being assigned. + target.property.type === 'Identifier' + ) { + didInsertDefinition = true + // We expect `exports` assignments to happen: + // - at the top level for prod builds of react + // - inside an IIFE for dev builds of react + // In either case, we now need find an ancestor node we can insert the definition into. + const blocklikeAncestor = findBlocklikeAncestor( + /** @type {recast.types.NodePath} */ (path) + ) + if (!blocklikeAncestor) { + throw new Error('Could not find a block to insert definition') + } + blocklikeAncestor.insertAt(0, getDefinitionStmt()) + } + + // we don't care about any assignment expressions that might happen in the RHS, + // React doesn't do that + return false + }, + }) + if (!didInsertDefinition) { throw new Error( - `Cannot find insertion point for setTimeoutOrImmediate in ${file}` + `Failed to find an insertion point for \`setTimeout\` replacement in '${filepath}'` ) } - const toInsert = - '\n\n' + - outdent` - // This is a patch added by Next.js - const setTimeoutOrImmediate = - typeof globalThis['set' + 'Immediate'] === 'function' && - // edge runtime sandbox defines a stub for setImmediate - // (see 'addStub' in packages/next/src/server/web/sandbox/context.ts) - // but it's made non-enumerable, so we can detect it - globalThis.propertyIsEnumerable('setImmediate') - ? globalThis['set' + 'Immediate'] - : setTimeout; - ` + - '\n' - - return ( - code.slice(0, insertionPoint) + toInsert + code.slice(insertionPoint) - ) + function findBlocklikeAncestor( + /** @type {recast.types.NodePath} */ path + ) { + /** @type {recast.types.NodePath | null} */ + let current = path + while (current) { + if ( + recast.types.namedTypes.BlockStatement.check(current.node) || + recast.types.namedTypes.Program.check(current.node) + ) { + break + } else { + current = current.parentPath + } + } + return current + } + } + + function replaceIdentifiersInAst( + /** @type {recast.types.namedTypes.File} */ ast, + /** @type {Map} */ replacements + ) { + recast.types.namedTypes.File.assert(ast) + recast.visit(ast, { + visitIdentifier(path) { + const replacement = replacements.get(path.node.name) + if (replacement !== undefined) { + path.replace(replacement) + } + this.traverse(path) + }, + }) + } + + function parseFile( + /** @type {string} */ code, + /** @type {recast.Options} */ opts + ) { + /** @type {recast.types.namedTypes.File} */ + const file = recast.parse(code, { + parser: { + parse(source, options) { + return require('recast/parsers/acorn').parse(source, { + ...options, + // allow `import()` in `react-server-dom-{webpack,turbopack}-client.node.unbundled.development.js` + ecmaVersion: 'latest', + sourceType: 'script', + }) + }, + }, + ...opts, + }) + return file + } + + /** @typedef {ReturnType} ExpressionKind */ + + function parseExpression(/** @type {string} */ exprCode) { + /** @type {recast.types.namedTypes.File} */ + const ast = recast.parse(`(${exprCode});`) + const statement = + /** @type {recast.types.namedTypes.ExpressionStatement} */ ( + ast.program.body[0] + ) + return statement.expression } // Remove unused files @@ -1753,19 +1878,22 @@ export async function copy_vendor_react(task_) { (file.base.startsWith('react-server-dom-webpack-server') && !file.base.startsWith('react-server-dom-webpack-server.browser')) ) { + const filepath = file.dir + '/' + file.base const source = file.data.toString() - let newSource = source.replace( - /__webpack_require__/g, - 'globalThis.__next_require__' + const ast = parseFile(source, { sourceFileName: filepath }) + replaceIdentifiersInAst( + ast, + new Map([ + [ + '__webpack_require__', + parseExpression('globalThis.__next_require__'), + ], + ]) ) if (file.base.startsWith('react-server-dom-webpack-server.edge')) { - newSource = replaceSetTimeout({ - code: newSource, - file: file.base, - insertBefore: /\n\s*exports\.renderToReadableStream =/, - }) + replaceSetTimeoutInAst(ast, filepath) } - file.data = newSource + file.data = recast.print(ast).code } else if (file.base === 'package.json') { file.data = overridePackageName(file.data) } @@ -1803,31 +1931,41 @@ export async function copy_vendor_react(task_) { if (file.base.startsWith('react-server-dom-turbopack-client.browser')) { const source = file.data.toString() - let newSource = source.replace( - /__turbopack_load__/g, - '__turbopack_load_by_url__' + const filepath = file.dir + '/' + file.base + const ast = parseFile(source, { sourceFileName: filepath }) + replaceIdentifiersInAst( + ast, + new Map([['__turbopack_load__', '__turbopack_load_by_url__']]) ) - - file.data = newSource + file.data = recast.print(ast).code } else if ( file.base.startsWith('react-server-dom-turbopack-client') || (file.base.startsWith('react-server-dom-turbopack-server') && !file.base.startsWith('react-server-dom-turbopack-server.browser')) ) { const source = file.data.toString() - let newSource = source - .replace(/__turbopack_load__/g, 'globalThis.__next_chunk_load__') - .replace(/__turbopack_require__/g, 'globalThis.__next_require__') + const filepath = file.dir + '/' + file.base + const ast = parseFile(source, { sourceFileName: filepath }) + + replaceIdentifiersInAst( + ast, + new Map([ + [ + '__turbopack_load__', + parseExpression('globalThis.__next_chunk_load__'), + ], + [ + '__turbopack_require__', + parseExpression('globalThis.__next_require__'), + ], + ]) + ) if (file.base.startsWith('react-server-dom-turbopack-server.edge')) { - newSource = replaceSetTimeout({ - code: newSource, - file: file.base, - insertBefore: /\n\s*exports\.renderToReadableStream =/, - }) + replaceSetTimeoutInAst(ast, filepath) } - file.data = newSource + file.data = recast.print(ast).code } else if (file.base === 'package.json') { file.data = overridePackageName(file.data) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aaa5d31f7e972..65453c038abfb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1432,6 +1432,9 @@ importers: react-refresh: specifier: 0.12.0 version: 0.12.0 + recast: + specifier: 0.23.11 + version: 0.23.11 regenerator-runtime: specifier: 0.13.4 version: 0.13.4 @@ -13692,6 +13695,7 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qs@6.11.0: @@ -14000,6 +14004,10 @@ packages: resolution: {integrity: sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==} engines: {node: '>= 4'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + recast@0.23.9: resolution: {integrity: sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==} engines: {node: '>= 4'} @@ -20404,7 +20412,7 @@ snapshots: esbuild-register: 3.6.0(esbuild@0.24.2) jsdoc-type-pratt-parser: 4.0.0 process: 0.11.10 - recast: 0.23.9 + recast: 0.23.11 semver: 7.6.3 util: 0.12.5 ws: 8.2.3 @@ -31887,6 +31895,14 @@ snapshots: source-map: 0.6.1 tslib: 2.8.1 + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + recast@0.23.9: dependencies: ast-types: 0.16.1