You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
module: async hooks stop require.extensions from loading CommonJS resolved by registerHooks() #66998
v26.2.0 and later (tested up to v26.12.1). v26.0.0 and v26.1.0 work. v24.22.1 behaves like v26.2.0.
Platform
Darwin 27.0.0 arm64
Subsystem
module
What steps will reproduce the bug?
setup.cjs:
constModule=require('node:module');// A require hook for .ts files, like the one pirates installsModule._extensions['.ts']=(mod,filename)=>{constsrc=require('node:fs').readFileSync(filename,'utf8').replace('TYPESCRIPT','transformed');mod._compile(src,filename);};if(process.env.SYNC){Module.registerHooks({resolve(s,c,n){constr=n(s,c);returnr.url.endsWith('.ts') ? { ...r,format: 'commonjs'} : r;},load: (u,c,n)=>n(u,c),});}if(process.env.ASYNC)Module.register('./async-hooks.mjs',require('node:url').pathToFileURL(__filename));
How often does it reproduce? Is there a required condition?
Always, when a module.registerHooks() resolve hook returns the commonjs format for a file, and any module.register() hooks are also registered, even pass-through ones.
What is the expected behavior? Why is that the expected behavior?
transformed in both cases, as in v26.0.0 and v26.1.0. Adding a pass-through hook shouldn't change how the module is loaded. Without it, the CommonJS module is loaded through require.extensions, so the .ts handler runs.
What do you see instead?
With the pass-through hook, the source is compiled as it is, and the .ts handler in require.extensions is never called. With real TypeScript in the file, the import fails with a SyntaxError.
Additional information
The behavior changed in v26.2.0. That release includes #62920 ("module: fix sync hook short-circuit in require() in imported CJS"), which may be related.
I hit this while moving the Backstage CLI's TypeScript transform from module.register() to module.registerHooks() because of DEP0205. Tools such as import-in-the-middle, which OpenTelemetry uses for ESM, still register their hooks with module.register(), so both kinds of hooks end up registered in the same process.
Activity