Live preview¶
rules_latex ships two live-preview rules for the
"edit-the-source-watch-the-PDF-update" workflow. Both watch the
document's transitive sources via LatexInfo and rebuild via
bazel build on every save.
latex_serve — system PDF viewer¶
load("@rules_latex//latex:defs.bzl", "latex_document", "latex_serve")
latex_document(name = "cv", main = "cv.tex", srcs = ["cv.tex"])
latex_serve(
name = "cv_live",
document = ":cv",
)
The PDF opens once in your system viewer (Preview on macOS,
xdg-open on Linux, start on Windows). Subsequent rebuilds rely on
the viewer's own auto-reload behaviour:
| Viewer | Auto-reload? |
|---|---|
| macOS Preview | |
| Linux Evince | |
| Linux Okular | |
| Adobe Reader | (locks the file) |
| Chrome PDF viewer | (manual refresh) |
latex_serve_web — in-browser preview¶
For an Overleaf-style experience, declare a latex_serve_web target:
load("@rules_latex//latex:defs.bzl", "latex_document", "latex_serve_web")
latex_document(
name = "cv",
main = "cv.tex",
srcs = ["cv.tex"],
synctex = True, # enables click-to-source
)
latex_serve_web(
name = "cv_web",
document = ":cv",
)
Open the URL in your browser. The page:
- Renders the PDF with PDF.js (vendored, no CDN dependency).
- Listens for "reload" events over Server-Sent Events.
- Preserves scroll position across reloads.
- When
synctex = Trueis set on the document, clicking anywhere in the rendered PDF resolves to a sourcefile:linedisplayed in the footer bar.
How fast is the loop?¶
For a small document (single-page CV, hello-world) paired with a cache snapshot, steady-state rebuilds complete in 200–400 ms. First build is slower (the online prime takes ~30 s) but happens exactly once per content-hash of the inputs — Bazel's action cache handles the rest.
For larger documents (multi-chapter thesis, paper with figures), the TeX compile itself dominates and rebuilds run in 2–5 s.
What gets watched?¶
The watcher monitors every .tex, .bib, image, and other file in
the document's srcs plus transitively via deps. Edits to the
toolchain binary or the cache snapshot are picked up by Bazel's
analysis layer, so they trigger correct rebuilds too.
External-repo files (e.g. from a latex_library published in another
Bazel module) are not watched. Edit those and re-run bazel run
//:cv_web to pick up the change.
Architecture¶
Both rules synthesise a small launcher script that:
- Polls the watched paths every 250 ms via
os.stat. - Shells out to
bazel build <document_label>on change. latex_serveopens the PDF once;latex_serve_webkeeps a tiny HTTP server alive and pushes SSE events to connected browser tabs.
Both use the same bazel build invocation as a normal build, which
means live-mode behaviour is identical to CI — no "works locally,
fails in CI" drift. See
DESIGN.md §4.7
for the rationale.