Repository navigation
On Windows arm64 TS-based custom loader sometimes causes the process to exit silently when used with --experimental-strip-types #54645
Description
Activity
- addedwindowsIssues and PRs related to the Windows platform.Issues and PRs related to the Windows platform.loadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.strip-typesIssues and PRs related to TypeScript type stripping.Issues and PRs related to TypeScript type stripping.
on Aug 29, 2024 Is this issue specific to the code you are importing, or is it imports (via --import) in general?
Looks like striping types from loaders issue, the one this issue is primarily about, is not specific to the code I'm importing. The example I provided is literally just a console.log, and it still fails.
The second issue that I experienced when using pure JS loaders instead needs further investigation so I'll report this separately. But so far, it seems it's stopping module resolution on the entry module, without any errors. I'd suspect it's my mistake, I'm no expert in Node.js loaders, but then why it works on macOS 👀
CC @nodejs/loaders @nodejs/typescript
Can you run it again with
NODE_DEBUGset to*in your env?I could not reproduce with node v22.7.0 on windows:
PS C:\Users\MarcoHD\Documents\projects\forks\node> node --experimental-strip-types --import file:///C:/Users/MarcoHD/Documents/projects/forks/node/test/fixtures/typescript/ts/test-loader.ts test\fixtures\typescript\ts\test-typescript.ts (node:2428) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) (node:2428) [MODULE_TYPELESS_PACKAGE_JSON] Warning: file:///C:/Users/MarcoHD/Documents/projects/forks/node/test/fixtures/typescript/ts/test-loader.ts parsed as an ES module because module syntax was detected; to avoid the performance penalty of syntax detection, add "type": "module" to C:\package.json (node:2428) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) (node:2428) [MODULE_TYPELESS_PACKAGE_JSON] Warning: file:///C:/Users/MarcoHD/Documents/projects/forks/node/test/fixtures/typescript/ts/hook.ts parsed as an ES module because module syntax was detected; to avoid the performance penalty of syntax detection, add "type": "module" to C:\package.json Hello, TypeScript!Warns are emitted twice because loader is off thread.
you can find the test here: #54657Can you run it again with NODE_DEBUG set to * in your env?
Sure!
node --import=./register.ts --experimental-strip-types ./test.js
PS C:\server> $Env:NODE_DEBUG = "*" PS C:\server> node --import=./register.ts --experimental-strip-types ./test.js (node:32848) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) ESM 32848: Storing file:///C:/server/register.ts (implicit type) in ModuleLoadMap ESM 32848: async addJobsToDependencyGraph() file:///C:/server/register.ts ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'file:///C:/server/register.ts', module: Promise { }, modulePromise: Promise { }, linked: Promise { }, instantiated: undefined } ESM 32848: Translating TypeScript file:///C:/server/register.ts ESM 32848: Translating StandardModule file:///C:/server/register.ts ESM 32848: Storing node:module (implicit type) in ModuleLoadMap ESM 32848: async link() file:///C:/server/register.ts -> node:module ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'node:module', module: Promise { }, modulePromise: Promise { }, linked: Promise { }, instantiated: undefined } ESM 32848: Translating BuiltinModule node:module MODULE 32848: load built-in module node:module ESM 32848: Loading BuiltinModule node:module ESM 32848: async addJobsToDependencyGraph() file:///C:/server/register.ts ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'node:module', module: ModuleWrap { url: 'node:module' }, modulePromise: Promise { ModuleWrap { url: 'node:module' } }, linked: Promise { [Array(0): null prototype] [] }, instantiated: undefined } WORKER 32848: [0] create new worker internal/modules/esm/worker { stderr: false, stdin: false, stdout: false, trackUnmanagedFds: false, workerData: { lock: SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 } } } isInternal: true WORKER 32848: instantiating Worker. url: node:internal/modules/esm/worker doEval: internal WORKER 32848: [0] created Worker with ID 1 STREAM 32848: pipe count=1 opts=undefined STREAM 32848: resume STREAM 32848: pipe count=1 opts=undefined STREAM 32848: resume ESM 32848: wait for signal from worker ESM 32848: post sync message to worker { method: 'register', args: [ './hooks.ts', 'file:///C:/server/register.ts', undefined, undefined ], transferList: undefined } ESM 32848: wait for sync response from worker { method: 'register', args: [ './hooks.ts', 'file:///C:/server/register.ts', undefined, undefined ] } ESM 32848: wait for sync response from worker { method: 'register', args: [ './hooks.ts', 'file:///C:/server/register.ts', undefined, undefined ] }Which is vastly different output than when using JS loader:
node --import=./register.js --experimental-strip-types ./test.js
PS C:\server> node --import=./register.js --experimental-strip-types ./test.js (node:23116) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) ESM 23116: Storing file:///C:/server/register.js (implicit type) in ModuleLoadMap ESM 23116: async addJobsToDependencyGraph() file:///C:/server/register.js ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'file:///C:/server/register.js', module: Promise { }, modulePromise: Promise { }, linked: Promise { }, instantiated: undefined } ESM 23116: Translating StandardModule file:///C:/server/register.js ESM 23116: Storing node:module (implicit type) in ModuleLoadMap ESM 23116: async link() file:///C:/server/register.js -> node:module ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'node:module', module: Promise { }, modulePromise: Promise { }, linked: Promise { }, instantiated: undefined } ESM 23116: Translating BuiltinModule node:module MODULE 23116: load built-in module node:module ESM 23116: Loading BuiltinModule node:module ESM 23116: async addJobsToDependencyGraph() file:///C:/server/register.js ModuleJob { importAttributes: [Object: null prototype] {}, isMain: false, inspectBrk: false, url: 'node:module', module: ModuleWrap { url: 'node:module' }, modulePromise: Promise { ModuleWrap { url: 'node:module' } }, linked: Promise { [Array(0): null prototype] [] }, instantiated: undefined } WORKER 23116: [0] create new worker internal/modules/esm/worker { stderr: false, stdin: false, stdout: false, trackUnmanagedFds: false, workerData: { lock: SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 } } } isInternal: true WORKER 23116: instantiating Worker. url: node:internal/modules/esm/worker doEval: internal WORKER 23116: [0] created Worker with ID 1 STREAM 23116: pipe count=1 opts=undefined STREAM 23116: resume STREAM 23116: pipe count=1 opts=undefined STREAM 23116: resume ESM 23116: wait for signal from worker ESM 23116: post sync message to worker { method: 'register', args: [ './hooks.js', 'file:///C:/server/register.js', undefined, undefined ], transferList: undefined } ESM 23116: wait for sync response from worker { method: 'register', args: [ './hooks.js', 'file:///C:/server/register.js', undefined, undefined ] } ESM 23116: wait for sync response from worker { method: 'register', args: [ './hooks.js', 'file:///C:/server/register.js', undefined, undefined ] } ESM 23116: got sync response from worker { method: 'register', args: [ './hooks.js', 'file:///C:/server/register.js', undefined, undefined ] } ESM 23116: post async message to worker { method: 'resolve', args: [ 'file:///C:/server/test.js', undefined, [Object: null prototype] {} ], transferList: undefined } ESM 23116: wait for async response from worker { method: 'resolve', args: [ 'file:///C:/server/test.js', undefined, [Object: null prototype] {} ] } ESM 23116: wait for async response from worker { method: 'resolve', args: [ 'file:///C:/server/test.js', undefined, [Object: null prototype] {} ] } STREAM 23116: resume false STREAM 23116: read 0 STREAM 23116: need readable false STREAM 23116: length less than watermark true STREAM 23116: do read STREAM 23116: flow STREAM 23116: read undefined STREAM 23116: need readable true STREAM 23116: length less than watermark true STREAM 23116: reading, ended or constructing false STREAM 23116: resume false STREAM 23116: read 0 STREAM 23116: need readable false STREAM 23116: length less than watermark true STREAM 23116: do read STREAM 23116: flow STREAM 23116: read undefined STREAM 23116: need readable true STREAM 23116: length less than watermark true STREAM 23116: reading, ended or constructing false STREAM 23116: push WORKER 23116: [1] is setting up worker child environmentSTREAM 23116: ondata
WORKER 23116: [1] is setting up worker child environment
STREAM 23116: dest.write true
STREAM 23116: maybeReadMore read 0
STREAM 23116: read 0
STREAM 23116: need readable true
STREAM 23116: length less than watermark true
STREAM 23116: do read
STREAM 23116: push STREAM 23116: push nullSTREAM 23116: ondata
STREAM 23116: push null
STREAM 23116: dest.write true
STREAM 23116: push STREAM 23116: onEofChunkSTREAM 23116: ondata
STREAM 23116: onEofChunk
STREAM 23116: dest.write true
STREAM 23116: push STREAM 23116: emitReadableSTREAM 23116: ondata
STREAM 23116: emitReadable
STREAM 23116: dest.write true
STREAM 23116: push STREAM 23116: emitReadable falseSTREAM 23116: ondata
STREAM 23116: emitReadable false
STREAM 23116: dest.write true
STREAM 23116: push WORKER 23116: [1] starts worker script internal/modules/esm/worker (eval = internal) at cwd = C:\serverSTREAM 23116: ondata
WORKER 23116: [1] starts worker script internal/modules/esm/worker (eval = internal) at cwd = C:\server
STREAM 23116: dest.write true
STREAM 23116: push (node:23116) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Usenode --trace-warnings ...to show where the warning was created)STREAM 23116: ondata
(node:23116) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Usenode --trace-warnings ...to show where the warning was created)
STREAM 23116: dest.write true
STREAM 23116: push STREAM 23116: emitReadable_STREAM 23116: ondata
STREAM 23116: emitReadable_
STREAM 23116: dest.write true
STREAM 23116: push STREAM 23116: flowSTREAM 23116: ondata
STREAM 23116: flow
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: Storing file:///C:/server/hooks.js (implicit type) in ModuleLoadMapSTREAM 23116: ondata
ESM 23116: Storing file:///C:/server/hooks.js (implicit type) in ModuleLoadMap
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: async addJobsToDependencyGraph() file:///C:/server/hooks.js ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'file:///C:/server/hooks.js',
module: Promise { },
modulePromise: Promise { },
linked: Promise { },
instantiated: undefined
}STREAM 23116: ondata
ESM 23116: async addJobsToDependencyGraph() file:///C:/server/hooks.js ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'file:///C:/server/hooks.js',
module: Promise { },
modulePromise: Promise { },
linked: Promise { },
instantiated: undefined
}
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: Translating StandardModule file:///C:/server/hooks.jsSTREAM 23116: ondata
ESM 23116: Translating StandardModule file:///C:/server/hooks.js
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: Storing node:path (implicit type) in ModuleLoadMapSTREAM 23116: ondata
ESM 23116: Storing node:path (implicit type) in ModuleLoadMap
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: async link() file:///C:/server/hooks.js -> node:path ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'node:path',
module: Promise { },
modulePromise: Promise { },
linked: Promise { },
instantiated: undefined
}STREAM 23116: ondata
ESM 23116: async link() file:///C:/server/hooks.js -> node:path ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'node:path',
module: Promise { },
modulePromise: Promise { },
linked: Promise { },
instantiated: undefined
}
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: Translating BuiltinModule node:pathSTREAM 23116: ondata
ESM 23116: Translating BuiltinModule node:path
STREAM 23116: dest.write true
STREAM 23116: push MODULE 23116: load built-in module node:pathSTREAM 23116: ondata
MODULE 23116: load built-in module node:path
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: Loading BuiltinModule node:pathSTREAM 23116: ondata
ESM 23116: Loading BuiltinModule node:path
STREAM 23116: dest.write true
STREAM 23116: push ESM 23116: async addJobsToDependencyGraph() file:///C:/server/hooks.js ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'node:path',
module: ModuleWrap { url: 'node:path' },
modulePromise: Promise { ModuleWrap { url: 'node:path' } },
linked: Promise { [Array(0): null prototype] [] },
instantiated: undefined
}STREAM 23116: ondata
ESM 23116: async addJobsToDependencyGraph() file:///C:/server/hooks.js ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: false,
inspectBrk: false,
url: 'node:path',
module: ModuleWrap { url: 'node:path' },
modulePromise: Promise { ModuleWrap { url: 'node:path' } },
linked: Promise { [Array(0): null prototype] [] },
instantiated: undefined
}
STREAM 23116: dest.write true
STREAM 23116: maybeReadMore read 0
STREAM 23116: read 0
STREAM 23116: need readable true
STREAM 23116: length less than watermark true
STREAM 23116: do read
ESM 23116: got async response from worker {
method: 'resolve',
args: [
'file:///C:/server/test.js',
undefined,
[Object: null prototype] {}
]
} Int32Array(1) [ 5 ]
ESM 23116: post async message to worker {
method: 'load',
args: [
'file:///C:/server/test.ts',
{
format: 'module-typescript',
importAttributes: [Object: null prototype] {}
}
],
transferList: undefined
}
ESM 23116: wait for async response from worker {
method: 'load',
args: [
'file:///C:/server/test.ts',
{
format: 'module-typescript',
importAttributes: [Object: null prototype] {}
}
]
}
ESM 23116: Storing file:///C:/server/test.ts (implicit type) in ModuleLoadMap
ESM 23116: async addJobsToDependencyGraph() file:///C:/server/test.ts ModuleJob {
importAttributes: [Object: null prototype] {},
isMain: true,
inspectBrk: false,
url: 'file:///C:/server/test.ts',
module: Promise { },
modulePromise: Promise { },
linked: Promise { },
instantiated: undefined
}
ESM 23116: got async response from worker {
method: 'load',
args: [
'file:///C:/server/test.ts',
{
format: 'module-typescript',
importAttributes: [Object: null prototype] {}
}
]
} Int32Array(1) [ 7 ]
ESM 23116: Translating TypeScript file:///C:/server/test.ts
ESM 23116: Translating StandardModule file:///C:/server/test.ts
Hello, world!
I could not reproduce with node v22.7.0 on windows:
On Windows arm64? :)
Fun facts:
register.tsthat registershooks.jsalso works finehooks.tsdoes not work under ANY circumstances, even if I strip types off it so it's essentially pure JavaScript
- changed the title
[-]On Windows, unlike macOS --import can't be a TS file when used with --experimental-strip-types[/-][+]On Windows (arm64?) `--import` can't be a TS file when used with `--experimental-strip-types`[/+]on Aug 30, 2024 try to add change
hook.tstoexport const resolve: ResolveHook = async function resolve(specifier, context, nextResolve) { throw new Error('Kaboom') };I tested it on windows x64 I think this an arm64 specific issue.
I noticed weird behavior on arm64 in the past (cc @legendecas) but I dont have a machine to reproduce@marco-ippolito Both JS and TS throw! O_O
PS C:\server> node --import=./register.js --experimental-strip-types ./src/index.js (node:26300) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) (node:26300) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) node:internal/modules/run_main:123 triggerUncaughtException( ^ Error: Kaboom! at resolve (file:///C:/server/hooks.js:6:9) at nextResolve (node:internal/modules/esm/hooks:748:28) at Hooks.resolve (node:internal/modules/esm/hooks:240:30) at handleMessage (node:internal/modules/esm/worker:199:24) at Immediate.checkForMessages (node:internal/modules/esm/worker:141:28) at process.processImmediate (node:internal/timers:491:21) Node.js v22.7.0 PS C:\server> node --import=./register.ts --experimental-strip-types ./src/index.js (node:23316) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) (node:23316) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) node:internal/modules/run_main:123 triggerUncaughtException( ^ Error: Kaboom! at resolve (file:///C:/server/hooks.ts:8:9) at nextResolve (node:internal/modules/esm/hooks:748:28) at Hooks.resolve (node:internal/modules/esm/hooks:240:30) at handleMessage (node:internal/modules/esm/worker:199:24) at Immediate.checkForMessages (node:internal/modules/esm/worker:141:28) at process.processImmediate (node:internal/timers:491:21) Node.js v22.7.0 PS C:\server>I confirm it is arm64-specific:
PS C:\Users\mzasso\Documents\winbug> node -p "os.arch()" arm64 PS C:\Users\mzasso\Documents\winbug> node --import=./register.ts --experimental-strip-types ./test.ts (node:5008) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) PS C:\Users\mzasso\Documents\winbug> .\node-x64.exe --import=./register.ts --experimental-strip-types ./test.ts (node:7584) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node-x64 --trace-warnings ...` to show where the warning was created) (node:7584) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time (Use `node-x64 --trace-warnings ...` to show where the warning was created) Hello, world!26 remaining items
Well, it's blocked by Amaro, which in turn is blocked by SWC. But after Amaro is eventually updated with a fixed SWC version, a final push is still needed on Node.js side to get this issue resolved.
What about renaming the issue though?
Reacted by Aviv Keller- addeddependenciesPRs that add, update, or configure Node.js dependencies.PRs that add, update, or configure Node.js dependencies.and removedloadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.
on Sep 2, 2024 - changed the title
[-]On Windows arm64 custom loader can't be a TS file when used with `--experimental-strip-types`[/-][+]On Windows arm64 TS-based custom loader sometimes causes the process to exit silently when used with `--experimental-strip-types`[/+]on Sep 2, 2024 Apparently now its working
#54657
I just got a windows arm64 VM to double check- added a commit that references this issue
on Dec 23, 2024 @marco-ippolito What is the first version on which it's expected to work properly? I'll test on a real machine. Latest LTS, 22.12.0, still has this bug. Moreover, the bug in SWC that I originally filed (and is the cause of this failure) still can be reproduced.
@marco-ippolito What is the first version on which it's expected to work properly? I'll test on a real machine. Latest LTS, 22.12.0, still has this bug. Moreover, the bug in SWC that I originally filed (and is the cause of this failure) still can be reproduced.
Try the latest 23, on main the issue is fixed. Today I will provide more info
Reacted by Wojciech MajTested it on main and v23.5.0, everything works fine, commented here: swc-project/swc#9520 (comment)
Whatever it was it has been fixed, it's hard to bisect since compiling on my Windows ARM64 VM takes hours, (I went to sleep and woke up with node compiled). Unless someone wants to invest more money/better machines (which I'm already doing) into finding the commit that caused this issue, I consider this issue fixed.I can confirm that this problem appears to be fixed on Node.js 23.5.0 on a real Windows arm64 machine. 🥳 Melts my brain a little since the bug in swc-project can still be reproduced, but good news anyway I guess 😅
Reacted by Marco Ippolito
Version
22.7.0
Platform
Subsystem
No response
What steps will reproduce the bug?
I was trying to run my TypeScript + node16 resolution app using
--experimental-strip-types.To cope with
--experimental-strip-typesnot working when using.jsextension in import paths, I've decided to use--import, so this is the command I came up with:register.tshooks.tstest.tsHow often does it reproduce? Is there a required condition?
100% of the time, condition: Windows (I tested arm64, can't tell if that happens on other architectures as well).
What is the expected behavior? Why is that the expected behavior?
./test.tsto be executedWhat do you see instead?
On macOS, this works flawlessly, executing
./test.tsfile (mind the extension).On Windows, however, this does not execute the file, and just silently exits after producing one ExperimentalWarning written with red text:
Additional information
Note 1
If I rename register.ts and hooks.ts files to .js and strip types manually, it works:
(side note: first ExperimentalWarning is in red, seconds one in white. I guess one would be enough? :D)
Note 2
In addition, the workaround I came up with (stripping types manually from register.ts and hooks.ts), does not work on a larger scale application for me. This, in turn, produces two ExperimentalWarning like above, but no code appears to be executed, so my guess is that resolution still fails at some point. When added logs, I observed that my resolution hook receives all specifiers it found in my app's entry file, but then stopped resolution altogether.
I logged that issue separately in #54665.