or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-system.mdcli-commands.mdconfiguration.mddevelopment-server.mdindex.mdroute-management.mdvite-integration.md

development-server.mddocs/

0

# Development Server

1

2

Development server with live reload, Hot Module Replacement (HMR), and development-time optimizations for efficient Remix application development.

3

4

## Capabilities

5

6

### Live Reload

7

8

Development server with live reload functionality that automatically refreshes the browser when files change.

9

10

```typescript { .api }

11

/**

12

* Start live reload development server

13

* @param config - Resolved Remix configuration

14

* @param options - Live reload options

15

* @returns Promise that resolves when server stops

16

*/

17

namespace devServer {

18

function liveReload(

19

config: ResolvedRemixConfig,

20

options?: LiveReloadOptions

21

): Promise<void>;

22

}

23

24

interface LiveReloadOptions {

25

/** Port for live reload server (default: auto-detect) */

26

port?: number;

27

28

/** Host for live reload server (default: localhost) */

29

host?: string;

30

31

/** Whether to include node_modules in file watching */

32

includeNodeModules?: boolean;

33

34

/** Callback called when server starts */

35

onStart?: (port: number) => void;

36

37

/** Callback called when file changes */

38

onFileChange?: (file: string) => void;

39

40

/** Callback called when rebuild starts */

41

onRebuildStart?: () => void;

42

43

/** Callback called when rebuild finishes */

44

onRebuildFinish?: (success: boolean) => void;

45

}

46

```

47

48

### Environment Management

49

50

Environment variable loading and management for development.

51

52

```typescript { .api }

53

/**

54

* Load environment variables from .env files

55

* @param rootDirectory - Root directory to search for .env files

56

* @returns Promise that resolves when environment is loaded

57

*/

58

namespace env {

59

function loadEnv(rootDirectory: string): Promise<void>;

60

}

61

```

62

63

### Hot Module Replacement

64

65

HMR system for updating modules without full page refresh during development.

66

67

```typescript { .api }

68

/**

69

* HMR update information

70

*/

71

interface Update {

72

/** Type of update */

73

type: "js-update" | "css-update" | "full-reload";

74

75

/** Timestamp of update */

76

timestamp: number;

77

78

/** Modules that were updated */

79

modules: string[];

80

81

/** Update payload */

82

payload?: any;

83

}

84

85

/**

86

* HMR client connection interface

87

*/

88

interface HMRClient {

89

/** Send update to client */

90

send(update: Update): void;

91

92

/** Close client connection */

93

close(): void;

94

95

/** Check if client is connected */

96

isConnected(): boolean;

97

}

98

```

99

100

### Development Middleware

101

102

Express-compatible middleware for development features.

103

104

```typescript { .api }

105

/**

106

* Create development middleware for Express

107

* @param config - Remix configuration

108

* @param options - Middleware options

109

* @returns Express-compatible middleware

110

*/

111

function createDevMiddleware(

112

config: RemixConfig,

113

options?: DevMiddlewareOptions

114

): (req: Request, res: Response, next: NextFunction) => void;

115

116

interface DevMiddlewareOptions {

117

/** Enable source map support */

118

sourceMaps?: boolean;

119

120

/** Enable request logging */

121

logging?: boolean;

122

123

/** Custom error handler */

124

onError?: (error: Error) => void;

125

}

126

```

127

128

### File Watching

129

130

Advanced file watching system for development server functionality.

131

132

```typescript { .api }

133

/**

134

* File watch cache for efficient file system monitoring

135

*/

136

interface FileWatchCache {

137

/** Start watching files */

138

start(): Promise<void>;

139

140

/** Stop watching files */

141

stop(): Promise<void>;

142

143

/** Check if file has changed */

144

hasChanged(file: string): boolean;

145

146

/** Get file modification time */

147

getModTime(file: string): Date | undefined;

148

149

/** Invalidate cache for file */

150

invalidate(file: string): void;

151

}

152

153

/**

154

* Create file watch cache

155

* @param options - Watch cache options

156

* @returns File watch cache instance

157

*/

158

function createFileWatchCache(options?: {

159

/** Directories to watch */

160

watchDirs?: string[];

161

162

/** File patterns to ignore */

163

ignore?: string[];

164

165

/** Enable polling mode */

166

usePolling?: boolean;

167

168

/** Polling interval in milliseconds */

169

pollingInterval?: number;

170

}): FileWatchCache;

171

```

172

173

### Development Utilities

174

175

Utility functions for development server operations.

176

177

```typescript { .api }

178

/**

179

* Get available port for development server

180

* @param preferredPort - Preferred port number

181

* @param host - Host to bind to

182

* @returns Promise resolving to available port

183

*/

184

function getPort(

185

preferredPort?: number,

186

host?: string

187

): Promise<number>;

188

189

/**

190

* Detect package manager being used

191

* @returns Package manager name or null if not detected

192

*/

193

function detectPackageManager(): "npm" | "yarn" | "pnpm" | null;

194

195

/**

196

* Check if development mode is active

197

* @returns Whether in development mode

198

*/

199

function isDevelopment(): boolean;

200

201

/**

202

* Format development server messages

203

* @param message - Message to format

204

* @param type - Message type

205

* @returns Formatted message

206

*/

207

function formatDevMessage(

208

message: string,

209

type?: "info" | "warn" | "error"

210

): string;

211

```

212

213

## Usage Examples

214

215

### Basic Live Reload Server

216

217

