Skip to content

Commit

Permalink
docs(node): module.register
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber committed May 1, 2024
1 parent 42b7ede commit 16e87a5
Showing 1 changed file with 65 additions and 39 deletions.
104 changes: 65 additions & 39 deletions docs/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,122 +2,148 @@
outline: deep
---

# Node.js
# Node.js integration

## Hooks
This guide details how to integrate `tsx` with Node.js, allowing you to enhance Node.js with TypeScript support without directly running `tsx`. Because Node.js offers Module and CommonJS contexts, you can opt into enhancing them selectively.

> Previously known as _Loaders_ ([renamed in v21](https://github.com/nodejs/loaders/issues/95))
This setup is useful for running binaries with TypeScript support, developing packages that load TypeScript files, or direct usage of `node`.

_tsx_ is primarily designed to be a standalone binary used in place of `node`. But sometimes, you'll want to use `node` directly. For example, when adding TypeScript & ESM support to npm-installed binaries that specify node in hashbang.

### Usage
::: info Only TypeScript & ESM support
When using the Node.js integrations, CLI features such as [_Watch mode_](/watch-mode) will not be available.
:::

## Module & CommonJS enhancement

### Command-line API

To use `tsx` as a Node.js loader, pass it in to the [`--import`](https://nodejs.org/api/module.html#enabling) flag. This will add TypeScript & ESM support for both Module and CommonJS contexts.

```sh
node --import tsx ./file.ts
```

Or via the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) environment variable:
Node.js also allows you to pass in command-line flags via the [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#node_optionsoptions) environment variable:
```sh
NODE_OPTIONS='--import tsx' node ./file.ts
```

::: warning
When using the hook, CLI features such as [_Watch mode_](/watch-mode) will not be available.
:::
This means you can also add tsx to binaries to add TypeScript support:
```sh
NODE_OPTIONS='--import tsx' npx eslint
```

### Node.js API

### ES Modules only
Add this at the top of your entry-file:
```js
import 'tsx'
```

If you only need to add TypeScript support in a Module context, you can use the ESM loader:
## Only Module enhancement

##### Node.js v20.6.0 and above
```sh
node --import tsx/esm ./file.ts
```
> For situations where you need TypeScript support only in a Module context (using `.mjs` files or `package.json` with `"type": "module"`).
##### Node.js v20.5.1 and below
### Command-line API

```sh
# Node.js v20.6.0 and above
node --import tsx/esm ./file.ts

# Node.js v20.5.1 and below
node --loader tsx/esm ./file.ts
```

---
### Hooks API
> Previously known as _Loaders_ ([renamed in Node.js v21](https://github.com/nodejs/loaders/issues/95))
# CommonJS
You can use the [Hooks API](https://nodejs.org/api/module.html#customization-hooks) to load TypeScript files with `tsx/esm`:

If you only need to add TypeScript & ESM support in a CommonJS context.
```js
import { register } from 'node:module'

register('tsx/esm', {
parentURL: import.meta.url,
data: true
})

## Command-line API
const loaded = await import('./hello.ts')
```

Pass tsx into the `--require` flag:
## Only CommonJS enhancement

> For situations where you need TypeScript and ESM support only in a CommonJS context (using `.cjs` files or `package.json` with `"type": "commonjs"`).
### Command-line API

Pass _tsx_ into the `--require` flag:

```sh
node --require tsx/cjs ./file.ts
```

## Node.js API
### Node.js API

### Globally patching `require`
#### Globally patching `require`

#### Enabling TSX Enhancement
##### Enabling TSX Enhancement

To enhance the global `require()` function with TypeScript support, prepend your script with the following line:
Add the following line at the top of your entry file:

```js
require('tsx/cjs')
```

#### Manual Registration & Unregistration
##### Manual Registration & Unregistration

To manually register and unregister the TypeScript enhancement on the global `require()`:
To manually register and unregister the TypeScript enhancement:

```js
const tsx = require('tsx/cjs/api')

// Register tsx enhancement for all global require() calls
// Register tsx enhancement
const unregister = tsx.register()

// Optionally, unregister the enhancement when needed
// Unregister when needed
unregister()
```

### Isolated `require()`
## `tsx.require()`

In situations where TypeScript support is needed only for loading a specific file (e.g. within third-party packages) without affecting the global environment, you can utilize tsx's custom `require` function.
For loading a TypeScript file without affecting the environment, `tsx` exports a custom `require(id, loadFromPath)` function.

Note the current file path must be passed in as the second argument so it knows how to resolve relative paths.
Note, the current file path must be passed in as the second argument so it knows how to resolve relative paths.

### CommonJS usage

#### CommonJS usage
```js
const tsx = require('tsx/cjs/api')

const loaded = tsx.require('./file.ts', __filename)
const filepath = tsx.require.resolve('./file.ts', __filename)
```

#### ESM usage
### ESM usage

```js
import { require } from 'tsx/cjs/api'

const loaded = require('./file.ts', import.meta.url)
const filepath = require.resolve('./file.ts', import.meta.url)
```
#### Module graph
### Module graph inspection
If you're interested in seeing what files were loaded, you can traverse the CommonJS module graph. This can be useful for watchers:
Because the CommonJS API tracks loaded modules in `require.cache`, you can use it to identify loaded files for dependency tracking. This can be useful when implementing a watcher.
```js
// To detect watch files, we can parse the CommonJS module graph
const resolvedPath = require.resolve('./file', import.meta.url)
const resolvedPath = tsx.require.resolve('./file', import.meta.url)

const collectDependencies = module => [
module.filename,
...module.children.flatMap(collectDependencies)
]

console.log(collectDependencies(require.cache[resolvedPath]))
console.log(collectDependencies(tsx.require.cache[resolvedPath]))
// ['/file.ts', '/foo.ts', '/bar.ts']
```

0 comments on commit 16e87a5

Please sign in to comment.