Skip to content

Commit

Permalink
docs: update readme. (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
knightedcodemonkey authored Jul 29, 2023
1 parent dbf5227 commit b16bb2e
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 17 deletions.
60 changes: 50 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,76 @@ Node.js tool for creating a TypeScript dual package.

Early stages of development. Inspired by https://github.com/microsoft/TypeScript/issues/49462.

## Requirements

* Node >= 16.19.0.
* TypeScript, `npm i typescript`.

## Example

Consider a project that is ESM-first, i.e. `"type": "module"` in package.json, that also wants to create a separate CJS build. It might have a tsconfig.json file that looks like the following.
First, install the package to create the `duel` executable inside your `node_modules/.bin` directory.

```console
user@comp ~ $ npm i @knighted/duel
```

**tsconfig.json**
Then, given a `package.json` that defines `"type": "module"` and a `tsconfig.json` file that looks like the following:

```json
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"esModuleInterop": true,
"outDir": "dist",
"strict": true,
"outDir": "dist"
},
"include": ["src/*.ts"]
"include": ["src"]
}
```

You can create a build for the project defined by the above configuration, **and also a separate dual CJS build** by defining the following npm run script in your `package.json`:

```json
"scripts": {
"build": "duel"
}
```

Running the following will use the tsconfig.json defined above and create a separate CJS build in `dist/cjs`.
And then running it:

```console
user@comp ~ $ duel -p tsconfig.json -x .cjs
user@comp ~ $ npm run build
```

Now you can update your `exports` in package.json to match the build output.
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` in package.json to match the build output.

It should work similarly for a CJS first project. Except, your tsconfig.json would be slightly different and you'd want to pass `-x .mjs`.
It should work similarly for a CJS first project. Except, your `tsconfig.json` would define `--module` and `--moduleResolution` differently, and you'd want to pass `-x .mjs`.

See the available [options](#options).


## Options

The available options are limited, because you should define most of them inside your project's `tsconfig.json` file.

* `--project, -p` The path to the project's configuration file. Defaults to `tsconfig.json`.
* `--target-extension, -x` The desired target extension which determines the type of dual build. Defaults to `.cjs`.

You can run `duel --help` to get more info. Below is the output of that:

```console
Usage: duel [options]

Options:
--project, -p Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.
--target-extension, -x Sets the file extension for the dual build. [.cjs,.mjs]
--help, -h Print this message.
```

## Gotchas

Unfortunately, TypeScript doesn't really understand dual packages very well. For instance, it will **always** create CJS exports when `--module commonjs` is used, even on files with an `.mts` extension. One reference issue is https://github.com/microsoft/TypeScript/issues/54573.
* Unfortunately, TypeScript doesn't really understand dual packages very well. For instance, it will **always** create CJS exports when `--module commonjs` is used, even on files with an `.mts` extension. One reference issue is https://github.com/microsoft/TypeScript/issues/54573. If you use `.mts` extensions to enforce an ESM module system, this might break in the corresponding dual CJS build.
* If targeting a dual CJS build, and you are using [top level `await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await), you will most likely encounter the compilation error `error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher.` during the CJS build. This is because `duel` creates a temporary `tsconfig.json` from your original and overwrites the `--module` and `--moduleResolution` based on the provided `--target-ext`.
* 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`.
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@knighted/duel",
"version": "1.0.0-alpha.1",
"version": "1.0.0-alpha.2",
"description": "TypeScript dual packages.",
"type": "module",
"main": "dist",
Expand Down Expand Up @@ -56,8 +56,7 @@
},
"dependencies": {
"@knighted/specifier": "^1.0.0-alpha.5",
"glob": "^10.3.3",
"magic-string": "^0.30.1"
"glob": "^10.3.3"
},
"prettier": {
"arrowParens": "avoid",
Expand Down

0 comments on commit b16bb2e

Please sign in to comment.