or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-utilities.mderror-overlay.mdindex.mdloader-configuration.mdplugin-configuration.mdplugin-utilities.mdruntime-utilities.mdsocket-integrations.md

client-utilities.mddocs/

0

# Client Utilities

1

2

Browser-side utilities for error handling, webpack error formatting, and connection retry logic used by the React Refresh client-side runtime.

3

4

## Capabilities

5

6

### Error Event Handlers

7

8

Utilities for handling runtime errors and unhandled promise rejections in the browser.

9

10

```javascript { .api }

11

const { handleError, handleUnhandledRejection } = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/errorEventHandlers');

12

13

/**

14

* Creates an error event handler for runtime errors

15

* @param {Function} errorReporter - Function to report errors to overlay

16

* @returns {Function} - Error event handler function

17

*/

18

function handleError(errorReporter: (error: Error) => void): (event: ErrorEvent) => void;

19

20

/**

21

* Creates an unhandled rejection handler for promise rejections

22

* @param {Function} errorReporter - Function to report errors to overlay

23

* @returns {Function} - Unhandled rejection event handler function

24

*/

25

function handleUnhandledRejection(errorReporter: (error: Error) => void): (event: PromiseRejectionEvent) => void;

26

```

27

28

**Usage Example:**

29

30

```javascript

31

const { handleError, handleUnhandledRejection } = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/errorEventHandlers');

32

33

// Error reporting function

34

function reportError(error) {

35

console.error('Runtime error:', error);

36

// Send to error overlay

37

window.__react_refresh_error_overlay__.handleRuntimeError(error);

38

}

39

40

// Set up global error handlers

41

const errorHandler = handleError(reportError);

42

const rejectionHandler = handleUnhandledRejection(reportError);

43

44

// Install handlers

45

window.addEventListener('error', errorHandler);

46

window.addEventListener('unhandledrejection', rejectionHandler);

47

48

// Cleanup function

49

function removeErrorHandlers() {

50

window.removeEventListener('error', errorHandler);

51

window.removeEventListener('unhandledrejection', rejectionHandler);

52

}

53

```

54

55

### Format Webpack Errors

56

57

Formats webpack compilation errors for display in the error overlay with ANSI color support and stack trace processing.

58

59

```javascript { .api }

60

/**

61

* Formats webpack compilation errors for display

62

* @param {string[]} errors - Array of raw webpack error messages

63

* @returns {FormattedError[]} - Array of formatted error objects

64

*/

65

function formatWebpackErrors(errors: string[]): FormattedError[];

66

67

interface FormattedError {

68

message: string;

69

stack?: string;

70

file?: string;

71

lineNumber?: number;

72

columnNumber?: number;

73

}

74

```

75

76

**Usage Example:**

77

78

```javascript

79

const formatWebpackErrors = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/formatWebpackErrors');

80

81

// Raw webpack errors from compilation

82

const rawErrors = [

83

"Module not found: Error: Can't resolve './missing-component' in '/src'",

84

"SyntaxError: Unexpected token '}' (15:4)\n at Parser.pp$4.raise (/webpack/lib/Parser.js:349:13)"

85

];

86

87

// Format errors for display

88

const formattedErrors = formatWebpackErrors(rawErrors);

89

90

formattedErrors.forEach(error => {

91

console.log('Error message:', error.message);

92

console.log('File:', error.file);

93

console.log('Line:', error.lineNumber);

94

if (error.stack) {

95

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

96

}

97

});

98

99

// Display in error overlay

100

formattedErrors.forEach(error => {

101

window.__react_refresh_error_overlay__.showCompileError(error.message);

102

});

103

```

104

105

### Connection Retry Logic

106

107

Retry utility for socket connections with exponential backoff and maximum retry limits.

108

109

```javascript { .api }

110

/**

111

* Runs a function with retry logic and exponential backoff

112

* @param {Function} fn - Function to execute with retry

113

* @param {number} maxAttempts - Maximum number of retry attempts

114

* @param {number} baseDelay - Base delay between retries in milliseconds

115

* @returns {Promise} - Promise that resolves when function succeeds or rejects after max attempts

116

*/

117

function runWithRetry<T>(

118

fn: () => Promise<T>,

119

maxAttempts?: number,

120

baseDelay?: number

121

): Promise<T>;

122

```

