Skip to content

Commit

Permalink
feat: register() & tsImport() via esm/api (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber authored May 3, 2024
1 parent 8eb1674 commit 4f515ab
Show file tree
Hide file tree
Showing 17 changed files with 600 additions and 354 deletions.
98 changes: 73 additions & 25 deletions docs/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,27 @@ node --import tsx/esm ./file.ts
node --loader tsx/esm ./file.ts
```

### Hooks API
> Previously known as _Loaders_ ([renamed in Node.js v21](https://github.com/nodejs/loaders/issues/95))
### Registration & Unregistration
```js
import { register } from 'tsx/esm/api'

You can use the [Hooks API](https://nodejs.org/api/module.html#customization-hooks) to load TypeScript files with `tsx/esm`:
// register tsx enhancement
const unregister = register()

```js
import { register } from 'node:module'
// Unregister when needed
unregister()
```

register('tsx/esm', {
parentURL: import.meta.url,
data: true
})
#### Tracking loaded files
Detect files that get loaded with the `onImport` hook:

const loaded = await import('./hello.ts')
```ts
register({
onImport: (file: string) => {
console.log(file)
// file:///foo.ts
}
})
```

## Only CommonJS enhancement
Expand All @@ -82,21 +89,15 @@ Pass _tsx_ into the `--require` flag:
node --require tsx/cjs ./file.ts
```

### Node.js API

#### Globally patching `require`

##### Enabling TSX Enhancement

Add the following line at the top of your entry file:
This is the equivalent of adding the following at the top of your entry file, which you can also do:

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

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

To manually register and unregister the TypeScript enhancement:
To manually register and unregister the tsx enhancement:

```js
const tsx = require('tsx/cjs/api')
Expand All @@ -108,13 +109,60 @@ const unregister = tsx.register()
unregister()
```

## `tsx.require()`
## Enhanced `import()` & `require()`

tsx exports enhanced `import()` or `require()` functions, allowing you to load TypeScript/ESM files without affecting the runtime environment.

### `tsImport()`

The `import()` function enhanced to support TypeScript. Because it's the native `import()`, it supports [top-level await](https://v8.dev/features/top-level-await).

::: warning Caveat
`require()` calls in the loaded files are not enhanced.
:::

#### ESM usage

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

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

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

Check warning on line 131 in docs/node.md

View workflow job for this annotation

GitHub Actions / Release

'loaded' is assigned a value but never used
```
#### CommonJS usage
```js
const { tsImport } = require('tsx/esm/api')

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

Check warning on line 139 in docs/node.md

View workflow job for this annotation

GitHub Actions / Release

'loaded' is assigned a value but never used
```
#### Tracking loaded files
Detect files that get loaded with the `onImport` hook:
For loading a TypeScript file without affecting the environment, `tsx` exports a custom `require(id, loadFromPath)` function.
```ts
tsImport('./file.ts', {
parentURL: import.meta.url,
onImport: (file: string) => {
console.log(file)
// file:///foo.ts
}
})
```
### `tsx.require()`
The `require()` function enhanced to support TypeScript and ESM.
::: warning Caveat
`import()` & asynchronous `require()` calls in the loaded files are not enhanced.
:::
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
Note, the current file path must be passed in as the second argument to resolve the import context.
```js
const tsx = require('tsx/cjs/api')
Expand All @@ -123,7 +171,7 @@ const loaded = tsx.require('./file.ts', __filename)
const filepath = tsx.require.resolve('./file.ts', __filename)

Check warning on line 171 in docs/node.md

View workflow job for this annotation

GitHub Actions / Release

'filepath' is assigned a value but never used
```
### ESM usage
#### ESM usage
```js
import { require } from 'tsx/cjs/api'
Expand All @@ -132,7 +180,7 @@ const loaded = require('./file.ts', import.meta.url)
const filepath = require.resolve('./file.ts', import.meta.url)

Check warning on line 180 in docs/node.md

View workflow job for this annotation

GitHub Actions / Release

'filepath' is assigned a value but never used
```
### Module graph inspection
#### 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.
Expand Down
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,24 @@
"default": "./dist/cjs/api/index.cjs"
},
"./esm": "./dist/esm/index.mjs",
"./esm/api": {
"import": {
"types": "./dist/esm/api/index.d.mts",
"default": "./dist/esm/api/index.mjs"
},
"require": {
"types": "./dist/esm/api/index.d.cts",
"default": "./dist/esm/api/index.cjs"
}
},
"./cli": "./dist/cli.mjs",
"./suppress-warnings": "./dist/suppress-warnings.cjs",
"./preflight": "./dist/preflight.cjs",
"./repl": "./dist/repl.mjs"
},
"scripts": {
"prepare": "pnpm simple-git-hooks",
"build": "pkgroll --target=node12.19 --minify",
"build": "pkgroll --minify",
"lint": "lintroll --node --cache .",
"type-check": "tsc --noEmit",
"test": "pnpm build && node ./dist/cli.mjs tests/index.ts",
Expand Down Expand Up @@ -80,7 +90,7 @@
"get-node": "^15.0.0",
"kolorist": "^1.8.0",
"lint-staged": "^15.2.2",
"lintroll": "^1.5.0",
"lintroll": "^1.5.1",
"magic-string": "^0.30.10",
"manten": "^1.3.0",
"memfs": "^4.9.1",
Expand Down
Loading

0 comments on commit 4f515ab

Please sign in to comment.