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
In TypeScript 7.0, we have no plans to reimplement --moduleResolution classic - its behavior does not model any resolution system in widespread use, and at best it's just an approximation that avoids Node.js style resolution. Users will be better of using nodenext or bundler if necessary.
In TypeScript 6.0, --moduleResolution classic will be deprecated. Users enabling it will get an error message that can only be suppressed via --ignoreDeprecations.
In 7.0, we are thinking the default will be bundler unless there is an appropriate moduleResolution target that matches a given --module target.
See more on deprecations/changes for 6.0/7.0 in #54500.
its behavior does not model any resolution system in widespread use
I know not many people distribute their apps as unbundled ESM in the browser, but that is a valid resolution target used by many when sandboxing applications.
Regardless, a simple "relative paths with file extensions" resolution strategy seems sensible to continue maintaining. I know for sure that I need it
Regardless, a simple "relative paths with file extensions" resolution strategy seems sensible to continue maintaining. I know for sure that I need it
+1 on the above. With the deprecation of the Classic mode, it seems that there is no appropriate moduleResolution value for TypeScript projects that
Target the Browser as the running environment (meaning not NodeJS) AND
Use ES modules (ESM) AND
Don't use bundling, instead deploy the transpiled ES modules directly.
FWIW, this is the mode we had been using in the Chromium codebase up until now, and as part of updating our toolchain to use TS v6 and v7, finding out that we need to change, see https://issues.chromium.org/issues/423789047#comment5 for more context.
Offering basically only NodeNext and Bundled leaves a gap for what I think is quite a common case. While technically NodeNext could be used for projects targeting the Browser this is suboptimal as it performs a bunch of unnecessary NodeJS-related module resolution attempts (as revealed by using --traceResolution) for example trying to walk up the directry tree looking for package.json/ files. See such example below from a trace during Chromium's build when using 'NodeNext'
======== Module name './cr_button.js' was successfully resolved to '/usr/local/home/workspace/chromium/src/out/gchrome/gen/ui/webui/resources/cr_elements/preprocessed/cr_button/cr_button.ts'. ========
File '/usr/local/home/workspace/chromium/src/out/gchrome/gen/third_party/lit/v3_0/package.json' does not exist.
File '/usr/local/home/workspace/chromium/src/out/gchrome/gen/third_party/lit/package.json' does not exist.
File '/usr/local/home/workspace/chromium/src/out/gchrome/gen/third_party/package.json' does not exist.
File '/usr/local/home/workspace/chromium/src/out/gchrome/gen/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/workspace/chromium/src/out/gchrome/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/workspace/chromium/src/out/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/workspace/chromium/src/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/workspace/chromium/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/workspace/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/package.json' does not exist according to earlier cached lookups.
File '/usr/local/home/package.json' does not exist according to earlier cached lookups.
File '/usr/local/package.json' does not exist according to earlier cached lookups.
File '/usr/local/package.json' does not exist according to earlier cached lookups.
File '/usr/package.json' does not exist according to earlier cached lookups.
File '/package.json' does not exist according to earlier cached lookups.
Unfortunately there is no explicit way to turn off this auto-discovery upwards traversal either. Adding a dummy src/package.json file at the root of the repository is a workaround to at least prevent the traversal from looking for files outside of the repository.
Still experimenting with whether using Bundled is OK for non-NodeJS code that is ultimately not bundled and instead deployed as plain ES modules, but given that Bundled is too lenient essentially it would miss errors for import URLs that couldn't be resolved by a browser at runtime (like extension-less imports URLs), so it does not sound appropriate either.
It is probably best filing a separate feature request for "Offer a simple resolutionMode resolving only relative paths and paths specified in tsconfig" (will post a link here if/when I file a dedicated feature request).
FWIW, the part of the trace you posted is not looking for node_modules resolutions; it’s looking for a package.json whose "type" setting would affect the ESM-ness of some file we’re processing. The “according to earlier cached lookups” bit means that there’s effectively zero performance cost of doing that. I agree with your broader point that we don’t have a resolution mode that’s a perfect fit for browser-based ESM. classic wasn’t a good fit either, as it has some really bizarre directory-based lookup behavior for non-relative names that didn’t match any paths.
FWIW, the part of the trace you posted is not looking for node_modules resolutions; it’s looking for a package.json whose "type" setting would affect the ESM-ness of some file we’re processing. The “according to earlier cached lookups” bit means that there’s effectively zero performance cost of doing that.
Thanks for clarifying. I agree that this is probably not affecting performance in practice, and after all v7 already seems lightning fast compared to previous versions, so I incorrectly highlighted this as a performance issue in my previous message.
As for whether this lookup is necessary, the browser itself does not use package.json files to determine if a file is an ES module or old type plain script, nor does it differentiate .js vs .mjs extensions (IIUC it knows either by encountering type="module" in script tags or by knowing whether it was imported via the import keyword). The presence/absence of import, export statements could be a reasonable proxy to automatically detect that in TS, instead of relying on looking up type fields in package.json files (if a hypothetical Browser resolution mode is used).
Either so, the main problem with such auto-discovery lookups is that it can potentially reach outside of the root of a development repository into a developer's machine, making it fragile (for example a developer incidentally/unknowingly places a package.json file in their home dir, resulting in build errors that noone else on the team can reproduce, which has actually happened in the past)
I agree with your broader point that we don’t have a resolution mode that’s a perfect fit for browser-based ESM
Thank you. Should I file a new feature request so that this can be more properly discussed there?
classic wasn’t a good fit either, as it has some really bizarre directory-based lookup behavior for non-relative names that didn’t match any paths.
Ack. I am not advocating for bringing back classic as it was. Essentially asking whether a simpler Browser resolution mode, as a counterpart to NodeNext could be offerred. Thanks!
Activity
DanielRosenwasser commentedon Aug 5, 2025
See also #11434, where I said we were doing this years ago. 😅
DanielRosenwasser commentedon Aug 25, 2025
Updated the issue to mention using
bundleras the default in 7.0.alshdavid commentedon Sep 1, 2025
I know not many people distribute their apps as unbundled ESM in the browser, but that is a valid resolution target used by many when sandboxing applications.
Regardless, a simple "relative paths with file extensions" resolution strategy seems sensible to continue maintaining. I know for sure that I need it
DanielRosenwasser commentedon Sep 3, 2025
Note: this is a bit iffy since the default might still be
classic, but it'll be deprecated.freshp86 commentedon Dec 15, 2025
+1 on the above. With the deprecation of the Classic mode, it seems that there is no appropriate
moduleResolutionvalue for TypeScript projects thatFWIW, this is the mode we had been using in the Chromium codebase up until now, and as part of updating our toolchain to use TS v6 and v7, finding out that we need to change, see https://issues.chromium.org/issues/423789047#comment5 for more context.
Offering basically only
NodeNextandBundledleaves a gap for what I think is quite a common case. While technicallyNodeNextcould be used for projects targeting the Browser this is suboptimal as it performs a bunch of unnecessary NodeJS-related module resolution attempts (as revealed by using--traceResolution) for example trying to walk up the directry tree looking forpackage.json/files. See such example below from a trace during Chromium's build when using 'NodeNext'Unfortunately there is no explicit way to turn off this auto-discovery upwards traversal either. Adding a dummy
src/package.jsonfile at the root of the repository is a workaround to at least prevent the traversal from looking for files outside of the repository.Still experimenting with whether using
Bundledis OK for non-NodeJS code that is ultimately not bundled and instead deployed as plain ES modules, but given thatBundledis too lenient essentially it would miss errors for import URLs that couldn't be resolved by a browser at runtime (like extension-less imports URLs), so it does not sound appropriate either.It is probably best filing a separate feature request for "Offer a simple
resolutionModeresolving only relative paths andpathsspecified in tsconfig" (will post a link here if/when I file a dedicated feature request).andrewbranch commentedon Dec 15, 2025
FWIW, the part of the trace you posted is not looking for
node_modulesresolutions; it’s looking for a package.json whose"type"setting would affect the ESM-ness of some file we’re processing. The “according to earlier cached lookups” bit means that there’s effectively zero performance cost of doing that. I agree with your broader point that we don’t have a resolution mode that’s a perfect fit for browser-based ESM.classicwasn’t a good fit either, as it has some really bizarre directory-based lookup behavior for non-relative names that didn’t match anypaths.freshp86 commentedon Dec 15, 2025
Thanks for clarifying. I agree that this is probably not affecting performance in practice, and after all v7 already seems lightning fast compared to previous versions, so I incorrectly highlighted this as a performance issue in my previous message.
As for whether this lookup is necessary, the browser itself does not use
package.jsonfiles to determine if a file is an ES module or old type plain script, nor does it differentiate.jsvs.mjsextensions (IIUC it knows either by encounteringtype="module"in script tags or by knowing whether it was imported via theimportkeyword). The presence/absence ofimport,exportstatements could be a reasonable proxy to automatically detect that in TS, instead of relying on looking uptypefields inpackage.jsonfiles (if a hypotheticalBrowserresolution mode is used).Either so, the main problem with such auto-discovery lookups is that it can potentially reach outside of the root of a development repository into a developer's machine, making it fragile (for example a developer incidentally/unknowingly places a
package.jsonfile in their home dir, resulting in build errors that noone else on the team can reproduce, which has actually happened in the past)Thank you. Should I file a new feature request so that this can be more properly discussed there?
Ack. I am not advocating for bringing back
classicas it was. Essentially asking whether a simplerBrowserresolution mode, as a counterpart toNodeNextcould be offerred. Thanks!WebUI: Switch default tsconfig moduleResolution to 'NodeNext'.
28 remaining items
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
[Reland] WebUI: Switch default tsconfig moduleResolution to 'NodeNext'.
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution
TS fixes for package resolution