or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-lifecycle.mdenvironment-building.mdevents.mdindex.md
tile.json

events.mddocs/

0

# Event System

1

2

EventEmitter-based system providing lifecycle hooks for module preloading, loader registration, and process respawning with detailed status information and error handling.

3

4

## Capabilities

5

6

### Preload Events

7

8

Events emitted during module preloading operations, providing hooks for logging, error handling, and module registration customization.

9

10

```javascript { .api }

11

/**

12

* Event emitted before attempting to preload a module

13

* @param moduleName - Name of the module being preloaded

14

*/

15

on('preload:before', (moduleName: string) => void): Liftoff;

16

17

/**

18

* Event emitted when a module is successfully preloaded

19

* @param moduleName - Name of the successfully loaded module

20

* @param module - The actual loaded module object

21

*/

22

on('preload:success', (moduleName: string, module: any) => void): Liftoff;

23

24

/**

25

* Event emitted when module preloading fails

26

* @param moduleName - Name of the module that failed to load

27

* @param error - Error object containing failure details

28

*/

29

on('preload:failure', (moduleName: string, error: Error) => void): Liftoff;

30

```

31

32

**Usage Examples:**

33

34

```javascript

35

const Liftoff = require('liftoff');

36

37

const MyApp = new Liftoff({

38

name: 'myapp',

39

extensions: {

40

'.coffee': 'coffee-script/register',

41

'.ts': 'ts-node/register'

42

}

43

});

44

45

// Set up preload event handlers

46

MyApp.on('preload:before', function(moduleName) {

47

console.log(`[PRELOAD] Attempting to load: ${moduleName}`);

48

});

49

50

MyApp.on('preload:success', function(moduleName, module) {

51

console.log(`[PRELOAD] Successfully loaded: ${moduleName}`);

52

53

// Custom module configuration after successful load

54

if (moduleName === 'coffee-script/register') {

55

// CoffeeScript is now available for .coffee files

56

console.log('CoffeeScript support enabled');

57

} else if (moduleName === 'babel-register') {

58

// Customize babel configuration

59

module.setDefaults({

60

presets: ['env'],

61

plugins: ['transform-runtime']

62

});

63

console.log('Babel configured with default presets');

64

}

65

});

66

67

MyApp.on('preload:failure', function(moduleName, error) {

68

console.error(`[PRELOAD] Failed to load: ${moduleName}`);

69

console.error(`[PRELOAD] Error: ${error.message}`);

70

71

// Provide fallback or alternative solutions

72

if (moduleName === 'coffee-script/register') {

73

console.warn('CoffeeScript support unavailable - .coffee files will not be processed');

74

} else if (moduleName === 'babel-register') {

75

console.warn('Babel transpilation unavailable - modern JS syntax may cause errors');

76

}

77

});

78

79

// Execute with preload modules

80

MyApp.prepare({

81

preload: ['babel-register', 'coffee-script/register', 'nonexistent-module']

82

}, function(env) {

83

MyApp.execute(env, function(env, argv) {

84

console.log('Application started with preloaded modules');

85

});

86

});

87

```

88

89

### Loader Events

90

91

Events emitted when file extension loaders are registered, allowing for monitoring and customization of extension handling.

92

93

```javascript { .api }

94

/**

95

* Event emitted when a file extension loader is successfully registered

96

* @param loaderName - Name/path of the loader module

97

* @param module - The loaded loader module

98

*/

99

on('loader:success', (loaderName: string, module: any) => void): Liftoff;

100

101

/**

102

* Event emitted when a file extension loader fails to load

103

* @param loaderName - Name/path of the loader module that failed

104

* @param error - Error object containing failure details

105

*/

106

on('loader:failure', (loaderName: string, error: Error) => void): Liftoff;

107

```

108

109

**Usage Examples:**

110

111

