-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a compiler error when using `module: esxxxx with moduleResolution: nodexx #50985
Conversation
I think we should discuss making the other |
Mmm, I mean, it sounds kinda bad, but, conversely, when you think about it without the file extension, it's what people do all the time - downleveling esm input to cjs output. It's just that output file extension is kinda eck, since you'd have a .mjs file with a commonjs module inside. But, like, ignoring the "type: module" field and transforming esm .js files to commonjs is exactly why people combine those flags. |
The code looks fine, but as per the comments above, I'd like to better understand a few things. @weswigham @andrewbranch what types of bad things can happen e.g. with |
I think we should consider a broader set of errors or fixes for trying to do stuff that’s only going to work in |
Why even mess with the files module system when either of the new file extensions are used? The compiler should just leave it alone if the extension is Here's an example of what could go wrong. esm.mts interface ESM {
esm: boolean;
}
export const esm: ESM = {
esm: true
}
export type { ESM } tsconfig.json {
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"moduleResolution": "NodeNext",
"outDir": "dist",
},
"include": ["esm.mts"]
} package.json {
"version": "0.0.0",
"type": "commonjs"
} Now run script.js const doImport = async () => {
await import('./dist/esm.mjs')
}
doImport() Now run the script: node script.js
file:///path/to/dist/esm.mjs:2
Object.defineProperty(exports, "__esModule", { value: true });
^
ReferenceError: exports is not defined in ES module scope
at file:///path/to/dist/esm.mjs:2:23
at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:428:15)
at async doImport (/Users/morgan/code/babel-dual-package/script.js:3:3)
Node.js v20.5.0 Errors also arise when starting from an ESM-first project, i.e. changing to script.js import { esm } from './dist/esm.mjs' Running this script produces this unexpected error: file:///path/to/script.js:1
import { esm } from './dist/esm.mjs'
^^^
SyntaxError: The requested module './dist/esm.mjs' does not provide an export named 'esm'
at ModuleJob._instantiate (node:internal/modules/esm/module_job:122:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:188:5)
at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
at async loadESM (node:internal/process/esm_loader:40:7)
at async handleMainPromise (node:internal/modules/run_main:66:12)
Node.js v20.5.0 Ok, well that's because I know it was compiled to use the CJS module system (unexpectedly), so do the import * as esm from './dist/esm.mjs' And running it once again produces another error: file:///path/to/dist/esm.mjs:2
Object.defineProperty(exports, "__esModule", { value: true });
^
ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/path/to/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///path/to/dist/esm.mjs:2:23
at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
at async loadESM (node:internal/process/esm_loader:40:7)
at async handleMainPromise (node:internal/modules/run_main:66:12)
Node.js v20.5.0 None of this is what one would expect when using |
By the way, if TypeScript was thinking people using package.json "type": "commonjs" script.js require('./dist/esm.mjs') node script.js
node:internal/modules/cjs/loader:1089
throw new ERR_REQUIRE_ESM(filename, true);
^
Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/dist/esm.mjs not supported.
Instead change the require of /path/to/dist/esm.mjs to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (/path/to/script.js:1:1) {
code: 'ERR_REQUIRE_ESM'
}
Node.js v20.5.0 The generated output for "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.esm = void 0;
exports.esm = {
esm: true
}; Is there a workaround for this? |
Setting
|
This can be closed; it was superseded by #54567. I forgot this PR existed when I made that one. |
So the shortcomings I brought up here have been addressed in #54567? Namely, there is no way to compile |
Since this combination of options can have confusing behavior for, eg,
.cjs
or.cts
files, which are emitted as esm in this mode. We don't really intend to support this combination of flags, so while it does work and does do something, it's probably not what whoever combined the flags is hoping for, given whatmoduleResolution
andmodule
are each responsible for. (The other old module flags make a degree of sense, since they trigger emitting everything as cjs/amd/umd/system, which are all downlevel formats)Fixes #50647