From ab9a57910fa4a897f6b91240c7005aaa4699f2c1 Mon Sep 17 00:00:00 2001 From: Dmitrii Troitskii Date: Sat, 18 Apr 2026 10:36:04 +0000 Subject: [PATCH] fix(require-hook): guard require.extensions accesses for Node 24.15+ Yarn PnP Node.js v24.15.0 introduced a regression (nodejs/node#61769) where the `require` function exposed to CJS modules loaded via the ESM loader no longer carries the `.extensions` property when the module source comes through a custom loader (e.g. Yarn PnP zip loader). This caused a crash at module evaluation time: TypeError: Cannot read properties of undefined (reading '.js') at require-hook.js:35 The fix guards all `require.extensions` accesses with optional chaining and adds early-return guards in `registerHook`/`deregisterHook` so the build degrades gracefully instead of crashing. No behaviour change on Node versions where `require.extensions` is always defined. Fixes #92935 --- .../src/build/next-config-ts/require-hook.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/next/src/build/next-config-ts/require-hook.ts b/packages/next/src/build/next-config-ts/require-hook.ts index e4603c9a340e..938eb1693314 100644 --- a/packages/next/src/build/next-config-ts/require-hook.ts +++ b/packages/next/src/build/next-config-ts/require-hook.ts @@ -3,17 +3,22 @@ import Module from 'node:module' import { readFileSync } from 'node:fs' import { dirname } from 'node:path' -const oldJSHook = require.extensions['.js'] +// Node.js v24.15+ with Yarn PnP ESM loader may expose a `require` function +// that does not carry the deprecated `.extensions` property (DEP0007). +// Guard all accesses so next build does not crash in that environment. +const oldJSHook = require.extensions?.['.js'] const extensions = ['.ts', '.cts', '.mts', '.cjs', '.mjs'] export function registerHook(swcOptions: SWCOptions) { + if (!require.extensions) return + // lazy require swc since it loads React before even setting NODE_ENV // resulting loading Development React on Production const { transformSync } = require('../swc') as typeof import('../swc') require.extensions['.js'] = function (mod: any, oldFilename) { try { - return oldJSHook(mod, oldFilename) + return oldJSHook!(mod, oldFilename) } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ERR_REQUIRE_ESM') { throw error @@ -37,13 +42,16 @@ export function registerHook(swcOptions: SWCOptions) { return _compile.call(this, swc.code, filename) } - return oldHook(mod, oldFilename) + return oldHook!(mod, oldFilename) } } } export function deregisterHook() { - require.extensions['.js'] = oldJSHook + if (!require.extensions) return + if (oldJSHook !== undefined) { + require.extensions['.js'] = oldJSHook + } extensions.forEach((ext) => delete require.extensions[ext]) }