123

124

**Usage Example:**

125

126

```javascript

127

const runWithRetry = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/retry');

128

129

// Function that might fail (e.g., socket connection)

130

async function connectToWebSocket() {

131

return new Promise((resolve, reject) => {

132

const socket = new WebSocket('ws://localhost:8080');

133

134

socket.onopen = () => resolve(socket);

135

socket.onerror = (error) => reject(error);

136

137

// Timeout after 5 seconds

138

setTimeout(() => reject(new Error('Connection timeout')), 5000);

139

});

140

}

141

142

// Retry connection with exponential backoff

143

runWithRetry(connectToWebSocket, 5, 1000)

144

.then(socket => {

145

console.log('Connected successfully:', socket);

146

})

147

.catch(error => {

148

console.error('Failed to connect after retries:', error);

149

});

150

151

// Custom retry configuration

152

runWithRetry(

153

() => fetch('/api/health-check'),

154

3, // Max 3 attempts

155

500 // Start with 500ms delay

156

)

157

.then(response => response.json())

158

.then(data => console.log('Health check:', data))

159

.catch(error => console.error('Health check failed:', error));

160

```

161

162

## Advanced Usage Patterns

163

164

### Comprehensive Error Handling Setup

165

166

Set up complete error handling for a React application:

167

168

```javascript

169

const { handleError, handleUnhandledRejection } = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/errorEventHandlers');

170

const formatWebpackErrors = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/formatWebpackErrors');

171

172

class ErrorManager {

173

constructor() {

174

this.errorOverlay = window.__react_refresh_error_overlay__;

175

this.setupErrorHandlers();

176

}

177

178

setupErrorHandlers() {

179

// Report runtime errors to overlay

180

const reportRuntimeError = (error) => {

181

if (this.errorOverlay) {

182

this.errorOverlay.handleRuntimeError(error);

183

}

184

// Also log to console for debugging

185

console.error('Runtime error:', error);

186

};

187

188

// Set up global error handlers

189

const errorHandler = handleError(reportRuntimeError);

190

const rejectionHandler = handleUnhandledRejection(reportRuntimeError);

191

192

window.addEventListener('error', errorHandler);

193

window.addEventListener('unhandledrejection', rejectionHandler);

194

195

// Store handlers for cleanup

196

this.errorHandler = errorHandler;

197

this.rejectionHandler = rejectionHandler;

198

}

199

200

handleCompilationErrors(errors) {

201

if (errors && errors.length > 0) {

202

const formatted = formatWebpackErrors(errors);

203

204

// Show first error in overlay

205

if (this.errorOverlay && formatted[0]) {

206

this.errorOverlay.showCompileError(formatted[0].message);

207

}

208

209

// Log all errors to console

210

formatted.forEach((error, index) => {

211

console.group(`Compilation Error ${index + 1}:`);

212

console.error(error.message);

213

if (error.file) console.log('File:', error.file);

214

if (error.lineNumber) console.log('Line:', error.lineNumber);

215

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

216

console.groupEnd();

217

});

218

}

219

}

220

221

clearErrors() {

222

if (this.errorOverlay) {

223

this.errorOverlay.clearRuntimeErrors();

224

this.errorOverlay.clearCompileError();

225

}

226

}

227

228

cleanup() {

229

if (this.errorHandler) {

230

window.removeEventListener('error', this.errorHandler);

231

}

232

if (this.rejectionHandler) {

233

window.removeEventListener('unhandledrejection', this.rejectionHandler);

234

}

235

}

236

}

237

238

// Initialize error management

239

const errorManager = new ErrorManager();

240

241

// Handle webpack hot updates

242

if (module.hot) {

243

module.hot.addStatusHandler(status => {

244

if (status === 'idle') {

245

errorManager.clearErrors();

246

}

247

});

248

}

249

```

250

251

### Resilient Socket Connection Manager

252

253

Create a robust socket connection with retry logic:

254

255

