From ca0e5913d42c39c4d7660f1bd793bf3f3380793c Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Fri, 9 Oct 2026 14:09:55 +0200 Subject: [PATCH] fix(dev): Support Node 24 loader hooks --- packages/cli/script/file-import-hook.mjs | 11 +++++++++++ packages/cli/script/require-shim.mjs | 23 +++++------------------ 2 files changed, 16 insertions(+), 18 deletions(-) create mode 100644 packages/cli/script/file-import-hook.mjs diff --git a/packages/cli/script/file-import-hook.mjs b/packages/cli/script/file-import-hook.mjs new file mode 100644 index 0000000000..826671dfa1 --- /dev/null +++ b/packages/cli/script/file-import-hook.mjs @@ -0,0 +1,11 @@ +/** Handle Bun-style file imports while running source through tsx. */ +export function load(url, context, nextLoad) { + if (context.importAttributes?.type === "file") { + return { + format: "module", + shortCircuit: true, + source: `export default ${JSON.stringify(new URL(url).pathname)};`, + }; + } + return nextLoad(url, context); +} diff --git a/packages/cli/script/require-shim.mjs b/packages/cli/script/require-shim.mjs index 0d8420ce5c..415793fd41 100644 --- a/packages/cli/script/require-shim.mjs +++ b/packages/cli/script/require-shim.mjs @@ -14,7 +14,7 @@ * Or in package.json scripts via the `pnpm tsx` alias. */ -import { createRequire, registerHooks } from "node:module"; +import { createRequire, register } from "node:module"; if (typeof globalThis.require === "undefined") { globalThis.require = createRequire( @@ -22,20 +22,7 @@ if (typeof globalThis.require === "undefined") { ); } -// Handle `with { type: "file" }` import attributes in Node.js dev mode. -// Bun supports this natively; esbuild's text-import-plugin handles it at -// build time. In tsx dev mode neither applies, so we register a synchronous -// hook that returns the file path as a string — matching Bun's behaviour. -// registerHooks() is available from Node 22.15+ (our minimum). -registerHooks({ - load(url, context, nextLoad) { - if (context.importAttributes?.type === "file") { - return { - format: "module", - shortCircuit: true, - source: `export default ${JSON.stringify(new URL(url).pathname)};`, - }; - } - return nextLoad(url, context); - }, -}); +// Use an asynchronous hook so existing CommonJS loaders may omit `source`. +// Node 24 rejects that valid asynchronous result when it passes through a +// synchronous hook. +register(new URL("./file-import-hook.mjs", import.meta.url));