--moduleResolution bundler
(formerly known as hybrid
) by andrewbranch · Pull Request #51669 · microsoft/TypeScript (original) (raw)
This PR introduces a new moduleResolution
setting value called hybrid
bundler
(see #51714), designed primarily for bundlers and runtimes that include a range of Node-like resolution features and ESM syntax, but do not enforce the strict resolution rules that accompany ES modules in Node or in the browser. Special consideration has also been given for bundlers and runtimes that understand TypeScript natively and do not require compilation to JavaScript by tsc
before consumption. Additionally, resolution of package.json exports
and imports
can be enabled/disabled/customized in configuration options. This should allow users of different bundlers and runtimes with slight variations in resolution features to customize TypeScript’s resolution settings under bundler
as appropriate.
- Superset of and closes Prepare module resolution for resolving TS extensions #51171: see --moduleResolution hybrid andrewbranch/TypeScript#2 for a diff between those two branches
- Part of A Proposal For Module Resolution #50152
- Fixes Support package.json exports outside of Node #50794
- Fixes allow voluntary .ts suffix for import paths #37582
- Fixes Remove "An import path cannot end with a '.ts' extension" check (rewriting out-of-scope) #38149
- Fixes Suppressing "The import path cannot end with a '.ts' extension" error? #27481
- Fixes Feature Request: tsconfig option "conditions=x,x,x," "exportConditions" with moduleResolve: node and nodenext and or importMap support #47931
- Closes What should the new moduleResolution setting be called? #51714
Who should use this mode?
- ✅ Application authors who use a bundler on their TS or JS files before a runtime consumes that bundle
- ✅ Application authors who run in Bun
- ✅ Library authors who use a bundler to deploy a UMD bundle
- ⚠️ Library authors who use a tool like Rollup to deploy multiple builds in different module formats—defer to advice from your build tool
- 🚫 Anyone intending to produce modules with
tsc
that will run in Node or the browser without further bundling or processing - 🚫 Anyone intending to produce modules with
tsc
that will run in Deno without further bundling or processing
Comparison with existing module resolution settings
classic | node | node16 | bundler | |
---|---|---|---|---|
node_modules packages | ✅ | ✅ | ✅ | |
extensionless | ✅ | ✅ | CJS only | ✅ |
directory index | ✅ | ✅ | CJS only | ✅ |
*.ts imports | ✅ | |||
package.json exports | ✅ | ✅ | ||
exports conditions | always node, types;import from ESM,require from CJS;custom additions | always types, import;custom additions |
Module syntax restrictions
--moduleResolution bundler
does not support resolution of require
calls. In TypeScript files, this means the import mod = require("foo")
syntax is forbidden; in JavaScript files, require
calls are not errors but only ever return the type any
(or whatever an ambient declaration of a global require
function is declared to return).
New compiler options
allowImportingTsExtensions
: Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set.resolvePackageJsonExports
: Use the package.json 'exports' field when resolving package imports. Enabled by default innode16
,nodenext
, andbundler
.resolvePackageJsonImports
: Use the package.json 'imports' field when resolving imports. Enabled by default innode16
,nodenext
, andbundler
.customConditions
: Conditions to set in addition to the resolver-specific defaults when resolving imports. Valid innode16
,nodenext
, andbundler
.
Open questions
- Should
resolvePackageJsonExports
andresolvePackageJsonImports
be disableable innode16
andnodenext
? I see no valid reason to disable them in those modes, but I haven’t yet prohibited it.- There was no objection to leaving these toggleable.
- I would like to consider allowing
*.ts
imports to resolve in every module resolution mode, or at leastnode16
andnodenext
, to improve consistency and (importantly) portability of .d.ts files between modes. I think @weswigham has already done this in another open PR, so perhaps it won’t be too controversial.- I think this is doable but not necessary for merging; will follow up in a subsequent PR.
- With four new resolution-specific compiler options, it would be nice to introduce hierarchy into tsconfig.json. That’s a non-trivial design discussion on its own, especially considering that tsconfig files can inherit from each other. Is it worth tackling that first / as part of this / in the same release cycle to avoid the expansion of root-level options here?
- This was not considered a blocker when I mentioned it in a design meeting. If there is time to design this before 5.0 is released, we can move the new options accordingly.
- Should
bundler
become the new default resolution mode for--module commonjs
? I would like to renamenode
tonode10
in a follow-up PR, and stop maintaining it going forward. It is not a good choice for anyone since Node 10 is long out of service.- @sandersn endorsed this mode being the new default. I will get more feedback in a subsequent PR.