From d7f371f8eefce9fe6989c3a0608619451ad760e5 Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Wed, 27 May 2026 16:38:17 +0300 Subject: [PATCH 1/6] ci: node 26 --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 3bd831cd2c5..dbccdb4f096 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -61,7 +61,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [20.x, 22.x, 24.x, 25.x] + node-version: [20.x, 22.x, 24.x, 26.x] webpack-version: [latest] dev-server-version: [latest] From 24ab3c033b25e145c329354e5fe15123f033bf0a Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Wed, 26 Aug 2026 22:45:23 +0200 Subject: [PATCH 2/6] test: dont use experimental-transform-types on v26 --- test/build/config-format/typescript-mjs/typescript.test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/build/config-format/typescript-mjs/typescript.test.mjs b/test/build/config-format/typescript-mjs/typescript.test.mjs index 03acf17b9a9..1b83c7a0b01 100644 --- a/test/build/config-format/typescript-mjs/typescript.test.mjs +++ b/test/build/config-format/typescript-mjs/typescript.test.mjs @@ -32,7 +32,7 @@ describe("typescript ecma modules configuration", () => { // Fallback to `ts-node/esm` for old Node.js versions nodeOptions: major >= 22 - ? ["--experimental-transform-types", "--no-warnings"] + ? ["--no-warnings", ...(major < 26 ? ["--experimental-transform-types"] : [""])] : [ "--no-deprecation", "--import=data:text/javascript,import { register } from 'node:module'; import { pathToFileURL } from 'node:url'; register('ts-node/esm', pathToFileURL('./'));", From 92caa9f68b9122999d06e59758a249a0c4057ddc Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Wed, 26 Aug 2026 23:27:37 +0200 Subject: [PATCH 3/6] test: fix failing tests --- .../config-format/typescript-mjs/typescript.test.mjs | 2 +- test/external-command/external-command.test.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/build/config-format/typescript-mjs/typescript.test.mjs b/test/build/config-format/typescript-mjs/typescript.test.mjs index 1b83c7a0b01..857678ae870 100644 --- a/test/build/config-format/typescript-mjs/typescript.test.mjs +++ b/test/build/config-format/typescript-mjs/typescript.test.mjs @@ -32,7 +32,7 @@ describe("typescript ecma modules configuration", () => { // Fallback to `ts-node/esm` for old Node.js versions nodeOptions: major >= 22 - ? ["--no-warnings", ...(major < 26 ? ["--experimental-transform-types"] : [""])] + ? ["--no-warnings", ...(major < 26 ? ["--experimental-transform-types"] : [])] : [ "--no-deprecation", "--import=data:text/javascript,import { register } from 'node:module'; import { pathToFileURL } from 'node:url'; register('ts-node/esm', pathToFileURL('./'));", diff --git a/test/external-command/external-command.test.js b/test/external-command/external-command.test.js index 187814fad34..4d405cc5383 100644 --- a/test/external-command/external-command.test.js +++ b/test/external-command/external-command.test.js @@ -3,7 +3,7 @@ const { run } = require("../utils/test-utils"); describe("external command", () => { it("should work", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["custom-command"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -13,7 +13,7 @@ describe("external command", () => { it("should work with options", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["custom-command", "--output=json"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -23,7 +23,7 @@ describe("external command", () => { it("should work with help", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["help", "custom-command"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -37,7 +37,7 @@ describe("external command", () => { __dirname, ["help", "custom-command", "--output"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }, ); @@ -49,7 +49,7 @@ describe("external command", () => { it("should handle errors in external commands", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["errored-custom-command"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }); expect(exitCode).toBe(2); @@ -60,7 +60,7 @@ describe("external command", () => { it("should handle errors in external commands when loading", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["errored-loading-custom-command"], { - nodeOptions: ["--import=./register-loader.mjs"], + nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], }); expect(exitCode).toBe(2); From 283b37f5e352a982169a2591ca03e51587503b2c Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Wed, 26 Aug 2026 23:39:57 +0200 Subject: [PATCH 4/6] chore: revert flag append --- test/external-command/external-command.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/external-command/external-command.test.js b/test/external-command/external-command.test.js index 4d405cc5383..187814fad34 100644 --- a/test/external-command/external-command.test.js +++ b/test/external-command/external-command.test.js @@ -3,7 +3,7 @@ const { run } = require("../utils/test-utils"); describe("external command", () => { it("should work", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["custom-command"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -13,7 +13,7 @@ describe("external command", () => { it("should work with options", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["custom-command", "--output=json"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -23,7 +23,7 @@ describe("external command", () => { it("should work with help", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["help", "custom-command"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }); expect(exitCode).toBe(0); @@ -37,7 +37,7 @@ describe("external command", () => { __dirname, ["help", "custom-command", "--output"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }, ); @@ -49,7 +49,7 @@ describe("external command", () => { it("should handle errors in external commands", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["errored-custom-command"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }); expect(exitCode).toBe(2); @@ -60,7 +60,7 @@ describe("external command", () => { it("should handle errors in external commands when loading", async () => { const { exitCode, stdout, stderr } = await run(__dirname, ["errored-loading-custom-command"], { - nodeOptions: ["--no-deprecation", "--import=./register-loader.mjs"], + nodeOptions: ["--import=./register-loader.mjs"], }); expect(exitCode).toBe(2); From e81993c8d2f9cc2c543ab1c96b6446a7c009de47 Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Wed, 26 Aug 2026 23:52:32 +0200 Subject: [PATCH 5/6] test: use new loader api and fallback to old --- test/external-command/my-loader.mjs | 43 ++++++++++++++++------- test/external-command/register-loader.mjs | 11 ++++-- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/test/external-command/my-loader.mjs b/test/external-command/my-loader.mjs index e1d2f1665a0..2f5280dd2b7 100644 --- a/test/external-command/my-loader.mjs +++ b/test/external-command/my-loader.mjs @@ -1,23 +1,40 @@ import { join } from "node:path"; import { pathToFileURL } from "node:url"; +/** + * Resolves a bare specifier from the `node_modules` directory of the current working directory. + * @param {string} specifier module specifier + * @param {Error & { code?: string }} err error thrown by the next resolve hook + * @returns {{ url: string, shortCircuit: boolean }} resolution result + */ +function resolveFromCwd(specifier, err) { + if (err.code === "ERR_MODULE_NOT_FOUND" && !specifier.startsWith(".")) { + const baseDir = join(process.cwd(), "node_modules/"); + const resolved = join(baseDir, specifier, "index.js"); + + return { + url: pathToFileURL(resolved).href, + shortCircuit: true, + }; + } + + throw err; +} + +// Asynchronous hook, used with `module.register()` export async function resolve(specifier, context, nextResolve) { try { return await nextResolve(specifier, context); } catch (err) { - if (err.code === "ERR_MODULE_NOT_FOUND" && !specifier.startsWith(".")) { - try { - const baseDir = join(process.cwd(), "node_modules/"); - const resolved = join(baseDir, specifier, "index.js"); + return resolveFromCwd(specifier, err); + } +} - return { - url: pathToFileURL(resolved).href, - shortCircuit: true, - }; - } catch { - throw err; - } - } - throw err; +// Synchronous hook, used with `module.registerHooks()` +export function resolveSync(specifier, context, nextResolve) { + try { + return nextResolve(specifier, context); + } catch (err) { + return resolveFromCwd(specifier, err); } } diff --git a/test/external-command/register-loader.mjs b/test/external-command/register-loader.mjs index d3c8a88dce4..3dd8d195ed3 100644 --- a/test/external-command/register-loader.mjs +++ b/test/external-command/register-loader.mjs @@ -1,4 +1,11 @@ -import { register } from "node:module"; +import nodeModule from "node:module"; import { pathToFileURL } from "node:url"; +import { resolveSync } from "./my-loader.mjs"; -register("./my-loader.mjs", pathToFileURL("./")); +// `module.register()` is deprecated (DEP0205) since Node.js 26, +// fallback to it only for Node.js versions without `module.registerHooks()` +if (typeof nodeModule.registerHooks === "function") { + nodeModule.registerHooks({ resolve: resolveSync }); +} else { + nodeModule.register("./my-loader.mjs", pathToFileURL("./")); +} From 2f8c7e1586253bd09582f9e3de3c6fe153b227b9 Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Thu, 27 Aug 2026 00:16:48 +0200 Subject: [PATCH 6/6] ci: add node 25 to test matrix Co-Authored-By: Claude Opus 5 --- .github/workflows/nodejs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index dbccdb4f096..6be6a0a6d5c 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -61,7 +61,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [20.x, 22.x, 24.x, 26.x] + node-version: [20.x, 22.x, 24.x, 25.x, 26.x] webpack-version: [latest] dev-server-version: [latest]