Watch mode & dev servers
Add -w to fabr build, fabr test or fabr run and fabr keeps running: it watches the files
your targets are built from and redoes the affected work when one changes, until you stop it with
Ctrl-C.
Fabr already knows exactly which files each step of a build reads, so only the steps whose inputs changed run again, and there is nothing to configure: no list of directories to watch or ignore. Changes that arrive close together, as when an editor saves several files or a branch is switched, are handled as one.
| Command | On a change |
|---|---|
fabr build -w <target> |
Rebuilds. |
fabr test -w <target> |
Rebuilds and re-runs the tests. |
fabr run -w <program> |
Rebuilds and restarts the program. |
fabr run -w <serve target> |
Updates the files being served, or restarts the server if the server itself changed. |
Rebuild and retest on change
Section titled “Rebuild and retest on change”fabr build -w mylib # recompile when a source changesfabr test -w mylib # recompile and re-run the testsEach round opens with Changes detected, rebuilding, prints what it rebuilt, ending with Built mylib, and fabr test -w prints the test
summary again, so the terminal shows whether the tests pass as you edit. A change that leaves
nothing to redo, such as an edit to a file no target uses, prints nothing. A build error is
reported once, and fabr goes on watching for the change that fixes it.
fabr test -w reruns a target’s tests only when something they depend on changes, and for
JavaScript only the test files a change can reach run again; see
Running tests. --retry-failed, which runs failed tests again without a change,
can’t be combined with -w.
--trace works under -w too: the trace file is rewritten at the end of each round, with each
round marked; see Tracing a run.
Editing a build file takes effect in the same way as editing a source.
Restart a program on change
Section titled “Restart a program on change”fabr run -w mytool --flag argWhen something the program is built from changes, fabr rebuilds it and restarts it with the same arguments:
- The new version is installed in a second directory while the old one keeps running, so a build error, or a rebuild that turns out identical to the running program, leaves the old one running undisturbed.
- fabr stops the running program with
SIGTERM, and withSIGKILLif it hasn’t exited within two seconds. Stopping includes any processes the program started itself. - Once it has exited, fabr starts the new version. A server can therefore bind the same port again.
The two directories take turns: the next restart updates the directory the old version ran from
with only the files that changed. fabr keeps them in its cache after you stop it, so a later
fabr run -w of the same program starts by updating them too.
A program that exits by itself isn’t restarted straight away: fabr goes on watching and starts it again on the next change.
Dev servers with serve
Section titled “Dev servers with serve”A serve target describes a long-running server together
with the files it serves. Any program fabr can run will do as the server:
serve site { tool = @npm:http-server:14.1.1; # the server: a package, a script or a js_script files = mysite; # what to serve: here, the output of the mysite target args = -c-1 .; # http-server options: no caching, serve this directory}fabr run -w siteThe server starts in a directory that contains files, which is why . is the right path to
serve. This differs from other programs, which fabr run starts in your current directory.
Under -w, fabr treats the two parts of the target differently:
- When the served files change, fabr updates them in the directory the server is running in,
and prints
Updating site content (N files). The server isn’t restarted. Each file is replaced in one step, so the server never reads half of one, and a server that watches its directory sees the change as it would any other. - When the server changes, meaning its
tool,deps,argsorenv, fabr restarts it.
Environment variables
Section titled “Environment variables”A server starts with the environment you ran fabr in. Give the target an env map to add
variables or replace ones your shell sets:
serve site { tool = site_server; files = mysite; env = { NODE_ENV = development; PORT = 8080; }}A generate target has env too, with a difference: its
commands are build steps and start with no environment, so the variables in env are the only
ones they have, beside each program’s own env, which the target’s is set over.
An example
Section titled “An example”Fabr’s own documentation site is built and previewed this way. A generate target runs the site
generator to produce the static site, and a serve target runs http-server over the result:
generate docs_site { srcs = ./src/** ./public/** ./astro.config.mjs; run = astro build; output = dist:**;}
serve docs_serve { tool = @npm:http-server:14.1.1; files = docs_site; args = -c-1 .;}With fabr run -w docs_serve running, saving a page rebuilds the site and updates the served
files.
Stopping
Section titled “Stopping”Ctrl-C stops fabr and the program it is running, along with any processes that program started;
so do SIGTERM and SIGHUP. A fabr killed with SIGKILL (kill -9, or the system running out of
memory) gets no chance to, and leaves the program running with nothing supervising it: stop it by
hand. For a server, finding the process that holds its port is usually quickest.