From fc432e0fd5a367349895b8381742376385e0fff4 Mon Sep 17 00:00:00 2001 From: Antoine Lethimonnier <43064022+WarningImHack3r@users.noreply.github.com> Date: Mon, 11 May 2026 16:25:28 +0200 Subject: [PATCH] fix(node): prefer Module#registerHooks over Module#register (#20028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix this warning when building apps with TailwindCSS with Node 26+: ``` (node:25346) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead. at node:internal/util:129:11 at Module.register (node:internal/modules/esm/loader:969:3) at file:///Users/antoine/Developer/my-app/node_modules/.pnpm/@tailwindcss+node@4.3.0/node_modules/@tailwindcss/node/dist/index.mjs:18:214 at ... ``` This PR: - Correctly prefers using `Module#registerHooks` instead of `Module#register` by checking its availability at runtime - Adjusts the exports of the hooks’ file by creating a synchronous version for the new API - Remove now unused exports from the `package.json`, relying on the [recommended usage in the docs](https://nodejs.org/docs/latest/api/module.html#registration-of-asynchronous-customization-hooks) for the `Module#register` calls ## Test plan I'd be happy to ensure this works correctly on my end before merging this, but it's not as trivial to test locally as a logic fix. Can you guide me through what I need to do to test this? I extensively based my change on the docs, following those guides: - [Fixing imports for `Module#register`](https://nodejs.org/docs/latest/api/module.html#registration-of-asynchronous-customization-hooks) - [Using the new `Module#registerHooks` function](https://nodejs.org/docs/latest/api/module.html#registration-of-synchronous-customization-hooks) (and other more detailed sections of the same docs page) --- Fixes #19893 Closes #19907 --------- Co-authored-by: Robin Malfait --- CHANGELOG.md | 4 +++- .../@tailwindcss-node/src/esm-cache.loader.mts | 16 +++++++++++++++- packages/@tailwindcss-node/src/index.cts | 9 ++++++++- packages/@tailwindcss-node/src/index.ts | 9 ++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ecc509c..cf5ebd5fd 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 diff --git a/packages/@tailwindcss-node/src/esm-cache.loader.mts b/packages/@tailwindcss-node/src/esm-cache.loader.mts index edcfc8d77..952b2f189 100644 --- a/packages/@tailwindcss-node/src/esm-cache.loader.mts +++ b/packages/@tailwindcss-node/src/esm-cache.loader.mts @@ -1,8 +1,22 @@ -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) +} + +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 diff --git a/packages/@tailwindcss-node/src/index.cts b/packages/@tailwindcss-node/src/index.cts index 4bca0a5e1..9f2788933 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?.(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 a5e7bf5b4..22a62b248 100644 --- a/packages/@tailwindcss-node/src/index.ts +++ b/packages/@tailwindcss-node/src/index.ts @@ -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' @@ -14,8 +15,14 @@ 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?.(pathToFileURL(localRequire.resolve('@tailwindcss/node/esm-cache-loader'))) + } }