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 detection treats typescript import ... = require as ES module syntax #54514
and run it with node --experimental-transform-types ./example.cts.
How often does it reproduce? Is there a required condition?
This happens consistently.
What is the expected behavior? Why is that the expected behavior?
This should execute as a CommonJS module.
Despite appearances import ... = require(...) is specifically for CommonJS modules (so that CommonJS modules can also import and export types, not just values).
What do you see instead?
The code is incorrectly transformed to have ES module syntax and throws an error at runtime:
(node:67783) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/home/jamesernator/projects/playground/test.cts:3
export { };
^^^^^^
SyntaxError: Unexpected token 'export'
at wrapSafe (node:internal/modules/cjs/loader:1469:18)
at Module._compile (node:internal/modules/cjs/loader:1491:20)
at Object.loadCTS [as .cts] (node:internal/modules/cjs/loader:1581:10)
at Module.load (node:internal/modules/cjs/loader:1317:32)
at Module._load (node:internal/modules/cjs/loader:1127:12)
at TracingChannel.traceSync (node:diagnostics_channel:315:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:166:5)
at node:internal/main/run_main_module:30:49
Node.js v22.7.0
changed the title [-]Detect modules treats typescript import require as es module syntax[/-][+]Module detection treats typescript import ... = require as ES module syntax[/+]on Aug 23, 2024
This syntax is not supported by node without some transformation.
cc @nodejs/typescript I think this syntax is not allowed under isolatedModules
EDIT: apparently swc can safely perform the transformation
It looks like SWC is auto-adding export {} which is something tsc does too to force the output to be recognised as ESM.
AFAIK that feature was added to workaround an issue with downstream processing by webpack.
Given the only consumer of the emitted JS here is the Node runtime, it has no use for this generated syntax, so we should probably just pass a flag to SWC to disable that addition. It's one of the existing (but lesser known) SWC transform options and I can't find the name just now.
There's noEmptyExport: bool. It's a part of the transform config. (same level as nativeClassProperties)
It exists for the exact reason - Deno did not need export {}
Is this a bug in SWC?
Previously, in SWC, subsequent processing would either convert to CJS, removing export {}.
Alternatively, it would proceed with the ESM process, where import = require would cause an error, same as tsc.
We didn't have a direct use case for TypeScript pass before, so we overlooked this intermediate outcome.
Activity
[-]Detect modules treats typescript import require as es module syntax[/-][+]Module detection treats typescript import ... = require as ES module syntax[/+]marco-ippolito commentedon Aug 23, 2024
This syntax is not supported by node without some transformation.
cc @nodejs/typescript I think this syntax is not allowed under
isolatedModulesEDIT: apparently swc can safely perform the transformation
Jamesernator commentedon Aug 23, 2024
I don't see why this would be different than
enumornamespace, the expected transform is trivial (this is whattscalready does):robpalme commentedon Aug 23, 2024
It looks like SWC is auto-adding
export {}which is somethingtscdoes too to force the output to be recognised as ESM.AFAIK that feature was added to workaround an issue with downstream processing by webpack.
Given the only consumer of the emitted JS here is the Node runtime, it has no use for this generated syntax, so we should probably just pass a flag to SWC to disable that addition. It's one of the existing (but lesser known) SWC transform options and I can't find the name just now.
kdy1 commentedon Aug 23, 2024
cc @magic-akari for visibility
There's
noEmptyExport: bool. It's a part of the transform config. (same level asnativeClassProperties)It exists for the exact reason - Deno did not need
export {}magic-akari commentedon Aug 23, 2024
Is this a bug in SWC?
Previously, in SWC, subsequent processing would either convert to CJS, removing
export {}.Alternatively, it would proceed with the ESM process, where
import = requirewould cause an error, same as tsc.We didn't have a direct use case for TypeScript pass before, so we overlooked this intermediate outcome.
fix(es/typescript): Correctly handle ESM context (#9490)
ovflowd commentedon Aug 24, 2024
This is a legit “aha” moment
ovflowd commentedon Aug 24, 2024
@marco-ippolito will amaro need to bump its swc version?
marco-ippolito commentedon Aug 24, 2024
No, we manually set the flag to remove
export {}regardless, PR is already open to update amarov0.1.8with the right flag #54520module: use amaro default transform values