```javascript

112

const MyApp = new Liftoff({

113

name: 'myapp',

114

extensions: {

115

'.js': null,

116

'.json': null,

117

'.coffee': 'coffee-script/register',

118

'.ts': 'ts-node/register',

119

'.yaml': 'js-yaml-loader'

120

},

121

configFiles: [

122

{ name: 'myappfile', path: '.', findUp: true }

123

]

124

});

125

126

// Monitor loader registration

127

MyApp.on('loader:success', function(loaderName, module) {

128

console.log(`[LOADER] Successfully registered: ${loaderName}`);

129

130

// Configure specific loaders after registration

131

if (loaderName === 'ts-node/register') {

132

console.log('TypeScript configuration loaded');

133

// ts-node is now handling .ts files

134

} else if (loaderName === 'js-yaml-loader') {

135

console.log('YAML configuration support enabled');

136

// YAML files can now be required

137

}

138

});

139

140

MyApp.on('loader:failure', function(loaderName, error) {

141

console.error(`[LOADER] Failed to register: ${loaderName}`);

142

console.error(`[LOADER] Reason: ${error.message}`);

143

144

// Handle missing optional loaders gracefully

145

if (loaderName === 'coffee-script/register') {

146

console.warn('CoffeeScript config files will not be supported');

147

console.warn('Install coffee-script package to enable .coffee configs');

148

} else if (loaderName === 'ts-node/register') {

149

console.warn('TypeScript config files will not be supported');

150

console.warn('Install ts-node package to enable .ts configs');

151

}

152

});

153

154

// Environment building will trigger loader events as configs are discovered

155

const env = MyApp.buildEnvironment();

156

console.log('Environment built with config support for:', Object.keys(MyApp.extensions));

157

```

158

159

### Respawn Events

160

161

Events emitted when the process needs to be respawned with v8 flags, providing visibility into process management and flag handling.

162

163

```javascript { .api }

164

/**

165

* Event emitted when Liftoff respawns the process for v8 flags

166

* @param flags - Array of v8 flags that triggered the respawn

167

* @param childProcess - The child process object

168

*/

169

on('respawn', (flags: string[], childProcess: object) => void): Liftoff;

170

```

171

172

**Usage Examples:**

173

174

```javascript

175

const Liftoff = require('liftoff');

176

177

const MyApp = new Liftoff({

178

name: 'myapp',

179

v8flags: ['--harmony', '--experimental-modules']

180

});

181

182

// Monitor process respawning

183

MyApp.on('respawn', function(flags, childProcess) {

184

console.log(`[RESPAWN] Process respawned with flags: ${flags.join(' ')}`);

185

console.log(`[RESPAWN] Child PID: ${childProcess.pid}`);

186

console.log(`[RESPAWN] Original PID: ${process.pid}`);

187

188

// Log respawn for debugging

189

if (flags.includes('--harmony')) {

190

console.log('ES6 harmony features enabled');

191

}

192

if (flags.includes('--experimental-modules')) {

193

console.log('Experimental ES modules enabled');

194

}

195

196

// Set up child process monitoring

197

childProcess.on('exit', function(code, signal) {

198

console.log(`[RESPAWN] Child process exited with code ${code}, signal ${signal}`);

199

});

200

});

201

202

// Execute - respawn will occur if v8flags detected in process.argv

203

MyApp.prepare({}, function(env) {

204

MyApp.execute(env, function(env, argv) {

205

console.log('Application running in respawned process (if respawn occurred)');

206

console.log('Process PID:', process.pid);

207

});

208

});

209

210

// Example with forced flags causing respawn

211

MyApp.prepare({}, function(env) {

212

MyApp.execute(env, ['--trace-deprecation'], function(env, argv) {

213

console.log('Forced respawn with --trace-deprecation flag');

214

});

215

});

216

```

217

218

### Event-Driven Workflow Example

219

220

Comprehensive example showing how to use all Liftoff events together for complete lifecycle monitoring and customization.

221

222

