Cookbook Router

Watch and recovery

How each adapter notices changes, avoids output loops, preserves good artifacts, and recovers after invalid input.

Recovery is part of correctness

A watch plugin that reports an error and then stops observing the broken input is not a watch plugin. It is a one-shot build wearing a lanyard.

Capability matrix

CapabilityViteWebpackRspackRollup/RolldownesbuildBun
Generate before compilationYesYesYesYesYesYes
Watch config candidatesYesYesYesYesHost graph onlyHost graph only
Watch route glob rootsYesYesYesYesNoNo
Detect created/deleted route filesYesYesYesYesNot guaranteedNot guaranteed
Preserve previous valid output after watch failureYesYesYesYesFiles are not rewritten on failed runFiles are not rewritten on failed run
Retry after repairYesYesYesYesOn next host build startOn next host build start

What is watched

The shared watch-state resolver tries to load effective options with empty route matches allowed. On success it watches the resolved config plus route-file watch roots. On failure it falls back to all standard config candidates plus roots derived from explicit route patterns.

Generated output is excluded from normal dependency watching. Otherwise writing contracts.ts would cause another build, which would write contracts.ts, which would cause another build, until the laptop becomes a space heater.

Delete recovery

Vite explicitly watches the output directory for deletion events and regenerates missing artifacts. Webpack/Rspack ignore the output directory as an ordinary watch dependency, then generate again before the next compilation. Rollup regenerates at each build start.

esbuild and Bun companion watch

package.json
{
  "scripts": {
    "dev:routes": "cbr generate --watch",
    "dev:app": "your-bundler-watch-command",
    "dev": "run-p dev:routes dev:app"
  }
}

Use any process runner your project already trusts. The architectural point is two cooperating watches: Cookbook Router owns route discovery; the bundler owns the application graph.

On this page