or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfiguration.mdcore-service.mdesm.mdindex.mdregister.mdrepl.mdtranspilers.md

esm.mddocs/

0

# ESM Integration

1

2

Native ECMAScript module support with loader hooks for seamless TypeScript execution in ESM contexts and modern Node.js applications.

3

4

## Capabilities

5

6

### ESM Hooks Creation

7

8

Creates ESM loader hooks for TypeScript module resolution and compilation.

9

10

```typescript { .api }

11

/**

12

* Create ESM loader hooks from an existing ts-node service

13

* @param tsNodeService - Service instance for TypeScript compilation

14

* @returns ESM hooks object compatible with Node.js loader API

15

*/

16

function createEsmHooks(tsNodeService: Service): NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2;

17

18

/**

19

* Register ts-node and create ESM hooks in one step

20

* @param opts - Configuration options for registration

21

* @returns ESM hooks object

22

*/

23

function registerAndCreateEsmHooks(opts?: RegisterOptions): NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2;

24

```

25

26

**Usage Examples:**

27

28

```typescript

29

import { createEsmHooks, create } from "ts-node";

30

31

// Create service and hooks separately

32

const service = create({

33

esm: true,

34

compilerOptions: {

35

target: "es2020",

36

module: "esnext",

37

}

38

});

39

40

const hooks = createEsmHooks(service);

41

42

// Or create both in one step

43

const hooks = registerAndCreateEsmHooks({

44

esm: true,

45

compilerOptions: {

46

target: "es2020",

47

module: "esnext",

48

}

49

});

50

```

51

52

### Node.js Loader Hooks API

53

54

ESM loader hooks compatible with Node.js loader API versions 1 and 2.

55

56

```typescript { .api }

57

/**

58

* Node.js Loader Hooks API Version 1

59

*/

60

interface NodeLoaderHooksAPI1 {

61

/**

62

* Resolve module specifier to URL

63

* @param specifier - Module specifier to resolve

64

* @param context - Resolution context

65

* @param defaultResolve - Default Node.js resolve function

66

* @returns Promise resolving to module URL and format

67

*/

68

resolve(

69

specifier: string,

70

context: { parentURL?: string; conditions?: string[] },

71

defaultResolve: Function

72

): Promise<{ url: string; format?: NodeLoaderHooksFormat }>;

73

74

/**

75

* Get format of resolved module

76

* @param url - Module URL

77

* @param context - Format context

78

* @param defaultGetFormat - Default Node.js getFormat function

79

* @returns Promise resolving to module format

80

*/

81

getFormat(

82

url: string,

83

context: object,

84

defaultGetFormat: Function

85

): Promise<{ format: NodeLoaderHooksFormat }>;

86

87

/**

88

* Transform source code before execution

89

* @param source - Source code to transform

90

* @param context - Transform context including URL and format

91

* @param defaultTransformSource - Default transform function

92

* @returns Promise resolving to transformed source

93

*/

94

transformSource(

95

source: string | Buffer,

96

context: { url: string; format: NodeLoaderHooksFormat },

97

defaultTransformSource: Function

98

): Promise<{ source: string | Buffer }>;

99

}

100

101

/**

102

* Node.js Loader Hooks API Version 2 (Node.js 16.12.0+)

103

*/

104

interface NodeLoaderHooksAPI2 {

105

/**

106

* Resolve module specifier to URL

107

* @param specifier - Module specifier to resolve

108

* @param context - Resolution context

109

* @param next - Next resolver in chain

110

* @returns Promise resolving to module URL and format

111

*/

112

resolve(

113

specifier: string,

114

context: {

115

conditions: string[];

116

importAssertions?: object;

117

parentURL?: string;

118

},

119

next: Function

120

): Promise<{

121

format?: NodeLoaderHooksFormat;

122

shortCircuit?: boolean;

123

url: string;

124

}>;

125

126

/**

127

* Load and transform module source

128

* @param url - Module URL to load

129

* @param context - Load context

130

* @param next - Next loader in chain

131

* @returns Promise resolving to loaded module

132

*/

133

load(

134

url: string,

135

context: {

136

conditions: string[];

137

format?: NodeLoaderHooksFormat;

138

importAssertions?: object;

139

},

140

next: Function

141

): Promise<{

142

format: NodeLoaderHooksFormat;

143

shortCircuit?: boolean;

144

source?: string | Buffer;

145

}>;

146

}

147

148

/**

149

* Supported ESM module formats

150

*/

151

type NodeLoaderHooksFormat =

152

| 'builtin'

153

| 'commonjs'

154

| 'json'

155

| 'module'

156

| 'wasm';

157

```

158

159

### API Version Filtering

160

161

Utility for filtering hooks based on Node.js version compatibility.

162

163

```typescript { .api }

164

/**

165

* Filter ESM hooks by Node.js API version

166

* @param hooks - Complete hooks object

167

* @param apiVersion - Target API version (1 or 2)

168

* @returns Hooks object compatible with specified API version

169

*/

170

function filterHooksByAPIVersion(

171

hooks: NodeLoaderHooksAPI1 & NodeLoaderHooksAPI2,

172

apiVersion: 1 | 2

173

): NodeLoaderHooksAPI1 | NodeLoaderHooksAPI2;

174

```

175

176

**Usage Examples:**

177

178

