# How Archify's Live Preview Mode Works with File Watching: A Deep Dive

> Learn how Archify's live preview mode uses chokidar file watching and WebSockets for instant browser updates without reloads. Deep dive into Archify's file watching.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: deep-dive
- Published: 2026-08-10

---

**Archify's live preview combines chokidar-based file watching with WebSocket messaging to deliver instant browser updates without full page reloads.**

This article explains how the `archify preview` command turns source file changes into real-time HTML updates. The implementation spans three coordinated systems: filesystem monitoring, incremental rebuilding, and client-side hot replacement as found in the `tt-a1i/archify` repository.

## File Watcher Initialization

When you run `npm run preview` or `archify preview`, the script at `scripts/build-start.mjs` initializes a **chokidar** watcher. Chokidar wraps Node's native `fs.watch` with cross-platform consistency and smarter change detection.

The watcher monitors the project's `src/` directory—or any paths configured in the `watch` field of your Archify config:

```javascript
// scripts/build-start.mjs
import { watch } from 'chokidar';

const watcher = watch('src/**/*', { 
  ignoreInitial: true  // skip build on startup
});

watcher.on('change', path => {
  console.log(`File changed: ${path}`);
  // triggers rebuild + browser notification
});

```

The `ignoreInitial: true` option prevents a redundant build when the preview server first starts. The `**/*` glob pattern recursively watches all files, letting you edit Markdown, templates, or assets anywhere in the tree.

## Incremental Rebuild Pipeline

Each `change` event fires a **debounced `rebuild` function** also defined in `scripts/build-start.mjs`. This function:

- Re-runs the Markdown-to-HTML transformer only for the changed file
- Re-renders dependent pages that include or reference that file
- Skips unchanged assets to keep rebuilds under 100ms for typical projects

```javascript
// scripts/build-start.mjs (excerpt)
import { rebuild } from './build.js';

watcher.on('change', path => {
  rebuild(path);  // incremental re-render
  // WebSocket broadcast happens here
});

```

The debounce timeout (typically 50-100ms) batches rapid saves from "save all" operations or IDE auto-save features.

## WebSocket Live Update to Browser

The preview server maintains a persistent **WebSocket connection** to every open browser tab. This eliminates polling overhead and enables sub-second update propagation.

### Server-Side Broadcast

The `ws` package creates a `WebSocketServer` attached to the same HTTP server that serves static files:

```javascript
// scripts/build-start.mjs
import { createServer } from 'http';
import { WebSocketServer } from 'ws';

const server = createServer(/* static file handler */);
const wss = new WebSocketServer({ server });

watcher.on('change', path => {
  rebuild(path);
  wss.clients.forEach(client => client.send('reload'));
});

server.listen(3000);

```

The `'reload'` string is intentionally minimal—just enough to signal without payload overhead. Full HTML content is fetched client-side to keep the protocol simple.

### Client-Side Hot Replacement

Every preview page embeds a small script (visible in [`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html)) that swaps the `<body>` element without refreshing the page:

```html
<!-- examples/web-app.html -->
<script>
  const ws = new WebSocket('ws://localhost:3000');
  
  ws.onmessage = event => {
    if (event.data === 'reload') {
      fetch(location.href)
        .then(response => response.text())
        .then(html => {
          const parser = new DOMParser();
          const doc = parser.parseFromString(html, 'text/html');
          document.body.replaceWith(doc.body);
        });
    }
  };
</script>

```

This **DOM-preserving swap** maintains scroll position, focused elements, and DevTools state—critical for iterative design work.

## Architecture Comparison: Why This Design Wins

| Component | Archify's Approach | Common Alternative | Benefit |
|-----------|-------------------|-------------------|---------|
| **File watching** | chokidar with native `fs.watch` | Polling with `setInterval` | Lower CPU, instant change detection |
| **Rebuild scope** | Incremental (single file + deps) | Full site rebuild | <100ms vs. seconds for large sites |
| **Browser update** | WebSocket push + body swap | Page refresh or HMR runtime | No full reload, zero client-side framework |
| **Protocol** | Plain text `'reload'` signal | JSON with full diff payloads | Simpler, smaller, no parsing overhead |

## Key Source Files

Understanding these files lets you customize or debug Archify's live preview:

- **`scripts/build-start.mjs`** — Watcher setup, debounced rebuild, WebSocket server
- **[`examples/web-app.html`](https://github.com/tt-a1i/archify/blob/main/examples/web-app.html)** — Client-side WebSocket handler and DOM swap implementation
- **`scripts/run-tests.mjs`** — Reuses the same watcher infrastructure for integration testing

## Summary

- **Chokidar** watches your `src/` directory and emits change events
- A **debounced rebuild** regenerates only affected HTML
- **WebSocket broadcast** notifies all connected browsers instantly
- **Client-side body replacement** updates the preview without losing UI state

This three-stage pipeline gives Archify its hallmark zero-config live preview that stays fast as projects grow.

## Frequently Asked Questions

### How do I change which files trigger a rebuild?

Archify respects a `watch` array in your configuration file. Add glob patterns there, or modify the `watch()` call in `scripts/build-start.mjs` if you need custom ignore rules beyond the default `src/**/*`.

### Does live preview work with external CSS or image changes?

Yes. The chokidar watcher monitors all files under `src/`, including stylesheets and assets. When these change, the rebuild step may skip re-rendering Markdown but still triggers the `'reload'` broadcast, and the client's `fetch()` retrieves fresh resource URLs.

### Why does my browser sometimes reload instead of hot-swapping?

Hot replacement requires the WebSocket connection to stay open. If the server restarted or port 3000 changed, the connection drops and Archify falls back to standard behavior on the next manual refresh. Check DevTools' Console for WebSocket errors to diagnose.

### Can I disable the debounce for faster updates?

Edit `scripts/build-start.mjs` and reduce or remove the timeout wrapping the `rebuild` call. Be aware that rapid file writes—like saving 20 files at once—will then trigger 20 sequential rebuilds instead of one batched update.