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
Copy file name to clipboardExpand all lines: README.md
+13-11
Original file line number
Diff line number
Diff line change
@@ -6,13 +6,17 @@
6
6
7
7
Node.js tool for building a TypeScript dual package.
8
8
9
-
Inspired by https://github.com/microsoft/TypeScript/issues/49462.
9
+
## Features
10
+
11
+
* Bidirectional ESM <--> CJS dual builds inferred from the package.json `type`.
12
+
* Correctly preserves module systems for `.mts` and `.cts` file extensions.
13
+
* Only one package.json and tsconfig.json needed.
10
14
11
15
## Requirements
12
16
13
17
* Node >= 16.19.0.
14
-
*TypeScript, `npm i typescript`.
15
-
* A `tsconfig.json` with `outDir` defined.
18
+
*A package.json with `type` defined.
19
+
* A tsconfig.json with `outDir` defined.
16
20
17
21
## Example
18
22
@@ -28,9 +32,7 @@ Then, given a `package.json` that defines `"type": "module"` and a `tsconfig.js
28
32
{
29
33
"compilerOptions": {
30
34
"module": "NodeNext",
31
-
"moduleResolution": "NodeNext",
32
35
"declaration": true,
33
-
"esModuleInterop": true,
34
36
"outDir": "dist",
35
37
"strict": true,
36
38
},
@@ -54,7 +56,7 @@ user@comp ~ $ npm run build
54
56
55
57
If everything worked, you should have an ESM build inside of `dist` and a CJS build inside of `dist/cjs`. Now you can update your [`exports`](https://nodejs.org/api/packages.html#exports) to match the build output.
56
58
57
-
It should work similarly for a CJS-first project. Except, your `tsconfig.json` may define `--module` and `--moduleResolution` differently, your package.json file would use `"type": "commonjs"`, and you'd want to pass `--target-extension .mjs`.
59
+
It should work similarly for a CJS-first project. Except, your package.json file would use `"type": "commonjs"`.
58
60
59
61
See the available [options](#options).
60
62
@@ -64,25 +66,25 @@ See the available [options](#options).
64
66
The available options are limited, because you should define most of them inside your project's `tsconfig.json` file.
65
67
66
68
*`--project, -p` The path to the project's configuration file. Defaults to `tsconfig.json`.
67
-
*`--target-extension, -x` The desired target extension which determines the type of dual build. Defaults to `.cjs`.
69
+
*`--pkg-dir, -k` The directory to start looking for a package.json file. Defaults to the cwd.
68
70
69
-
You can run `duel --help` to get more info. Below is the output of that:
71
+
You can run `duel --help` to get the same info. Below is the output of that:
70
72
71
73
```console
72
74
Usage: duel [options]
73
75
74
76
Options:
75
77
--project, -p Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.
76
-
--target-extension, -x Sets the file extension for the dual build. [.cjs,.mjs]
78
+
--pkg-dir, -k The directory to start looking for a package.json file. Defaults to cwd.
77
79
--help, -h Print this message.
78
80
```
79
81
80
82
## Gotchas
81
83
82
84
These are definitely edge cases, and would only really come up if your project mixes file extensions. For example, if you have `.ts` files combined with `.mts`, and/or `.cts`. For most projects, things should just work as expected.
83
85
84
-
As far as I can tell, `duel` is one (if not the only) way to get a correct dual package build using `tsc` while only using a **one package.json** file and **one tsconfig.json** file _and also_ preserving module system by file extension. The Microsoft backed TypeScript team [keep](https://github.com/microsoft/TypeScript/issues/54593)[talking](https://github.com/microsoft/TypeScript/pull/54546) about dual build support, but their philosophy is mainly one of self perseverance, rather than collaboration.
86
+
As far as I can tell, `duel` is one (if not the only) way to get a correct dual package build using only `tsc` while only using **one package.json** file and **one tsconfig.json** file _and also_ preserving module system by file extension. The Microsoft backed TypeScript team [keep](https://github.com/microsoft/TypeScript/issues/54593)[talking](https://github.com/microsoft/TypeScript/pull/54546) about dual build support, but their philosophy is mainly one of self perseverance, rather than collaboration. For instance, they continue to refuse to rewrite specifiers.
85
87
86
-
* Unfortunately, TypeScript doesn't really build [dual packages](https://nodejs.org/api/packages.html#dual-commonjses-module-packages) very well in regards to preserving module system by file extension. For instance, there doesn't appear to be a way to convert an arbitrary `.ts` file into another module system, _while also preserving the module system of `.mts` and `.cts` files_. In my opinion, the `tsc` compiler is fundamentally broken in this regard, and at best is enforcing usage patterns it shouldn't. If you want to see one of my extended rants on this, check out this [comment](https://github.com/microsoft/TypeScript/pull/50985#issuecomment-1656991606). This is only mentioned for transparency, `duel` will correct for this and produce files with the module system you would expect based on the files extension, so that it works with [how Node.js determines module systems](https://nodejs.org/api/packages.html#determining-module-system).
88
+
* Unfortunately, TypeScript doesn't really build [dual packages](https://nodejs.org/api/packages.html#dual-commonjses-module-packages) very well in regards to preserving module system by file extension. For instance, there doesn't appear to be a way to convert an arbitrary `.ts` file into another module system, _while also preserving the module system of `.mts` and `.cts` files_ without using **multiple** package.json files. In my opinion, the `tsc` compiler is fundamentally broken in this regard, and at best is enforcing usage patterns it shouldn't. This is only mentioned for transparency, `duel` will correct for this and produce files with the module system you would expect based on the files extension, so that it works with [how Node.js determines module systems](https://nodejs.org/api/packages.html#determining-module-system).
87
89
88
90
* If doing an `import type` across module systems, i.e. from `.mts` into `.cts`, or vice versa, you might encounter the compilation error ``error TS1452: 'resolution-mode' assertions are only supported when `moduleResolution` is `node16` or `nodenext`.``. This is a [known issue](https://github.com/microsoft/TypeScript/issues/49055) and TypeScript currently suggests installing the nightly build, i.e. `npm i typescript@next`.
0 commit comments