or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cjs-api.mdcli.mdesm-api.mdindex.md

esm-api.mddocs/

0

# ESM API

1

2

The ESM API (`tsx/esm/api`) provides programmatic access to tsx's TypeScript transformation capabilities within ES modules. It uses Node.js's module.register() system to provide hook-based loading of TypeScript files with advanced configuration options.

3

4

## Capabilities

5

6

### Module Registration

7

8

Register tsx transformation hooks for ES modules using Node.js module.register().

9

10

```typescript { .api }

11

/**

12

* Register tsx loader for ES modules

13

* @param options - Optional configuration

14

* @returns Unregister function

15

*/

16

function register(options?: RegisterOptions): Unregister;

17

18

/**

19

* Register tsx loader with required namespace

20

* @param options - Configuration with required namespace

21

* @returns Namespaced unregister function with additional methods

22

*/

23

function register(options: RequiredProperty<RegisterOptions, 'namespace'>): NamespacedUnregister;

24

25

interface RegisterOptions {

26

namespace?: string;

27

onImport?: (url: string) => void;

28

tsconfig?: TsconfigOptions;

29

}

30

31

interface InitializationOptions {

32

namespace?: string;

33

port?: MessagePort;

34

tsconfig?: TsconfigOptions;

35

}

36

37

type TsconfigOptions = false | string;

38

type Unregister = () => Promise<void>;

39

40

interface NamespacedUnregister extends Unregister {

41

import: ScopedImport;

42

unregister: Unregister;

43

}

44

45

type Register = {

46

(options: RequiredProperty<RegisterOptions, 'namespace'>): NamespacedUnregister;

47

(options?: RegisterOptions): Unregister;

48

};

49

```

50

51

**Usage Examples:**

52

53

```typescript

54

import { register } from "tsx/esm/api";

55

56

// Basic registration

57

const unregister = register();

58

59

// Now TypeScript files can be imported

60

const myModule = await import("./my-module.ts");

61

62

// Unregister when done

63

await unregister();

64

65

// Registration with import callback

66

const unregister2 = register({

67

onImport: (url) => console.log(`Loading: ${url}`)

68

});

69

70

// Namespaced registration for isolation

71

const api = register({ namespace: "my-app" });

72

const tsModule = await api.import("./module.ts", import.meta.url);

73

await api.unregister();

74

```

75

76

### TypeScript Import

77

78

Dynamic import function with TypeScript transformation support.

79

80

```typescript { .api }

81

/**

82

* Import TypeScript modules with transformation

83

* @param specifier - Module specifier or path

84

* @param options - Parent URL or options object

85

* @returns Promise resolving to module exports

86

*/

87

function tsImport(

88

specifier: string,

89

options: string | TsImportOptions

90

): Promise<any>;

91

92

interface TsImportOptions {

93

parentURL: string;

94

onImport?: (url: string) => void;

95

tsconfig?: TsconfigOptions;

96

}

97

```

98

99

**Usage Examples:**

100

101

```typescript

102

import { tsImport } from "tsx/esm/api";

103

104

// Import TypeScript files

105

const utils = await tsImport("./utils.ts", import.meta.url);

106

const config = await tsImport("./config.ts", import.meta.url);

107

108

// Import relative modules

109

const helper = await tsImport("../helpers/format.ts", import.meta.url);

110

111

// Import with options

112

const module = await tsImport("./module.ts", {

113

parentURL: import.meta.url,

114

onImport: (url) => console.log(`Importing: ${url}`),

115

tsconfig: "./custom-tsconfig.json"

116

});

117

```

118

119

### Scoped Import

120

121

When using namespace registration, access to scoped import functionality.

122

123

```typescript { .api }

124

type ScopedImport = (

125

specifier: string,

126

parent: string,

127

) => Promise<any>;

128

```

129

130

**Usage Examples:**

131

132

```typescript

133

import { register } from "tsx/esm/api";

134

135

// Create namespaced registration

136

const api = register({ namespace: "isolated-context" });

137

138

// Use scoped import - isolated from other tsx instances

139

const module1 = await api.import("./module1.ts", import.meta.url);

140

const module2 = await api.import("./module2.ts", import.meta.url);

141

142

// Cleanup

143

await api.unregister();

144

```

145

146

### TypeScript Configuration

147

148

Control tsx behavior through tsconfig options.

149

150

```typescript { .api }

151

// Disable tsconfig loading

152

const unregister = register({ tsconfig: false });

153

154

// Use custom tsconfig path

155

const unregister2 = register({

156

tsconfig: "./custom-tsconfig.json"

157

});

158

159

// Environment variable control

160

process.env.TSX_TSCONFIG_PATH = "./my-config.json";

161

const unregister3 = register();

162

```

163

164

**Usage Examples:**

165

166

```typescript

167

import { register } from "tsx/esm/api";

168

169

// Use specific tsconfig for registration

170

const unregister = register({

171

tsconfig: "./build-tsconfig.json",

172

onImport: (url) => {

173

if (url.includes('.test.')) {

174

console.log(`Loading test file: ${url}`);

175

}

176

}

177

});

178

179

// Import modules with custom configuration

180

const testModule = await import("./test.ts");

181

const srcModule = await import("./src/index.ts");

182

183

await unregister();

184

```

185

186

