or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-loading.mdhmr-client.mdindex.mdrequire-polyfill.md

hmr-client.mddocs/

0

# Hot Module Replacement Client

1

2

WebSocket-based client for receiving and applying hot updates during development. The HMR client provides real-time code updates without losing application state, enabling fast development iteration cycles.

3

4

## Capabilities

5

6

### HMRClient Class

7

8

Main class for establishing and managing HMR WebSocket connections with the Metro development server.

9

10

```javascript { .api }

11

/**

12

* WebSocket-based Hot Module Replacement client

13

* Extends EventEmitter for event-driven update handling

14

*/

15

class HMRClient extends EventEmitter {

16

/**

17

* Creates a new HMR client connection

18

* @param url - WebSocket URL for the Metro HMR server

19

*/

20

constructor(url: string);

21

22

/**

23

* Closes the WebSocket connection

24

*/

25

close(): void;

26

27

/**

28

* Sends a message to the HMR server

29

* @param message - String message to send

30

*/

31

send(message: string): void;

32

33

/**

34

* Enables HMR and applies any pending updates

35

*/

36

enable(): void;

37

38

/**

39

* Disables HMR (updates will be queued but not applied)

40

*/

41

disable(): void;

42

43

/**

44

* Returns whether HMR is currently enabled

45

* @returns True if HMR is enabled

46

*/

47

isEnabled(): boolean;

48

49

/**

50

* Returns whether there are updates waiting to be applied

51

* @returns True if there are pending updates

52

*/

53

hasPendingUpdates(): boolean;

54

}

55

56

type SocketState = 'opening' | 'open' | 'closed';

57

```

58

59

**Usage Examples:**

60

61

```javascript

62

const HMRClient = require("metro-runtime/modules/HMRClient");

63

64

// Basic HMR client setup

65

const client = new HMRClient("ws://localhost:8081/hot");

66

67

// Enable HMR when ready

68

client.enable();

69

70

// Set up event listeners

71

client.on("open", () => {

72

console.log("HMR connection established");

73

});

74

75

client.on("update", (update) => {

76

console.log("Received hot update:", update.revisionId);

77

console.log("Modified modules:", update.modified.length);

78

});

79

80

client.on("error", (error) => {

81

console.error("HMR error:", error);

82

});

83

84

// Disable HMR temporarily

85

const pauseHMR = () => {

86

client.disable();

87

console.log("HMR paused, updates will be queued");

88

};

89

90

// Re-enable and apply queued updates

91

const resumeHMR = () => {

92

client.enable();

93

console.log("HMR resumed, applying queued updates");

94

};

95

```

96

97

### Event System

98

99

The HMRClient emits various events for different stages of the update process:

100

101

```javascript { .api }

102

// Connection events

103

client.on('open', () => void);

104

client.on('close', (closeEvent) => void);

105

client.on('connection-error', (error) => void);

106

107

// HMR lifecycle events

108

client.on('bundle-registered', () => void);

109

client.on('update-start', (data: {isInitialUpdate: boolean}) => void);

110

client.on('update', (update: HmrUpdate) => void);

111

client.on('update-done', () => void);

112

client.on('error', (error: FormattedError) => void);

113

```

114

115

**Event Usage Examples:**

116

117

```javascript

118

// Complete HMR event handling

119

const setupHMRClient = (url) => {

120

const client = new HMRClient(url);

121

122

// Connection lifecycle

123

client.on("open", () => {

124

console.log("πŸ”₯ HMR connected");

125

client.send(JSON.stringify({

126

type: "register-entrypoints",

127

entryPoints: ["index.js"]

128

}));

129

});

130

131

client.on("close", (event) => {

132

console.log("❌ HMR disconnected:", event.reason);

133

});

134

135

client.on("connection-error", (error) => {

136

console.error("🚨 HMR connection failed:", error);

137

});

138

139

// Update lifecycle

140

client.on("bundle-registered", () => {

141

console.log("πŸ“¦ Bundle registered with HMR server");

142

});

143

144

client.on("update-start", ({ isInitialUpdate }) => {

145

if (isInitialUpdate) {

146

console.log("🎬 Initial HMR update");

147

} else {

148

console.log("⚑ Hot update starting");

149

}

150

});

151

152

client.on("update", (update) => {

153

const { added, modified, deleted, revisionId } = update;

154

console.log(`πŸ”„ Update ${revisionId}:`, {

155

added: added.length,

156

modified: modified.length,

157

deleted: deleted.length

158

});

159

});

160

161

client.on("update-done", () => {

162

console.log("βœ… Hot update completed");

163

});

164

165

client.on("error", (error) => {

166

console.error("πŸ’₯ HMR error:", error.message);

167

if (error.errors) {

168

error.errors.forEach(err => console.error(" -", err.description));

169

}

170

});

171

172

return client;

173

};

174

```

