@routegraph/watcher
v1.0.1
Published
Chokidar-based file watcher that hot-reloads route files into a running RouteGraph.
Readme
@routegraph/watcher
Hot reload for RouteGraph in development — watches your routes/ directory and calls graph.reload() when a route file is added, changed, or removed.
Installation
pnpm add -D @routegraph/watcherRouteWatcher
class RouteWatcher extends EventEmitter {
constructor(graph: RouteGraph, options?: WatcherOptions)
start(): void
stop(): void
get isWatching(): boolean
on(event: 'route:added', cb: (node: RouteNode) => void): this
on(event: 'route:removed', cb: (node: RouteNode) => void): this
on(event: 'route:changed', cb: (node: RouteNode) => void): this
on(event: 'reloaded', cb: (diff: RouteDiff) => void): this
on(event: 'error', cb: (err: Error) => void): this
}WatcherOptions
interface WatcherOptions {
debounceMs?: number // default: 100 — per-file debounce, prevents duplicate reloads on rapid saves
ignored?: string[] // extra chokidar ignore patterns, added to the built-in ones
}Built-in ignore patterns (always applied, regardless of ignored): **/node_modules/**, **/dist/**, **/_*.
Events
| Event | Payload | Fires when |
|---|---|---|
| route:added | RouteNode | A new <Method>.ts file appears |
| route:changed | RouteNode | An existing <Method>.ts file is modified |
| route:removed | RouteNode | A <Method>.ts file is deleted |
| reloaded | RouteDiff ({ added, removed, changed }, each RouteNode[]) | After every successful graph.reload() triggered by the above |
| error | Error | chokidar itself errors, or graph.reload() throws |
Usage
import { RouteGraph } from '@routegraph/core'
import { RouteWatcher } from '@routegraph/watcher'
import { createExpressRouter } from '@routegraph/express'
const graph = new RouteGraph({ routesDir: './routes' })
await graph.load()
if (process.env.NODE_ENV === 'development') {
const watcher = new RouteWatcher(graph, { debounceMs: 150 })
watcher.on('reloaded', (diff) => {
console.log(`hot reload: +${diff.added.length} ~${diff.changed.length} -${diff.removed.length}`)
})
watcher.on('error', (err) => console.error('[watcher]', err))
watcher.start()
process.on('SIGINT', () => {
watcher.stop()
process.exit(0)
})
}
app.use('/api', createExpressRouter(graph))Only edits to files matching the <Method>.ts route naming convention trigger a reload — editing a shared helper (e.g. _shared/db.ts) that a route imports does not itself trigger one, since only the route file's own dynamic import is cache-busted on reload.
Why chokidar
Native fs.watch fires multiple events per save on macOS, doesn't reliably report creation/deletion across platforms, and hits inotify limits on Linux for large trees. chokidar is battle-tested across all three platforms and handles atomic saves and editor backup files gracefully — see DECISIONS.md for the full reasoning. It's the only intentionally-added runtime dependency in this package besides picocolors (used only for the terminal log lines this package prints on its own — reload done (+1 ~0 -0) style messages).