```javascript

223

const Liftoff = require('liftoff');

224

const chalk = require('chalk'); // For colored output (optional)

225

226

const MyTool = new Liftoff({

227

name: 'mytool',

228

extensions: {

229

'.js': null,

230

'.json': null,

231

'.coffee': 'coffee-script/register',

232

'.ts': 'ts-node/register',

233

'.babel.js': 'babel-register'

234

},

235

v8flags: ['--harmony'],

236

configFiles: [

237

{ name: '.mytoolrc', path: '~' },

238

{ name: 'mytoolfile', path: '.', findUp: true }

239

]

240

});

241

242

// Comprehensive event monitoring

243

let preloadCount = 0;

244

let loaderCount = 0;

245

let respawnOccurred = false;

246

247

MyTool.on('preload:before', function(moduleName) {

248

process.stdout.write(`⏳ Loading ${moduleName}...`);

249

});

250

251

MyTool.on('preload:success', function(moduleName, module) {

252

preloadCount++;

253

console.log(` βœ… Loaded ${moduleName}`);

254

255

// Module-specific post-load configuration

256

if (moduleName === 'babel-register') {

257

// Configure Babel after successful load

258

if (module.setDefaultOption) {

259

module.setDefaultOption('presets', ['env']);

260

console.log(' πŸ“ Configured Babel with env preset');

261

}

262

} else if (moduleName === 'coffee-script/register') {

263

console.log(' β˜• CoffeeScript support enabled');

264

}

265

});

266

267

MyTool.on('preload:failure', function(moduleName, error) {

268

console.log(` ❌ Failed to load ${moduleName}: ${error.message}`);

269

270

// Provide helpful installation hints

271

if (moduleName.includes('coffee-script')) {

272

console.log(' πŸ’‘ Try: npm install coffee-script');

273

} else if (moduleName.includes('babel')) {

274

console.log(' πŸ’‘ Try: npm install babel-register babel-preset-env');

275

} else if (moduleName.includes('ts-node')) {

276

console.log(' πŸ’‘ Try: npm install ts-node typescript');

277

}

278

});

279

280

MyTool.on('loader:success', function(loaderName, module) {

281

loaderCount++;

282

console.log(`πŸ”§ Registered loader: ${loaderName}`);

283

});

284

285

MyTool.on('loader:failure', function(loaderName, error) {

286

console.warn(`⚠️ Failed to register loader: ${loaderName}`);

287

console.warn(` Reason: ${error.message}`);

288

});

289

290

MyTool.on('respawn', function(flags, childProcess) {

291

respawnOccurred = true;

292

console.log(`πŸ”„ Respawned with flags: ${flags.join(' ')}`);

293

console.log(` Parent PID: ${process.pid} β†’ Child PID: ${childProcess.pid}`);

294

});

295

296

// Execute the tool with full event monitoring

297

console.log('πŸš€ Starting MyTool...\n');

298

299

MyTool.prepare({

300

preload: ['babel-register', 'source-map-support/register']

301

}, function(env) {

302

console.log('\nπŸ“Š Environment Summary:');

303

console.log(` Working Directory: ${env.cwd}`);

304

console.log(` Config File: ${env.configPath || 'none found'}`);

305

console.log(` Local Module: ${env.modulePath || 'none found'}`);

306

console.log(` Preloaded Modules: ${preloadCount}`);

307

console.log(` Registered Loaders: ${loaderCount}`);

308

console.log(` Process Respawned: ${respawnOccurred ? 'yes' : 'no'}`);

309

310

MyTool.execute(env, function(env, argv) {

311

console.log('\n✨ MyTool is ready!');

312

console.log('CLI Arguments:', argv);

313

314

// Your tool's main logic here

315

if (env.configPath) {

316

try {

317

const config = require(env.configPath);

318

console.log('πŸ“„ Configuration loaded:', Object.keys(config));

319

} catch (e) {

320

console.error('❌ Failed to load config:', e.message);

321

}

322

}

323

});

324

});

325

```

326

327

### Error Event Handling

328

329

Best practices for handling errors in event listeners and preventing unhandled exceptions.

330

331

```javascript

332

const MyApp = new Liftoff({ name: 'myapp' });

333

334

// Always handle errors in event listeners

335

MyApp.on('preload:failure', function(moduleName, error) {

336

// Log the error but don't throw - let execution continue

337

console.error(`Module ${moduleName} failed to load:`, error.message);

338

339

// Optionally exit for critical modules

340

if (moduleName === 'critical-module') {

341

console.error('Critical module failed - cannot continue');

342

process.exit(1);

343

}

344

});

345

346

MyApp.on('loader:failure', function(loaderName, error) {

347

// Loader failures are usually non-fatal

348

console.warn(`Optional loader ${loaderName} unavailable:`, error.message);

349

});

350

351

// Set up global error handling for unhandled exceptions

352

process.on('uncaughtException', function(error) {

353

console.error('Uncaught exception:', error.message);

354

console.error('Stack:', error.stack);

355

process.exit(1);

356

});

357

358

process.on('unhandledRejection', function(reason, promise) {

359

console.error('Unhandled promise rejection:', reason);

360

process.exit(1);

361

});

362

```