Dev Mode
The watch loop that powers ciderpress dev -- file watching, incremental resyncs, and Rspress hot reload.
Overview
Dev mode combines three systems: an initial full sync, a file watcher that triggers incremental resyncs, and a Rspress dev server that picks up content changes via HMR. The watcher is the orchestrator -- it decides what kind of sync to run and whether to restart Rspress.
Lifecycle
File Watching
The watcher (packages/cli/src/lib/watcher.ts) uses Node.js native fs.watch with recursive: true -- a single FSEvents subscription on macOS, a single inotify recursive watch on Linux (Node 22+). It monitors the entire repo root and filters events in the callback.
Ignored directories: node_modules, .git, .ciderpress, dist, .turbo, bundle
Trigger Table
Concurrency
If a sync is already running, the next change queues a pending resync. Config reload state is tracked across queued syncs so a content change followed by a config change still triggers a full reload. After 5 consecutive sync failures, pending resyncs are dropped until the next file change.
Rspress Restart
Config changes do not unconditionally restart Rspress. The watcher (packages/cli/src/lib/watcher.ts:97-101) only invokes onConfigReload when needsServerRestart(previousConfig, config) returns true — i.e. when the hash of restart-relevant fields differs between the old and new config. When triggered, the restart starts a fresh Rspress dev server with persistent build cache disabled so title/theme/color changes take effect. Content-only changes and edits to non-restart-relevant fields skip the restart; Rspress HMR picks up updated files directly from .ciderpress/content/.
Restart-relevant fields
needsServerRestart (packages/cli/src/lib/watcher.ts:223-260) hashes exactly these top-level config fields:
A change to any of these triggers a server restart on the next sync. Changes to sections, nav, or any field not in this list reload + resync only.
When adding a new top-level config field, decide whether edits to it require a Rspress restart and update the hash list accordingly.
OpenAPI Cache
A shared Map<string, unknown> is created once in the dev command and threaded through all sync passes. Dereferenced OpenAPI specs persist in the cache across resyncs, avoiding expensive re-parsing on content-only changes. The cache is cleared on config reload to force re-parsing.