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
- ESM emit transforms `importx = require("...")` to a `require` call constructed from a `createRequire` import.
273
273
- CommonJS emit leaves dynamic `import()` calls untransformed, so CommonJS modules can asynchronously import ES modules.
274
274
275
+
### `preserve`
276
+
277
+
In `--module preserve` ([added](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html#support-for-require-calls-in---moduleresolution-bundler-and---module-preserve) in TypeScript 5.4), ECMAScript imports and exports written in input files are preserved in the output, and CommonJS-style `import x = require("...")` and `export = ...` statements are emitted as CommonJS `require` and `module.exports`. In other words, the format of each individual import or export statement is preserved, rather than being coerced into a single format for the whole compilation (or even a whole file).
278
+
279
+
While it’s rare to need to mix imports and require calls in the same file, this `module` mode best reflects the capabilities of most modern bundlers, as well as the Bun runtime.
280
+
281
+
> Why care about TypeScript’s `module` emit with a bundler or with Bun, where you’re likely also setting `noEmit`? TypeScript’s type checking and module resolution behavior are affected by the module format that it _would_ emit. Setting `module` gives TypeScript information about how your bundler or runtime will process imports and exports, which ensures that the types you see on imported values accurately reflect what will happen at runtime or after bundling. See [`--moduleResolution bundler`](#bundler) for more discussion.
> The option `--esModuleInterop` is enabled by default in `--module preserve` only for its [type checking](https://www.typescriptlang.org/docs/handbook/modules/appendices/esm-cjs-interop.html#allowsyntheticdefaultimports-and-esmoduleinterop) behavior. Since imports never transform into require calls in `--module preserve`, `--esModuleInterop` does not affect the emitted JavaScript.
309
+
275
310
### `es2015`, `es2020`, `es2022`, `esnext`
276
311
277
312
#### Summary
@@ -1083,42 +1118,38 @@ Features are listed in order of precedence.
1083
1118
1084
1119
`--moduleResolution bundler` attempts to model the module resolution behavior common to most JavaScript bundlers. In short, this means supporting all the behaviors traditionally associated withNode.js’s CommonJS `require` resolution algorithm like [`node_modules` lookups](#node_modules-package-lookups), [directory modules](#directory-modules-index-file-resolution), and [extensionless paths](#extensionless-relative-paths), while also supporting newer Node.js resolution features like [package.json`"exports"`](#packagejson-exports) and [package.json`"imports"`](#packagejson-imports-and-self-name-imports).
1085
1120
1086
-
This is very similar to the behavior of [`node16` and `nodenext`](#node16-nodenext-1) resolving in CommonJS mode, butin`bundler`, the conditions used to resolve package.json`"exports"`and`"imports"` are always `"types"` and `"import"`. To understand why, let’s compare against what happens to an import in a `.ts` file in `nodenext`:
1121
+
It’s instructive to think about the similarities and differences between `--moduleResolution bundler` and `--moduleResolution nodenext`, particularlyinhow they decide what conditions to use when resolving package.json`"exports"`or`"imports"`. Consideran importstatement in a `.ts` file:
1087
1122
1088
1123
```ts
1089
1124
// index.ts
1090
1125
import { foo } from "pkg";
1091
1126
```
1092
1127
1093
-
In `--module nodenext --moduleResolution nodenext`, the `--module` setting first [determines](#module-format-detection) whether the importwillbeemittedtothe`.js`fileasan`import`or`require`callandpassesthatinformationtoTypeScript’smoduleresolver, whichdecideswhethertomatch`"import"`or`"require"`conditionsaccordingly. ThisensuresTypeScript’smoduleresolutionprocess, althoughworkingfrom input `.ts` files, reflects what will happen in Node.js’s module resolution process when it runs the output `.js` files.
1128
+
Recall that in`--module nodenext --moduleResolution nodenext`, the `--module` setting first [determines](#module-format-detection) whether the importwillbeemittedtothe`.js`fileasan`import`or`require`call, thenpassesthatinformationtoTypeScript’smoduleresolver, whichdecideswhethertomatch`"import"`or`"require"`conditionsin`"pkg"`’spackage.json`"exports"`accordingly. Let’sassumethatthere’snopackage.jsoninscopeofthisfile. Thefileextensionis`.ts`, sotheoutputfileextensionwillbe`.js`, whichNode.jswillinterpretasCommonJS, soTypeScriptwillemitthis`import`asa`require`call. So, themoduleresolverwillusethe`require`conditionasitresolves`"exports"`from`"pkg"`.
1094
1129
1095
-
When using a bundler, on the other hand, the bundler typically processes the raw `.ts` files directly and runs its module resolution process on the untransformed `import`statement. Inthis scenario, it doesn’t make a lot of sense to think about how TypeScript will emit the`import`, because TypeScript isn’t being used to emit anything at all. As far as the bundler is concerned, `import`s are `import`s and `require`s are `require`s, so the conditions used to resolve package.json`"exports"` and `"imports"` are determined by the syntax seen in the input `.ts`file. Likewise, the conditions TypeScript’s moduleresolution process uses in`--moduleResolution bundler` are _also_ determined by the input syntax in input TypeScript files—it’s just that `require` calls are not currently resolved at all:
1130
+
The same process happens in`--moduleResolution bundler`, but the rules for deciding whether to emit an`import` or `require` call forthisimportstatementwillbedifferent, since`--moduleResolution bundler`necessitatesusing [`--module esnext`](#es2015-es2020-es2022-esnext) or [`--module preserve`](#preserve). Inbothofthosemodes, ESM`import`declarationsalwaysemitasESM`import`declarations, soTypeScript’smoduleresolverwillreceivethatinformationandusethe`"import"`conditionasitresolves`"exports"`from`"pkg"`.
1096
1131
1097
-
```ts
1098
-
// Some library file:
1099
-
declare function require(module: string): any;
1132
+
This explanation may be somewhat unintuitive, since `--moduleResolution bundler` is usually used in combination with`--noEmit`—bundlers typically process raw `.ts` files and perform module resolution on untransformed `import`s or `require`s. However, for consistency, TypeScript still uses the hypothetical emit decided by `module` to inform module resolution and type checking. This makes [`--module preserve`](#preserve) the best choice whenever a runtime or bundler is operating on raw `.ts` files, since it implies no transformation. Under`--module preserve --moduleResolution bundler`, you can write imports and requires in the same file that will resolve with the `import` and `require` conditions, respectively:
1100
1133
1134
+
```ts
1101
1135
// index.ts
1102
-
import { foo } from "pkg"; // Resolved with "import" condition
1103
-
import pkg2 = require("pkg"); // Not allowed
1104
-
const pkg = require("pkg"); // Not an error, but not resolved to anything
1105
-
// ^? any
1136
+
import pkg1 from "pkg"; // Resolved with "import" condition
1137
+
import pkg2 = require("pkg"); // Resolved with "require" condition
1106
1138
```
1107
1139
1108
-
Since TypeScript doesn’t currently support resolving `require` calls in`--moduleResolution bundler`, everything it _does_ resolve uses the `"import"` condition.
1109
1140
1110
1141
#### Implied and enforced options
1111
1142
1112
-
-`--moduleResolution bundler` must be paired withthe `--module esnext`option.
1143
+
-`--moduleResolution bundler` must be paired with`--module esnext`or `--module preserve`.
<td><p><code>CommonJS</code> if <ahref="#target"><code>target</code></a> is <code>ES3</code> or <code>ES5</code>; <code>ES6</code>/<code>ES2015</code> otherwise.</p>
Copy file name to clipboardExpand all lines: packages/tsconfig-reference/copy/en/options/module.md
+19-1
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@ display: "Module"
3
3
oneline: "Specify what module code is generated."
4
4
---
5
5
6
-
Sets the module system for the program. See the [theory behind TypeScript’s `module` option](/docs/handbook/modules/theory.html#the-module-output-format) and [its reference page](/docs/handbook/modules/reference.html#the-module-compiler-option) for more information. You very likely want `"nodenext"` for modern Node.js projects.
6
+
Sets the module system for the program. See the [theory behind TypeScript’s `module` option](/docs/handbook/modules/theory.html#the-module-output-format) and [its reference page](/docs/handbook/modules/reference.html#the-module-compiler-option) for more information. You very likely want `"nodenext"` for modern Node.js projects and `preserve` or `esnext` for code that will be bundled.
7
7
8
8
Changing `module` affects [`moduleResolution`](#moduleResolution) which [also has a reference page](/docs/handbook/modules/reference.html#the-moduleresolution-compiler-option).
9
9
@@ -91,6 +91,24 @@ In addition to the base functionality of `ES2015`/`ES6`, `ES2020` adds support f
91
91
92
92
Available from 4.7+, the `node16` and `nodenext` modes integrate with Node's [native ECMAScript Module support](https://nodejs.org/api/esm.html). The emitted JavaScript uses either `CommonJS` or `ES2020` output depending on the file extension and the value of the `type` setting in the nearest `package.json`. Module resolution also works differently. You can learn more in the [handbook](/docs/handbook/esm-node.html) and [Modules Reference](/docs/handbook/modules/reference.html#node16-nodenext).
93
93
94
+
#### `preserve`
95
+
96
+
In `--module preserve` ([added](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html#support-for-require-calls-in---moduleresolution-bundler-and---module-preserve) in TypeScript 5.4), ECMAScript imports and exports written in input files are preserved in the output, and CommonJS-style `import x = require("...")` and `export = ...` statements are emitted as CommonJS `require` and `module.exports`. In other words, the format of each individual import or export statement is preserved, rather than being coerced into a single format for the whole compilation (or even a whole file).
While it’s rare to need to mix imports and require calls in the same file, this `module` mode best reflects the capabilities of most modern bundlers, as well as the Bun runtime.
109
+
110
+
> Why care about TypeScript’s `module` emit with a bundler or with Bun, where you’re likely also setting `noEmit`? TypeScript’s type checking and module resolution behavior are affected by the module format that it _would_ emit. Setting `module` gives TypeScript information about how your bundler or runtime will process imports and exports, which ensures that the types you see on imported values accurately reflect what will happen at runtime or after bundling.
Copy file name to clipboardExpand all lines: packages/tsconfig-reference/copy/en/options/moduleResolution.md
-3
Original file line number
Diff line number
Diff line change
@@ -8,9 +8,6 @@ Specify the module resolution strategy:
8
8
-`'node16'` or `'nodenext'` for modern versions of Node.js. Node.js v12 and later supports both ECMAScript imports and CommonJS `require`, which resolve using different algorithms. These `moduleResolution` values, when combined with the corresponding [`module`](#module) values, picks the right algorithm for each resolution based on whether Node.js will see an `import` or `require` in the output JavaScript code.
9
9
-`'node10'` (previously called `'node'`) for Node.js versions older than v10, which only support CommonJS `require`. You probably won't need to use `node10` in modern code.
10
10
-`'bundler'` for use with bundlers. Like `node16` and `nodenext`, this mode supports package.json `"imports"` and `"exports"`, but unlike the Node.js resolution modes, `bundler` never requires file extensions on relative paths in imports.
11
-
12
-
`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`).
13
-
14
11
-`'classic'` was used in TypeScript before the release of 1.6. `classic` should not be used.
15
12
16
13
There are reference pages explaining the [theory behind TypeScript’s module resolution](https://www.typescriptlang.org/docs/handbook/modules/theory.html#module-resolution) and the [details of each option](/docs/handbook/modules/reference.html#the-moduleresolution-compiler-option).
0 commit comments