From 79ce2135511ca7c48b6ef7e0bf7faa514606db0b Mon Sep 17 00:00:00 2001 From: WarningImHack3r <43064022+WarningImHack3r@users.noreply.github.com> Date: Sat, 9 May 2026 16:40:31 +0200 Subject: [PATCH 1/4] fix(node): prefer Module#registerHooks instead of Module#register --- packages/@tailwindcss-node/package.json | 8 ------ .../src/esm-cache.loader.mts | 28 ++++++++++++++----- packages/@tailwindcss-node/src/index.cts | 9 +++++- packages/@tailwindcss-node/src/index.ts | 12 +++++--- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/packages/@tailwindcss-node/package.json b/packages/@tailwindcss-node/package.json index be7fc7a40bd2..a28658e5dd46 100644 --- a/packages/@tailwindcss-node/package.json +++ b/packages/@tailwindcss-node/package.json @@ -29,10 +29,6 @@ "./require-cache": { "types": "./dist/require-cache.d.ts", "default": "./dist/require-cache.js" - }, - "./esm-cache-loader": { - "types": "./dist/esm-cache.loader.d.mts", - "default": "./dist/esm-cache.loader.mjs" } } }, @@ -46,10 +42,6 @@ "types": "./src/require-cache.ts", "import": "./src/require-cache.ts", "require": "./src/require-cache.cts" - }, - "./esm-cache-loader": { - "types": "./src/esm-cache.loader.mts", - "default": "./src/esm-cache.loader.mts" } }, "dependencies": { diff --git a/packages/@tailwindcss-node/src/esm-cache.loader.mts b/packages/@tailwindcss-node/src/esm-cache.loader.mts index edcfc8d778ba..6aef6e714205 100644 --- a/packages/@tailwindcss-node/src/esm-cache.loader.mts +++ b/packages/@tailwindcss-node/src/esm-cache.loader.mts @@ -1,22 +1,36 @@ -import { isBuiltin, type ResolveHook } from 'node:module' +import { + isBuiltin, + type ResolveFnOutput, + type ResolveHook, + type ResolveHookContext, + type ResolveHookSync, +} from 'node:module' export let resolve: ResolveHook = async (specifier, context, nextResolve) => { let result = await nextResolve(specifier, context) + return processResolve(context, result) +} + +export let resolveSync: ResolveHookSync = (specifier, context, nextResolve) => { + let result = nextResolve(specifier, context) + return processResolve(context, result) +} - if (result.url === import.meta.url) return result - if (isBuiltin(result.url)) return result - if (!context.parentURL) return result +function processResolve(context: ResolveHookContext, resolve: ResolveFnOutput) { + if (resolve.url === import.meta.url) return resolve + if (isBuiltin(resolve.url)) return resolve + if (!context.parentURL) return resolve let parent = new URL(context.parentURL) let id = parent.searchParams.get('id') - if (id === null) return result + if (id === null) return resolve - let url = new URL(result.url) + let url = new URL(resolve.url) url.searchParams.set('id', id) return { - ...result, + ...resolve, url: `${url}`, } } diff --git a/packages/@tailwindcss-node/src/index.cts b/packages/@tailwindcss-node/src/index.cts index 4bca0a5e11de..86a5e5682e36 100644 --- a/packages/@tailwindcss-node/src/index.cts +++ b/packages/@tailwindcss-node/src/index.cts @@ -1,6 +1,7 @@ import * as Module from 'node:module' import { pathToFileURL } from 'node:url' import * as env from './env' +import { resolveSync } from './esm-cache.loader.mjs' export * from './compile' export * from './instrumentation' export * from './normalize-path' @@ -12,8 +13,14 @@ export { env } // not necessary. if (!process.versions.bun) { // `Module#register` was added in Node v18.19.0 and v20.6.0 + // `Module#registerHooks` was added in Node v22.15.0 and v23.5.0 and is the preferred API since v25.9.0, + // runtime-deprecating `Module#register` since v26 // // Not calling it means that while ESM dependencies don't get reloaded, the // actual included files will because they cache bust directly via `?id=…` - Module.register?.(pathToFileURL(require.resolve('@tailwindcss/node/esm-cache-loader'))) + if (Module.registerHooks) { + Module.registerHooks({ resolve: resolveSync }) + } else { + Module.register?.('./esm-cache.loader.mjs', pathToFileURL(__filename)) + } } diff --git a/packages/@tailwindcss-node/src/index.ts b/packages/@tailwindcss-node/src/index.ts index a5e7bf5b4bc3..9759bc27bd7a 100644 --- a/packages/@tailwindcss-node/src/index.ts +++ b/packages/@tailwindcss-node/src/index.ts @@ -1,6 +1,6 @@ import * as Module from 'node:module' -import { pathToFileURL } from 'node:url' import * as env from './env' +import { resolveSync } from './esm-cache.loader.mjs' export * from './compile' export * from './instrumentation' export * from './normalize-path' @@ -11,11 +11,15 @@ export { env } // In Bun, ESM modules will also populate `require.cache`, so the module hook is // not necessary. if (!process.versions.bun) { - let localRequire = Module.createRequire(import.meta.url) - // `Module#register` was added in Node v18.19.0 and v20.6.0 + // `Module#registerHooks` was added in Node v22.15.0 and v23.5.0 and is the preferred API since v25.9.0, + // runtime-deprecating `Module#register` since v26 // // Not calling it means that while ESM dependencies don't get reloaded, the // actual included files will because they cache bust directly via `?id=…` - Module.register?.(pathToFileURL(localRequire.resolve('@tailwindcss/node/esm-cache-loader'))) + if (Module.registerHooks) { + Module.registerHooks({ resolve: resolveSync }) + } else { + Module.register?.('./esm-cache.loader.mjs', import.meta.url) + } } From 1226a82ecd34e0175c1c7b3e872d3433da3ccec1 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 11 May 2026 15:02:51 +0200 Subject: [PATCH 2/4] use `result` variable name Could've used `resolved` as well, but this reduces the diff --- .../@tailwindcss-node/src/esm-cache.loader.mts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/@tailwindcss-node/src/esm-cache.loader.mts b/packages/@tailwindcss-node/src/esm-cache.loader.mts index 6aef6e714205..952b2f189d94 100644 --- a/packages/@tailwindcss-node/src/esm-cache.loader.mts +++ b/packages/@tailwindcss-node/src/esm-cache.loader.mts @@ -16,21 +16,21 @@ export let resolveSync: ResolveHookSync = (specifier, context, nextResolve) => { return processResolve(context, result) } -function processResolve(context: ResolveHookContext, resolve: ResolveFnOutput) { - if (resolve.url === import.meta.url) return resolve - if (isBuiltin(resolve.url)) return resolve - if (!context.parentURL) return resolve +function processResolve(context: ResolveHookContext, result: ResolveFnOutput) { + if (result.url === import.meta.url) return result + if (isBuiltin(result.url)) return result + if (!context.parentURL) return result let parent = new URL(context.parentURL) let id = parent.searchParams.get('id') - if (id === null) return resolve + if (id === null) return result - let url = new URL(resolve.url) + let url = new URL(result.url) url.searchParams.set('id', id) return { - ...resolve, + ...result, url: `${url}`, } } From 40048037e535d737faa58d40c9d341faff5ab16b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 11 May 2026 16:03:58 +0200 Subject: [PATCH 3/4] re-add `esm-cache-loader` While I don't think anyone is actually using this export directly. Getting rid of this is technically a breaking change, so let's minimize the amount of changes. --- packages/@tailwindcss-node/package.json | 8 ++++++++ packages/@tailwindcss-node/src/index.cts | 2 +- packages/@tailwindcss-node/src/index.ts | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/@tailwindcss-node/package.json b/packages/@tailwindcss-node/package.json index a28658e5dd46..be7fc7a40bd2 100644 --- a/packages/@tailwindcss-node/package.json +++ b/packages/@tailwindcss-node/package.json @@ -29,6 +29,10 @@ "./require-cache": { "types": "./dist/require-cache.d.ts", "default": "./dist/require-cache.js" + }, + "./esm-cache-loader": { + "types": "./dist/esm-cache.loader.d.mts", + "default": "./dist/esm-cache.loader.mjs" } } }, @@ -42,6 +46,10 @@ "types": "./src/require-cache.ts", "import": "./src/require-cache.ts", "require": "./src/require-cache.cts" + }, + "./esm-cache-loader": { + "types": "./src/esm-cache.loader.mts", + "default": "./src/esm-cache.loader.mts" } }, "dependencies": { diff --git a/packages/@tailwindcss-node/src/index.cts b/packages/@tailwindcss-node/src/index.cts index 86a5e5682e36..9f27889337d3 100644 --- a/packages/@tailwindcss-node/src/index.cts +++ b/packages/@tailwindcss-node/src/index.cts @@ -21,6 +21,6 @@ if (!process.versions.bun) { if (Module.registerHooks) { Module.registerHooks({ resolve: resolveSync }) } else { - Module.register?.('./esm-cache.loader.mjs', pathToFileURL(__filename)) + Module.register?.(pathToFileURL(require.resolve('@tailwindcss/node/esm-cache-loader'))) } } diff --git a/packages/@tailwindcss-node/src/index.ts b/packages/@tailwindcss-node/src/index.ts index 9759bc27bd7a..22a62b248937 100644 --- a/packages/@tailwindcss-node/src/index.ts +++ b/packages/@tailwindcss-node/src/index.ts @@ -1,4 +1,5 @@ import * as Module from 'node:module' +import { pathToFileURL } from 'node:url' import * as env from './env' import { resolveSync } from './esm-cache.loader.mjs' export * from './compile' @@ -11,6 +12,8 @@ export { env } // In Bun, ESM modules will also populate `require.cache`, so the module hook is // not necessary. if (!process.versions.bun) { + let localRequire = Module.createRequire(import.meta.url) + // `Module#register` was added in Node v18.19.0 and v20.6.0 // `Module#registerHooks` was added in Node v22.15.0 and v23.5.0 and is the preferred API since v25.9.0, // runtime-deprecating `Module#register` since v26 @@ -20,6 +23,6 @@ if (!process.versions.bun) { if (Module.registerHooks) { Module.registerHooks({ resolve: resolveSync }) } else { - Module.register?.('./esm-cache.loader.mjs', import.meta.url) + Module.register?.(pathToFileURL(localRequire.resolve('@tailwindcss/node/esm-cache-loader'))) } } From 4ea27526a68d231af667cc9fcfa01f985ebe5970 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 11 May 2026 16:16:42 +0200 Subject: [PATCH 4/4] update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ecc509c3c4..cf5ebd5fdb6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Remove deprecation warnings by using `Module#registerHooks` instead of `Module#register` on Node 26+ ([#20028](https://github.com/tailwindlabs/tailwindcss/pull/20028)) ## [4.3.0] - 2026-05-08