```typescript

218

import { devServer, readConfig } from "@remix-run/dev";

219

220

async function startDevServer() {

221

const config = await readConfig();

222

223

await devServer.liveReload(config, {

224

port: 3001,

225

host: "localhost",

226

includeNodeModules: false,

227

onStart: (port) => {

228

console.log(`Development server started on port ${port}`);

229

},

230

onFileChange: (file) => {

231

console.log(`File changed: ${file}`);

232

},

233

onRebuildStart: () => {

234

console.log("Rebuilding...");

235

},

236

onRebuildFinish: (success) => {

237

console.log(`Rebuild ${success ? 'completed' : 'failed'}`);

238

},

239

});

240

}

241

242

startDevServer().catch(console.error);

243

```

244

245

### Custom Development Server with Express

246

247

```typescript

248

import express from "express";

249

import { createDevMiddleware, readConfig } from "@remix-run/dev";

250

import { createRequestHandler } from "@remix-run/express";

251

252

async function createCustomDevServer() {

253

const app = express();

254

const config = await readConfig();

255

256

// Add development middleware

257

app.use(createDevMiddleware(config, {

258

sourceMaps: true,

259

logging: true,

260

onError: (error) => {

261

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

262

},

263

}));

264

265

// Add Remix request handler

266

app.all("*", createRequestHandler({

267

build: () => import("./build"),

268

mode: "development",

269

}));

270

271

const port = await getPort(3000);

272

app.listen(port, () => {

273

console.log(`Server running at http://localhost:${port}`);

274

});

275

}

276

277

createCustomDevServer().catch(console.error);

278

```

279

280

### File Watching Setup

281

282

```typescript

283

import { createFileWatchCache } from "@remix-run/dev";

284

285

async function setupFileWatching() {

286

const watchCache = createFileWatchCache({

287

watchDirs: ["app", "public"],

288

ignore: ["**/node_modules/**", "**/.git/**"],

289

usePolling: false,

290

});

291

292

await watchCache.start();

293

294

// Check for changes periodically

295

setInterval(() => {

296

const files = ["app/root.tsx", "app/routes/_index.tsx"];

297

298

for (const file of files) {

299

if (watchCache.hasChanged(file)) {

300

console.log(`File changed: ${file}`);

301

console.log(`Modified: ${watchCache.getModTime(file)}`);

302

303

// Invalidate cache for this file

304

watchCache.invalidate(file);

305

}

306

}

307

}, 1000);

308

309

// Cleanup on exit

310

process.on("SIGINT", async () => {

311

await watchCache.stop();

312

process.exit(0);

313

});

314

}

315

316

setupFileWatching().catch(console.error);

317

```

318

319

### Environment Loading

320

321

```typescript

322

import { loadEnv } from "@remix-run/dev";

323

324

async function setupEnvironment() {

325

// Load environment variables from .env files

326

await loadEnv(process.cwd());

327

328

console.log("Environment loaded:");

329

console.log("NODE_ENV:", process.env.NODE_ENV);

330

console.log("DATABASE_URL:", process.env.DATABASE_URL);

331

console.log("SESSION_SECRET:", process.env.SESSION_SECRET ? "[REDACTED]" : "Not set");

332

}

333

334

setupEnvironment().catch(console.error);

335

```

336

337

### HMR Client Integration

338

339

```typescript

340

// Client-side HMR integration

341

interface HMRManager {

342

connect(): void;

343

disconnect(): void;

344

onUpdate(callback: (update: Update) => void): void;

345

}

346

347

const hmrManager: HMRManager = {

348

connect() {

349

const ws = new WebSocket("ws://localhost:3001/hmr");

350

351

ws.onmessage = (event) => {

352

const update: Update = JSON.parse(event.data);

353

354

switch (update.type) {

355

case "js-update":

356

// Handle JavaScript module updates

357

console.log("Updating JS modules:", update.modules);

358

break;

359

360

case "css-update":

361

// Handle CSS updates

362

console.log("Updating CSS modules:", update.modules);

363

this.reloadCSS();

364

break;

365

366

case "full-reload":

367

// Full page reload

368

window.location.reload();

369

break;

370

}

371

};

372

},

373

374

disconnect() {

375

// Cleanup WebSocket connection

376

},

377

378

onUpdate(callback) {

379

// Register update callback

380

},

381

382

reloadCSS() {

383

const links = document.querySelectorAll('link[rel="stylesheet"]');

384

links.forEach((link: HTMLLinkElement) => {

385

const href = link.href;

386

link.href = href + (href.includes("?") ? "&" : "?") + "t=" + Date.now();

387

});

388

},

389

};

390

391

// Initialize HMR in development

392

if (process.env.NODE_ENV === "development") {

393

hmrManager.connect();

394

}

395

```

396

397

### Development Server with Custom Port Detection

398

399

```typescript

400

import { getPort, detectPackageManager } from "@remix-run/dev";

401

402

async function smartDevServer() {

403

// Detect package manager

404

const packageManager = detectPackageManager() || "npm";

405

console.log(`Using package manager: ${packageManager}`);

406

407

// Find available port

408

const port = await getPort(3000, "localhost");

409

console.log(`Starting development server on port ${port}`);

410

411

// Start server based on package manager

412

const command = {

413

npm: "npm run dev",

414

yarn: "yarn dev",

415

pnpm: "pnpm dev",

416

}[packageManager];

417

418

console.log(`Run: ${command} --port ${port}`);

419

}

420

421

smartDevServer().catch(console.error);

422

```