```typescript

179

import { createEsmHooks, filterHooksByAPIVersion } from "ts-node";

180

181

const service = create({ esm: true });

182

const allHooks = createEsmHooks(service);

183

184

// Filter for Node.js API version 2 (recommended)

185

const v2Hooks = filterHooksByAPIVersion(allHooks, 2);

186

187

// Filter for Node.js API version 1 (legacy)

188

const v1Hooks = filterHooksByAPIVersion(allHooks, 1);

189

```

190

191

## ESM Entry Points

192

193

### Direct ESM Loader Usage

194

195

Pre-configured ESM loaders for command-line usage.

196

197

```typescript { .api }

198

// Available as /esm.mjs entry point

199

export const resolve: NodeLoaderHooksAPI2['resolve'];

200

export const load: NodeLoaderHooksAPI2['load'];

201

202

// Available as /esm/transpile-only.mjs entry point

203

// Same hooks with transpileOnly: true preset

204

export const resolve: NodeLoaderHooksAPI2['resolve'];

205

export const load: NodeLoaderHooksAPI2['load'];

206

```

207

208

**Usage Examples:**

209

210

```bash

211

# Use ts-node ESM loader

212

node --loader ts-node/esm script.ts

213

214

# Use transpile-only ESM loader for faster startup

215

node --loader ts-node/esm/transpile-only script.ts

216

217

# With experimental specifier resolution

218

node --loader ts-node/esm --experimental-specifier-resolution=node script.ts

219

```

220

221

### Child Process ESM Loader

222

223

Isolated ESM loader for child processes.

224

225

```typescript { .api }

226

// Available as /child-loader.mjs entry point

227

// ESM loader hooks that run in child processes for better isolation

228

export const resolve: NodeLoaderHooksAPI2['resolve'];

229

export const load: NodeLoaderHooksAPI2['load'];

230

```

231

232

**Usage Examples:**

233

234

```bash

235

# Use child process loader for isolation

236

node --loader ts-node/child-loader.mjs script.ts

237

```

238

239

## Configuration for ESM

240

241

### ESM-Specific Options

242

243

Configuration options specifically for ESM module handling.

244

245

```typescript { .api }

246

interface ESMCreateOptions extends CreateOptions {

247

/**

248

* Enable native ESM support

249

* @default false

250

*/

251

esm?: boolean;

252

253

/**

254

* Experimental specifier resolution mode

255

* @default undefined

256

*/

257

experimentalSpecifierResolution?: 'node' | 'explicit';

258

259

/**

260

* Allow .ts extensions in import specifiers

261

* @default false

262

*/

263

experimentalTsImportSpecifiers?: boolean;

264

265

/**

266

* Module type overrides for specific file patterns

267

*/

268

moduleTypes?: ModuleTypes;

269

}

270

```

271

272

**Usage Examples:**

273

274

```typescript

275

import { register } from "ts-node";

276

277

// Full ESM configuration

278

register({

279

esm: true,

280

experimentalSpecifierResolution: "node",

281

experimentalTsImportSpecifiers: true,

282

compilerOptions: {

283

target: "es2020",

284

module: "esnext",

285

moduleResolution: "node",

286

allowSyntheticDefaultImports: true,

287

esModuleInterop: true,

288

},

289

moduleTypes: {

290

"**/*.test.ts": "cjs", // Tests as CommonJS

291

"src/**/*.ts": "esm", // Source as ESM

292

}

293

});

294

```

295

296

## Advanced ESM Usage

297

298

### Mixed Module Systems

299

300

```typescript

301

import { register } from "ts-node";

302

303

// Configure for mixed CJS/ESM project

304

register({

305

esm: true,

306

compilerOptions: {

307

target: "es2020",

308

module: "esnext",

309

moduleResolution: "node",

310

},

311

moduleTypes: {

312

// Legacy components as CommonJS

313

"src/legacy/**/*.ts": "cjs",

314

// New components as ESM

315

"src/modern/**/*.ts": "esm",

316

// Tests follow package.json type

317

"**/*.test.ts": "package",

318

}

319

});

320

```

321

322

### Dynamic Import Support

323

324

```typescript

325

// TypeScript file with dynamic imports

326

export async function loadModule(moduleName: string) {

327

const module = await import(moduleName);

328

return module.default || module;

329

}

330

331

// Works with ts-node ESM loader

332

const result = await loadModule('./my-typescript-module.ts');

333

```

334

335

### ESM with Top-level Await

336

337

```typescript

338

import { register } from "ts-node";

339

340

// Configure for top-level await in ESM

341

register({

342

esm: true,

343

experimentalReplAwait: true,

344

compilerOptions: {

345

target: "es2022", // Required for top-level await

346

module: "esnext",

347

}

348

});

349

```

350

351

```typescript

352

// my-esm-script.ts - Can use top-level await

353

const response = await fetch('https://api.example.com/data');

354

const data = await response.json();

355

console.log(data);

356

```

357

358

### Package.json Configuration

359

360

```json

361

{

362

"type": "module",

363

"scripts": {

364

"dev": "node --loader ts-node/esm src/index.ts",

365

"dev:fast": "node --loader ts-node/esm/transpile-only src/index.ts"

366

},

367

"ts-node": {

368

"esm": true,

369

"experimentalSpecifierResolution": "node",

370

"compilerOptions": {

371

"target": "es2020",

372

"module": "esnext"

373

}

374

}

375

}

376

```