diff --git a/README.md b/README.md
index 90fb9f54a..5eaea70ae 100644
--- a/README.md
+++ b/README.md
@@ -153,11 +153,14 @@ ts-node-transpile-only script.ts
# Equivalent to ts-node --cwdMode
ts-node-cwd script.ts
+
+# Equivalent to ts-node --esm
+ts-node-esm script.ts
```
## Shebang
-```typescript
+```typescript twoslash
#!/usr/bin/env ts-node
console.log("Hello, world!")
@@ -165,7 +168,7 @@ console.log("Hello, world!")
Passing options via shebang requires the [`env -S` flag](https://manpages.debian.org/bullseye/coreutils/env.1.en.html#S), which is available on recent versions of `env`. ([compatibility](https://github.com/TypeStrong/ts-node/pull/1448#issuecomment-913895766))
-```typescript
+```typescript twoslash
#!/usr/bin/env -S ts-node --files
// This shebang works on Mac and Linux with newer versions of env
// Technically, Mac allows omitting `-S`, but Linux requires it
@@ -173,7 +176,7 @@ Passing options via shebang requires the [`env -S` flag](https://manpages.debian
To write scripts with maximum portability, [specify all options in your `tsconfig.json`](#via-tsconfigjson-recommended) and omit them from the shebang.
-```typescript
+```typescript twoslash
#!/usr/bin/env ts-node
// This shebang works everywhere
```
@@ -302,6 +305,7 @@ All command-line flags support both `--camelCase` and `--hyphen-case`.
* `-e, --eval` Evaluate code
* `-p, --print` Print result of `--eval`
* `-i, --interactive` Opens the REPL even if stdin does not appear to be a terminal
+* `--esm` Bootstrap with the ESM loader, enabling full ESM support
## TSConfig
@@ -361,7 +365,7 @@ Here is a brief comparison of the two.
| Write native `import` syntax | Write native `import` syntax |
| Transforms `import` into `require()` | Does not transform `import` |
| Node executes scripts using the classic [CommonJS loader](https://nodejs.org/dist/latest-v16.x/docs/api/modules.html) | Node executes scripts using the new [ESM loader](https://nodejs.org/dist/latest-v16.x/docs/api/esm.html) |
-| Use any of:
ts-node CLI
`node -r ts-node/register`
`NODE_OPTIONS="ts-node/register" node`
`require('ts-node').register({/* options */})` | Must use the ESM loader via:
`node --loader ts-node/esm`
`NODE_OPTIONS="--loader ts-node/esm" node` |
+| Use any of:
`ts-node`
`node -r ts-node/register`
`NODE_OPTIONS="ts-node/register" node`
`require('ts-node').register({/* options */})` | Use any of:
`ts-node --esm`
`ts-node-esm`
Set `"esm": true` in `tsconfig.json`
`node --loader ts-node/esm`
`NODE_OPTIONS="--loader ts-node/esm" node` |
## CommonJS
@@ -415,10 +419,36 @@ You must set [`"type": "module"`](https://nodejs.org/api/packages.html#packages_
{
"compilerOptions": {
"module": "ESNext" // or ES2015, ES2020
+ },
+ "ts-node": {
+ // Tell ts-node CLI to install the --loader automatically, explained below
+ "esm": true
}
}
```
+You must also ensure node is passed `--loader`. The ts-node CLI will do this automatically with our `esm` option.
+
+> Note: `--esm` must spawn a child process to pass it `--loader`. This may change if node adds the ability to install loader hooks
+> into the current process.
+
+```shell
+# pass the flag
+ts-node --esm
+# Use the convenience binary
+ts-node-esm
+# or add `"esm": true` to your tsconfig.json to make it automatic
+ts-node
+```
+
+If you are not using our CLI, pass the loader flag to node.
+
+```shell
+node --loader ts-node/esm ./index.ts
+# Or via environment variable
+NODE_OPTIONS="--loader ts-node/esm" node ./index.ts
+```
+
# Troubleshooting
## Understanding configuration
@@ -490,7 +520,7 @@ the [tsconfig `"target"` option](https://www.typescriptlang.org/tsconfig#target)
For example, `node` 12 does not understand the `?.` optional chaining operator. If you use `"target": "esnext"`, then the following TypeScript syntax:
-```typescript
+```typescript twoslash
const bar: string | undefined = foo?.bar;
```
@@ -606,7 +636,7 @@ Example project structure:
Example module declaration file:
-```typescript
+```typescript twoslash
declare module '' {
// module definitions go here
}
@@ -614,7 +644,7 @@ declare module '' {
For module definitions, you can use [`paths`](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping):
-```jsonc
+```jsonc title="tsconfig.json"
{
"compilerOptions": {
"baseUrl": ".",
@@ -627,9 +657,11 @@ For module definitions, you can use [`paths`](https://www.typescriptlang.org/doc
An alternative approach for definitions of third-party libraries are [triple-slash directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html). This may be helpful if you prefer not to change your TypeScript `compilerOptions` or structure your custom type definitions when using `typeRoots`. Below is an example of the triple-slash directive as a relative path within your project:
-```typescript
-///
-import UntypedJsLib from "untyped_js_lib"
+```typescript twoslash
+///
+import {Greeter} from "untyped_js_lib"
+const g = new Greeter();
+g.sayHello();
```
**Tip:** If you *must* use `files`, `include`, or `exclude`, enable `--files` flags or set `TS_NODE_FILES=true`.
@@ -737,7 +769,7 @@ CommonJS or ESM. Node supports similar overriding via `.cjs` and `.mjs` file ex
The following example tells ts-node to execute a webpack config as CommonJS:
-```jsonc title=tsconfig.json
+```jsonc title="tsconfig.json"
{
"ts-node": {
"transpileOnly": true,
@@ -783,7 +815,7 @@ Assuming you are configuring AVA via your `package.json`, add one of the followi
Use this configuration if your `package.json` does not have `"type": "module"`.
-```jsonc title"package.json"
+```jsonc title="package.json"
{
"ava": {
"extensions": [
@@ -800,7 +832,7 @@ Use this configuration if your `package.json` does not have `"type": "module"`.
This configuration is necessary if your `package.json` has `"type": "module"`.
-```jsonc title"package.json"
+```jsonc title="package.json"
{
"ava": {
"extensions": {