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

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:

// 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
// 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:

// 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) that swaps the <body> element without refreshing the page:

<!-- 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 — 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →