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
```