Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e10a1ea

Browse files
feat: infer dual build type from package.json microsoft/TypeScript#54593
BREAKING CHANGE: deprecates --target-extension
1 parent 919e176 commit e10a1ea

File tree

10 files changed

+146
-156
lines changed

10 files changed

+146
-156
lines changed

README.md

+13-11
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66

77
Node.js tool for building a TypeScript dual package.
88

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.
1014

1115
## Requirements
1216

1317
* 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.
1620

1721
## Example
1822

@@ -28,9 +32,7 @@ Then, given a `package.json` that defines `"type": "module"` and a `tsconfig.js
2832
{
2933
"compilerOptions": {
3034
"module": "NodeNext",
31-
"moduleResolution": "NodeNext",
3235
"declaration": true,
33-
"esModuleInterop": true,
3436
"outDir": "dist",
3537
"strict": true,
3638
},
@@ -54,7 +56,7 @@ user@comp ~ $ npm run build
5456

5557
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.
5658

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"`.
5860

5961
See the available [options](#options).
6062

@@ -64,25 +66,25 @@ See the available [options](#options).
6466
The available options are limited, because you should define most of them inside your project's `tsconfig.json` file.
6567

6668
* `--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.
6870

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:
7072

7173
```console
7274
Usage: duel [options]
7375

7476
Options:
7577
--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.
7779
--help, -h Print this message.
7880
```
7981

8082
## Gotchas
8183

8284
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.
8385

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.
8587

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).
8789

8890
* 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`.

package-lock.json

+10-38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@knighted/duel",
3-
"version": "1.0.0-rc.0",
3+
"version": "1.0.0-rc.1",
44
"description": "TypeScript dual packages.",
55
"type": "module",
66
"main": "dist",
@@ -56,7 +56,8 @@
5656
},
5757
"dependencies": {
5858
"@knighted/specifier": "^1.0.0-alpha.5",
59-
"glob": "^10.3.3"
59+
"glob": "^10.3.3",
60+
"read-pkg-up": "^10.0.0"
6061
},
6162
"prettier": {
6263
"arrowParens": "avoid",

0 commit comments

Comments
 (0)