### Advanced Import Hooks

187

188

Monitor and control the import process with callback hooks.

189

190

```typescript { .api }

191

interface ImportHookOptions {

192

namespace?: string;

193

onImport?: (url: string) => void;

194

tsconfig?: TsconfigOptions;

195

}

196

```

197

198

**Usage Examples:**

199

200

```typescript

201

import { register } from "tsx/esm/api";

202

203

// Track all imports

204

const importedFiles = new Set<string>();

205

const unregister = register({

206

onImport: (url) => {

207

importedFiles.add(url);

208

console.log(`Imported: ${url}`);

209

}

210

});

211

212

// Use the imports

213

await import("./app.ts");

214

await import("./config.ts");

215

216

console.log(`Total imports: ${importedFiles.size}`);

217

await unregister();

218

```

219

220

### Integration Patterns

221

222

Common patterns for integrating tsx in ESM applications.

223

224

**Application Bootstrap:**

225

226

```typescript

227

import { register } from "tsx/esm/api";

228

229

// Register at application start

230

const unregister = register({

231

onImport: (url) => console.log(`Loading: ${url}`)

232

});

233

234

// Import TypeScript application modules

235

const { startServer } = await import("./server.ts");

236

const { loadConfig } = await import("./config.ts");

237

238

// Start application

239

const config = await loadConfig();

240

await startServer(config);

241

242

// Cleanup on shutdown

243

process.on('SIGTERM', async () => {

244

await unregister();

245

process.exit(0);

246

});

247

```

248

249

**Conditional TypeScript Loading:**

250

251

```typescript

252

import { register, tsImport } from "tsx/esm/api";

253

254

async function loadPlugin(pluginPath: string) {

255

if (pluginPath.endsWith('.ts')) {

256

// Use tsx for TypeScript files

257

return await tsImport(pluginPath, import.meta.url);

258

} else {

259

// Use standard import for JavaScript

260

return await import(pluginPath);

261

}

262

}

263

264

// Load mixed plugin types

265

const jsPlugin = await loadPlugin("./plugins/js-plugin.js");

266

const tsPlugin = await loadPlugin("./plugins/ts-plugin.ts");

267

```

268

269

**Multiple Isolated Contexts:**

270

271

```typescript

272

import { register } from "tsx/esm/api";

273

274

// Create separate contexts

275

const devContext = register({

276

namespace: "dev",

277

tsconfig: "./tsconfig.dev.json"

278

});

279

280

const prodContext = register({

281

namespace: "prod",

282

tsconfig: "./tsconfig.prod.json"

283

});

284

285

// Load modules in different contexts

286

const devModule = await devContext.import("./dev.ts", import.meta.url);

287

const prodModule = await prodContext.import("./prod.ts", import.meta.url);

288

289

// Cleanup

290

await devContext.unregister();

291

await prodContext.unregister();

292

```

293

294

## Types

295

296

### Core Types

297

298

```typescript { .api }

299

interface TsxRequest {

300

namespace: string;

301

parentURL: string;

302

specifier: string;

303

}

304

305

type Message = {

306

type: 'deactivated';

307

} | {

308

type: 'load';

309

url: string;

310

};

311

```

312

313

### Node.js Compatibility

314

315

tsx ESM API requires Node.js v18.19+ or v20.6+ for module.register() support.

316

317

```typescript

318

import { register } from "tsx/esm/api";

319

320

try {

321

const unregister = register();

322

// Registration successful

323

} catch (error) {

324

if (error.message.includes('does not support module.register')) {

325

console.error('Please upgrade Node.js to v18.19+ or v20.6+');

326

}

327

}

328

```

329

330

### Error Handling

331

332

tsx preserves TypeScript error information and source maps for debugging.

333

334

#### Node.js Version Compatibility

335

336

```typescript

337

import { register } from "tsx/esm/api";

338

339

try {

340

const unregister = register();

341

// Registration successful

342

} catch (error) {

343

if (error.message.includes('does not support module.register')) {

344

console.error('Please upgrade Node.js to v18.19+ or v20.6+');

345

process.exit(1);

346

}

347

throw error;

348

}

349

```

350

351

#### TypeScript Transformation Errors

352

353

```typescript

354

import { tsImport } from "tsx/esm/api";

355

356

try {

357

const module = await tsImport("./broken.ts", import.meta.url);

358

} catch (error) {

359

// Error includes TypeScript source locations with source maps

360

console.error('TypeScript compilation error:', error.stack);

361

362

// Handle specific error types

363

if (error.code === 'MODULE_NOT_FOUND') {

364

console.error('Module could not be resolved:', error.path);

365

}

366

}

367

```

368

369

#### Import Parameter Validation

370

371

```typescript

372

import { tsImport } from "tsx/esm/api";

373

374

try {

375

// This will throw an error

376

const module = await tsImport("./module.ts"); // Missing parentURL

377

} catch (error) {

378

console.error(error.message);

379

// "The current file path (import.meta.url) must be provided in the second argument of tsImport()"

380

}

381

382

try {

383

// This will also throw an error

384

const module = await tsImport("./module.ts", { /* missing parentURL */ });

385

} catch (error) {

386

console.error(error.message);

387

// "The current file path (import.meta.url) must be provided in the second argument of tsImport()"

388

}

389

```