```javascript

256

const runWithRetry = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/retry');

257

const { handleError } = require('@pmmmwh/react-refresh-webpack-plugin/client/utils/errorEventHandlers');

258

259

class SocketManager {

260

constructor(url, options = {}) {

261

this.url = url;

262

this.maxRetries = options.maxRetries || 10;

263

this.baseDelay = options.baseDelay || 1000;

264

this.socket = null;

265

this.isConnecting = false;

266

this.messageHandlers = [];

267

268

// Set up error handling

269

this.errorHandler = handleError((error) => {

270

console.error('Socket error:', error);

271

this.handleConnectionError(error);

272

});

273

}

274

275

async connect() {

276

if (this.socket && this.socket.readyState === WebSocket.OPEN) {

277

return this.socket;

278

}

279

280

if (this.isConnecting) {

281

return new Promise((resolve) => {

282

this.once('connected', resolve);

283

});

284

}

285

286

this.isConnecting = true;

287

288

try {

289

this.socket = await runWithRetry(

290

() => this.createConnection(),

291

this.maxRetries,

292

this.baseDelay

293

);

294

295

this.isConnecting = false;

296

this.emit('connected', this.socket);

297

return this.socket;

298

299

} catch (error) {

300

this.isConnecting = false;

301

throw error;

302

}

303

}

304

305

createConnection() {

306

return new Promise((resolve, reject) => {

307

const socket = new WebSocket(this.url);

308

309

socket.onopen = () => {

310

console.log('Socket connected');

311

resolve(socket);

312

};

313

314

socket.onmessage = (event) => {

315

this.handleMessage(JSON.parse(event.data));

316

};

317

318

socket.onclose = () => {

319

console.log('Socket disconnected');

320

this.handleDisconnection();

321

};

322

323

socket.onerror = (error) => {

324

console.error('Socket connection failed:', error);

325

reject(error);

326

};

327

328

// Connection timeout

329

setTimeout(() => {

330

if (socket.readyState === WebSocket.CONNECTING) {

331

socket.close();

332

reject(new Error('Connection timeout'));

333

}

334

}, 10000);

335

});

336

}

337

338

handleMessage(message) {

339

this.messageHandlers.forEach(handler => {

340

try {

341

handler(message);

342

} catch (error) {

343

this.errorHandler({ error });

344

}

345

});

346

}

347

348

handleConnectionError(error) {

349

// Attempt reconnection after delay

350

setTimeout(() => {

351

if (!this.socket || this.socket.readyState === WebSocket.CLOSED) {

352

this.connect().catch(retryError => {

353

console.error('Reconnection failed:', retryError);

354

});

355

}

356

}, this.baseDelay);

357

}

358

359

handleDisconnection() {

360

// Auto-reconnect after short delay

361

setTimeout(() => {

362

this.connect().catch(error => {

363

console.error('Auto-reconnect failed:', error);

364

});

365

}, 2000);

366

}

367

368

onMessage(handler) {

369

this.messageHandlers.push(handler);

370

}

371

372

// Simple event emitter methods

373

once(event, handler) {

374

const onceHandler = (...args) => {

375

handler(...args);

376

this.off(event, onceHandler);

377

};

378

this.on(event, onceHandler);

379

}

380

381

on(event, handler) {

382

if (!this.events) this.events = {};

383

if (!this.events[event]) this.events[event] = [];

384

this.events[event].push(handler);

385

}

386

387

off(event, handler) {

388

if (!this.events || !this.events[event]) return;

389

const index = this.events[event].indexOf(handler);

390

if (index > -1) this.events[event].splice(index, 1);

391

}

392

393

emit(event, ...args) {

394

if (!this.events || !this.events[event]) return;

395

this.events[event].forEach(handler => handler(...args));

396

}

397

}

398

399

// Usage

400

const socketManager = new SocketManager('ws://localhost:8080');

401

402

socketManager.onMessage((message) => {

403

console.log('Received message:', message);

404

405

// Handle different message types

406

switch (message.type) {

407

case 'errors':

408

errorManager.handleCompilationErrors(message.errors);

409

break;

410

case 'ok':

411

errorManager.clearErrors();

412

break;

413

}

414

});

415

416

// Connect with retry logic

417

socketManager.connect()

418

.then(() => console.log('Socket ready'))

419

.catch(error => console.error('Failed to establish connection:', error));

420

```