-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
--moduleResolution bundler
: Require ESM for module
and remove node
from hard-coded conditions
#52940
Conversation
if (emitModuleKindIsNonNodeESM(moduleKind) || mode === ModuleKind.ESNext) { | ||
return importSourceWithoutExtension + (tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"); | ||
const preferTs = isDeclarationFileName(moduleReference) && shouldAllowImportingTsExtension(compilerOptions); | ||
const ext = | ||
tsExtension === Extension.Mts || tsExtension === Extension.Dmts ? preferTs ? ".mts" : ".mjs" : | ||
tsExtension === Extension.Cts || tsExtension === Extension.Dmts ? preferTs ? ".cts" : ".cjs" : | ||
preferTs ? ".ts" : ".js"; | ||
return importSourceWithoutExtension + ext; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has never made a ton of sense to predicate adding an extension to the suggested import source based on module
and not moduleResolution
, but rather than rethink that whole issue, I just made a narrow fix for when .ts
is allowed and intended but the message suggests .js
.
else if (!(node.flags & NodeFlags.Ambient) && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler) { | ||
grammarErrorOnNode(node, Diagnostics.Import_assignment_is_not_allowed_when_moduleResolution_is_set_to_bundler_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can drop this error because it’s redundant with the one that already existed for using import=
in --module esnext
. That makes me feel even more like this is a coherent move.
src/compiler/moduleNameResolver.ts
Outdated
const conditions = esmMode || getEmitModuleResolutionKind(options) === ModuleResolutionKind.Bundler | ||
? ["node", "import"] | ||
: ["node", "require"]; | ||
? ["import"] | ||
: ["require"]; | ||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Bundler) { | ||
conditions.unshift("node"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone suggested dropping node
from the hard-coded set of conditions when moduleResolution
is bundler
and I think that makes sense. I didn’t do it at first because Webpack includes the node
condition, oddly enough, but esbuild doesn’t unless its target is set to Node. It definitely makes more sense to leave it up to customConditions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit suggestion: Instead of unshift can we first add "node" and then others so we arent moving array elements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the order matters; I just didn’t want to change a bunch of baselines unnecessarily. I did unshift
because I remember Ron saying something about if you make an empty array and then push a non-number into it, that does a deopt. Unshift is probably worse though... I think I’ll just push node
on last and change some traces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly conditions can be a Set|undefined
i think.. we always check for contains(array, key) so may be set is better.. But thats not important for this PR.. just mentioning.
@@ -83,5 +83,5 @@ error TS6054: File '/project/e.txt' has an unsupported extension. The only suppo | |||
import {} from "./a.ts"; | |||
import {} from "./a.d.ts"; | |||
~~~~~~~~~~ | |||
!!! error TS2846: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './a' instead? | |||
!!! error TS2846: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './a.ts' instead? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the error message that changed based on my small addition in the checker. It was suggesting ./a.js
before, which is ok, but looks a bit weird when the user has explicitly opted into allowing .ts
extensions.
Out of curiosity - did you consider any special handling for the |
I didn’t, but because we lack the ability to remove conditions, I feel like the best move is to be conservative. Do all bundlers always set the |
Definitely not all of them. I know that it's supported by:
I can't say - without further testing - that it works exactly in the same way in all of them. But generally speaking most bundlers are more permissive when it comes to mixing CJS and ESM, so when that's enabled I would expect all of them to allow requiring a source that is written in ESM. This is the very goal of this condition - bundlers didn't want to not have any escape hatch from the node's strict rules. For that reason, I ship the module condition in all libs that I maintain (or at least in those that target browsers) |
|
This is totally unrelated to the default set of |
src/compiler/moduleNameResolver.ts
Outdated
const conditions = esmMode || getEmitModuleResolutionKind(options) === ModuleResolutionKind.Bundler | ||
? ["node", "import"] | ||
: ["node", "require"]; | ||
? ["import"] | ||
: ["require"]; | ||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Bundler) { | ||
conditions.unshift("node"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit suggestion: Instead of unshift can we first add "node" and then others so we arent moving array elements
Discussion: #52926, #51669 (comment)
Also fixes some missing traces and makes some minor error message tweaks.