## File: README.md

<h1 align="center">


	
	


[](https://npm.im/tsx) [](https://npm.im/tsx)
</h1>








## Sponsors

---

## File: docs/dev-api/entry-point.md

# Entry-point

Import `tsx` at the top of your entry-file:
```js
import 'tsx'

// Now you can load TS files
await import('./file.ts')
```


Note, because of the order of static import evaluation in ESM, the enhancement only works on [dynamic imports after registration](https://nodejs.org/docs/latest-v22.x/api/module.html#:~:text=dynamic%20import()%20must%20be%20used%20for%20any%20code%20that%20should%20be%20run%20after%20the%20hooks%20are%20registered).

::: danger
Enhancing Node.js by loading _tsx_ from within your source code at run-time can be unexpected for collaborators who aren’t aware of it.

When possible, it's recommended to use a more visible method, such as passing it as a [CLI flag](/dev-api/node-cli).
:::


## Advanced usage

### CommonJS mode only

Require `tsx/cjs` at the top of your entry-file:

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

// Now you can load TS files
require('./file.ts')
```

### Module mode only

Import `tsx/esm` at the top of your entry-file:

```js
import 'tsx/esm'

// Now you can load TS files
await import('./file.ts')
```

---

## File: docs/dev-api/index.md

# Developer API
The Developer API allows you to enhance Node.js with _tsx_ without needing to use the `tsx` command.

Note that CLI features such as [_Watch mode_](/watch-mode.md) and the [REPL](/usage#repl) will not be available.

## Use-cases

### Directly running `node`

Sometimes, you may need to run `node` directly but still want to use _tsx_. Instead of using the `tsx` command, you can pass it to Node with [`node --import tsx`](/dev-api/node-cli) or you can do [`import 'tsx'`](/dev-api/entry-point) at the top of your script. This is helpful when you need more control over the Node.js environment, are integrating with tools that specifically call `node`, or simply prefer using the `node` command.

### 3rd party packages

Some third-party packages need to load TypeScript files, like configuration files, without affecting the entire runtime environment. The [`tsImport()` API](/dev-api/ts-import) allows these packages to load TypeScript files natively, without causing side effects to the environment.

## Understanding module types

Understanding the Node.js module types, CommonJS (CJS) and ES Module (ESM), can be helpful when using the Developer API.

ESM is the modern standard, indicated by the file extensions `.mjs` for JavaScript and `.mts` for TypeScript. CommonJS, the older format, uses the file extensions `.cjs` for JavaScript and `.cts` for TypeScript. When the file extension is ambiguous, such as `.js` or `.ts`, [`package.json#type`](https://nodejs.org/api/packages.html#type) is used to determine the module type. If `type` is set to `module`, the files are treated as ES Modules. If `type` is set to `commonjs` or not set at all, the files are treated as CommonJS modules.

Although both module types can coexist in the same environment, they have distinct scopes and behaviors. _tsx_ offers APIs to enhance both CommonJS and ES modules selectively. Being aware of these distinctions and knowing which module type you are using will allow you to make informed decisions when opting into these enhancements.

---

## File: docs/dev-api/node-cli.md

# Node.js CLI

To use the `node` command directly with _tsx_, pass it as a flag:

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

::: details (Deprecated) Node.js v20.5.1 and below

Older Node.js versions use a deprecated API `--loader` instead of `--import`.

```sh
node --loader tsx ./file.ts
```
:::

## Custom `tsconfig.json` path

To specify a custom path to `tsconfig.json`, use an environment variable:

```sh
TSX_TSCONFIG_PATH=./path/to/tsconfig.custom.json node --import tsx ./file.ts
```

## Binaries

If you don't have direct access to the `node` command, use the Node.js [`NODE_OPTIONS` environment variable](https://nodejs.org/api/cli.html#node_optionsoptions) to pass in the flag:

```sh
NODE_OPTIONS='--import tsx' npx some-binary
```

## Advanced usage

### CommonJS mode only

To use _tsx_ for CommonJS files only:

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

### Module mode only

To use _tsx_ for Module files only:

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

---

## File: docs/dev-api/register-cjs.md

# CommonJS Register API

The CommonJS Register API allows you to manually register the enhancement at runtime. But note, this only affects CommonJS modules (`.cjs`/`.cts`, and `.js`/`.ts` when `package.json#type` is unset or `commonjs`).

::: warning Caveats

- `import()` calls in the loaded files are not enhanced because they're handled by Node's ESM hook. Use with the [`ESM Register API`](/dev-api/register-esm).
- Because it compiles ESM syntax to run in CommonJS mode, top-level await is not supported
:::

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

// Register tsx enhancement
const unregister = tsx.register()

const loaded = require('./file.ts')

// Unregister when needed
unregister()
```

### Scoped registration

If you want to register without affecting the entire runtime environment, you can add a namespace.

When a namespace is provided, it will return a private `require()` method for you to load files with:
```js
const crypto = require('node:crypto')
const tsx = require('tsx/cjs/api')

const api = tsx.register({
    // Pass in a unique namespace
    namespace: crypto.randomUUID()
})

// Pass in the request and the current file path
const loaded = api.require('./file.ts', __filename)

api.unregister()
```

---

## File: docs/dev-api/register-esm.md

# ESM Register API

The ESM Register API allows you to manually register the enhancement at runtime. But note, this only affects ESM (`.mjs`/`.mts`, and `.js`/`.ts` when `package.json#type` is `module`).

## Usage
```js
import { register } from 'tsx/esm/api'

// Register tsx enhancement
const unregister = register()

await import('./file.ts')

// Unregister when needed
unregister()
```

### Scoped registration

If you want to register without affecting the entire runtime environment, you can add a namespace.

When a namespace is provided, it will return a private `import()` method for you to load files with:

```js
import crypto from 'node:crypto'
import { register } from 'tsx/esm/api'

const api = register({
    // Pass in a unique namespace
    namespace: crypto.randomUUID()
})

// Pass in the request and the current file path
// Since this is namespaced, it will not cache hit from prior imports
const loaded = await api.import('./file.ts', import.meta.url)

// This is using the same namespace as above, so it will yield a cache hit
const loaded2 = await api.import('./file.ts', import.meta.url)

api.unregister()
```

### Tracking loaded files

Detect files that get loaded with the `onImport` hook. This can be useful when you want to track dependencies when setting up a watcher.

```ts
register({
    onImport: (file: string) => {
        console.log(file) // 'file:///foo.ts'
    }
})
```

---

## File: docs/dev-api/ts-import.md

# `tsImport()`

Native dynamic `import()` function to import TypeScript files (supports [top-level await](https://v8.dev/features/top-level-await)).

Use this function for importing TypeScript files without adding TypeScript support to the entire runtime.

The current file path must be passed in as the second argument to resolve the import context.

Since this is designed for one-time use, it does not cache loaded modules.

## Usage

### ESM

```js
import { tsImport } from 'tsx/esm/api'

const loaded = await tsImport('./file.ts', import.meta.url)

// If tsImport is used to load file.ts again,
// it does not yield a cache-hit and re-loads it
const loadedAgain = await tsImport('./file.ts', import.meta.url)
```

If you'd like to leverage module caching, see the [ESM scoped registration](/dev-api/register-esm.md) section.

### CommonJS

```js
const { tsImport } = require('tsx/esm/api')

const loaded = await tsImport('./file.ts', __filename)
```

## `tsconfig.json`

### Custom `tsconfig.json` path
```ts
tsImport('./file.ts', {
    parentURL: import.meta.url,
    tsconfig: './custom-tsconfig.json'
})
```

### Disable `tsconfig.json` lookup
```ts
tsImport('./file.ts', {
    parentURL: import.meta.url,
    tsconfig: false
})
```

## Tracking loaded files

Detect files that get loaded with the `onImport` hook:

```ts
tsImport('./file.ts', {
    parentURL: import.meta.url,
    onImport: (file: string) => {
        console.log(file)
        // file:///foo.ts
    }
})
```

---

## File: docs/dev-api/tsx-require.md

# `tsx.require()`

Native `require()` function enhanced with TypeScript & ESM support.

Use this function for importing TypeScript files in CommonJS mode without adding TypeScript support to the entire runtime.

Note, the current file path must be passed in as the second argument to resolve the import context.

::: warning Caveats

- `import()` calls in the loaded files are not enhanced. Use [`tsImport()`](/dev-api/ts-import) instead.
- Because it compiles ESM syntax to run in CommonJS mode, top-level await is not supported
:::

## Usage

### CommonJS

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

const tsLoaded = tsx.require('./file.ts', __filename)
const tsFilepath = tsx.require.resolve('./file.ts', __filename)
```

### ESM

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

const tsLoaded = require('./file.ts', import.meta.url)
const tsFilepath = require.resolve('./file.ts', import.meta.url)
```

## Tracking loaded files

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
const resolvedPath = tsx.require.resolve('./file', import.meta.url)

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

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

---

## File: docs/compilation.md

# Compilation

Compiling your TypeScript files to JavaScript is not handled by _tsx_, but it's a necessary step in most setups.

::: info Should I publish TypeScript files?

No. While _tsx_ is capable of running TypeScript files in dependencies if need be (e.g. monorepos), it's highly discouraged to publish uncompiled TypeScript. Source files require a specific compilation configuration in `tsconfig.json` which may not be read, and [TypeScript performance will degrade](https://x.com/atcb/status/1705675335814271157).
:::

## Compiling an npm package

npm packages are distinguished from applications by defining package entry-points in `package.json`.

[pkgroll](https://github.com/privatenumber/pkgroll) is the recommended bundler for projects using _tsx_. It's developed by the same author and used to compile _tsx_.

Given your source files are in the `src` directory, it automatically infers how to build your package based on the entry points defined in `package.json` by outputting them to the `dist` directory.

### Setup

::: details Basic setup

Set your entry-point in [`exports`](https://nodejs.org/api/packages.html#exports):

```json5
// package.json
{
    "exports": "./dist/index.mjs"
}
```
:::

::: details Dual package (CJS & ESM)

Set your CommonJS & Module entry-points in [`exports`](https://nodejs.org/api/packages.html#exports):

```json5
// package.json
{
    "main": "./dist/index.cjs",
    "module": "./dist/index.mjs",
    "types": "./dist/index.d.cts",

    "exports": {
        "require": {
            "types": "./dist/index.d.cts",
            "default": "./dist/index.cjs"
        },
        "import": {
            "types": "./dist/index.d.mts",
            "default": "./dist/index.mjs"
        }
    }
}
```
:::

::: details Command-line package

Set your CLI entry-point in [`bin`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#bin):

```json5
// package.json
{
    "bin": "./dist/cli.mjs"
}
```
:::

### Build
In your directory, simply run `pkgroll`:

::: code-group
```sh [npm]
$ npx pkgroll
```

```sh [pnpm]
$ pnpm pkgroll
```

```sh [yarn]
$ yarn pkgroll
```
:::

Optionally, add a `build` script for convenience:
```json
// package.json
{
    // Optional: build script
    "scripts": {// [!code ++]
        "build": "pkgroll"// [!code ++]
    }// [!code ++]
}
```

---

## File: docs/contact.md

# Contact

<script setup lang="ts">
import ContactForm from './.vitepress/theme/components/ContactForm.vue';
</script>

<ContactForm />