175

176

## HMR Message Types

177

178

The client handles various message types from the Metro server:

179

180

### Update Messages

181

182

```javascript { .api }

183

type HmrUpdate = {

184

+added: $ReadOnlyArray<HmrModule>,

185

+deleted: $ReadOnlyArray<number>,

186

+isInitialUpdate: boolean,

187

+modified: $ReadOnlyArray<HmrModule>,

188

+revisionId: string,

189

};

190

191

type HmrModule = {

192

+module: [number, string], // [moduleId, moduleCode]

193

+sourceMappingURL: string,

194

+sourceURL: string,

195

};

196

```

197

198

### Server Messages

199

200

Complete message types received from the Metro HMR server:

201

202

```javascript { .api }

203

type HmrMessage =

204

| {+type: 'bundle-registered'}

205

| {+type: 'update-start', +body: {+isInitialUpdate: boolean}}

206

| {+type: 'update-done'}

207

| {+type: 'update', +body: HmrUpdate}

208

| {+type: 'error', +body: FormattedError};

209

210

type FormattedError = {

211

+type: string,

212

+message: string,

213

+errors: Array<{description: string, ...}>,

214

};

215

```

216

217

### Client Messages

218

219

Messages that can be sent to the server:

220

221

```javascript { .api }

222

type HmrClientMessage =

223

| {

224

+type: 'register-entrypoints',

225

+entryPoints: Array<string>,

226

}

227

| {

228

+type: 'log',

229

+level: 'trace' | 'info' | 'warn' | 'log' | 'group' | 'groupCollapsed' | 'groupEnd' | 'debug',

230

+data: Array<mixed>,

231

+mode: 'BRIDGE' | 'NOBRIDGE',

232

}

233

| {

234

+type: 'log-opt-in',

235

};

236

```

237

238

## Update Processing

239

240

The HMR client automatically processes updates through code injection:

241

242

```javascript

243

// Updates are processed automatically when HMR is enabled

244

// The client injects new module code using eval() or globalEvalWithSourceUrl()

245

246

// Manual update handling (advanced usage)

247

client.on("update", (update) => {

248

// Updates are automatically applied when HMR is enabled

249

// This event is for monitoring/logging purposes

250

251

update.added.forEach(module => {

252

const [moduleId, code] = module.module;

253

console.log(`Added module ${moduleId}`);

254

});

255

256

update.modified.forEach(module => {

257

const [moduleId, code] = module.module;

258

console.log(`Modified module ${moduleId}`);

259

});

260

261

update.deleted.forEach(moduleId => {

262

console.log(`Deleted module ${moduleId}`);

263

});

264

});

265

```

266

267

## Connection Management

268

269

The client handles connection states and message queuing:

270

271

```javascript

272

// Connection state management

273

const monitorConnection = (client) => {

274

const checkState = () => {

275

console.log("HMR State:", {

276

enabled: client.isEnabled(),

277

hasPending: client.hasPendingUpdates()

278

});

279

};

280

281

setInterval(checkState, 5000);

282

};

283

284

// Graceful shutdown

285

const shutdownHMR = (client) => {

286

console.log("Shutting down HMR client...");

287

client.disable();

288

client.close();

289

};

290

291

// Reconnection logic (manual implementation)

292

const createReconnectingClient = (url) => {

293

let client = new HMRClient(url);

294

295

client.on("close", () => {

296

console.log("Attempting to reconnect in 5 seconds...");

297

setTimeout(() => {

298

client = new HMRClient(url);

299

client.enable();

300

}, 5000);

301

});

302

303

return client;

304

};

305

```

306

307

## Integration with React Fast Refresh

308

309

The HMR client integrates seamlessly with React Fast Refresh for component-level updates:

310

311

```javascript

312

// React Fast Refresh integration is handled automatically

313

// The client works with Metro's React Refresh implementation

314

315

// Custom refresh boundary detection (advanced)

316

client.on("update", (update) => {

317

const hasReactComponents = update.modified.some(module => {

318

const [, code] = module.module;

319

return code.includes("$RefreshReg$") || code.includes("react");

320

});

321

322

if (hasReactComponents) {

323

console.log("πŸ”„ React components updated with Fast Refresh");

324

}

325

});

326

```