Building a static HTML site¶
ubc build html renders your project into a self-contained static website —
one HTML page per indexed document, plus the assets those pages need.
It is ubc doing the rendering, not Sphinx:
there is no conf.py, no extension loading and no Python environment involved,
so the whole site comes out of the same index the editor and ubc check already use.
Caution
ubc build html is in alpha.
The command works and is under active development,
but the emitted markup, the theming surface and the available options
may still change between releases,
so it is not yet recommended for production builds.
Pin your ubc version if you depend on the output,
and see Differences from a Sphinx build for what a site built this way
does not yet match in a full sphinx-build.
We would love your feedback.
Quickstart¶
Run the command from anywhere inside your project:
ubc build html
It discovers the closest ubproject.toml, indexes the project,
and writes the site next to that file:
Building index for: /home/me/project/ubproject.toml
Processing 3 files
3 page(s): 3 rendered, 0 reused; 3 written, 0 unchanged; 6 asset(s).
Site written to: /home/me/project/_build/html
Root page: /home/me/project/_build/html/index.html
Done in 0.12s
The last two lines are the ones you want: the site directory, and the page to open first.
Principal options¶
Option |
What it does |
|---|---|
|
The project root to build. Defaults to the current directory. |
|
Where to write the site.
Defaults to |
|
Print the detail of every build and indexing warning. A build that fails the quality gate prints it anyway, so this matters mainly once the gate has been lowered (see Warnings). |
|
Re-render every page, ignoring any existing build manifest. |
|
Fail if a source file changes during the build, instead of re-indexing and retrying once. |
|
Index from scratch rather than reading the on-disk cache.
It implies |
|
Move the failure threshold for this run:
|
|
Fail if more than |
|
Additional diagnostic codes to ignore, comma separated. |
|
A configuration override, repeatable —
for example |
-v / --verbose additionally names the client-asset bundle the binary carries —
the Mermaid, highlight.js and KaTeX versions, and the bundle’s content hash —
which is what to quote when the rendered output looks stale or unexpected.
Run ubc build html --help for the complete list.
The output¶
Each document maps straight to a file:
an indexed document at docname guide/setup
becomes guide/setup.html —
the source layout is mirrored,
with no guide/setup/index.html rewriting —
and everything shared lives under _static/.
It has no server-side component of any kind.
Opening index.html straight from disk — a file:// URL — gives you the
whole site, including full-text search,
which is what makes a built site usable on an air-gapped machine
or straight out of a ZIP file.
See Search for what the search does
and the three files it adds.
Alongside the pages, the output root always carries an objects.inv —
the standard Sphinx inventory of the project’s std domain
(one row per document, per label and per glossary term),
written on every build with no option to turn it off,
exactly as sphinx-build writes one.
It is what makes a published site an intersphinx target:
another project pointing [intersphinx.projects] (or Sphinx’s own
intersphinx_mapping) at the site’s base URL
can then resolve :ref:, :doc: and :term: references into it.
The header’s project and version lines come from [project] name
and [project] version, so setting both is what makes the inventory
identify itself correctly to consumers.
Use ubc intersphinx inspect to read one back.
A needs.json sidecar joins it when [needs] build_json is enabled.
Pages that are no longer produced — because you deleted or renamed a document —
are removed from the output directory on the next build,
which is reported as Removed N stale file(s).
The build only prunes a directory it created itself
(or one an earlier ubc build html made);
pointed at some other non-empty directory
it writes the pages and warns instead of deleting anything.
Rebuilds¶
Rebuilds are incremental in two independent steps, and the count line reports both:
3 page(s): 0 rendered, 3 reused; 0 written, 3 unchanged; 6 asset(s).
- rendered / reused
Whether each page’s body had to be rendered again. A page whose inputs are unchanged has its stored body reused.
- written / unchanged
Whether the assembled page differed from what is already on disk. Identical output is not rewritten, so file timestamps stay put and tools watching the directory are not woken for nothing.
The two are separate, and the second is the stricter one.
--fresh re-renders every page but still byte-compares the result,
so a fresh build of unchanged sources honestly reports
3 rendered, 0 reused; 0 written, 3 unchanged.
Reach for --fresh when you want to rule the manifest out —
after upgrading ubc, or when a page looks stale.
--no-cache goes one step further and re-indexes from scratch as well.
If a source file changes during the build,
the build re-indexes and retries once rather than emitting a half-stale site.
--strict-sources turns that into an error instead,
which is the right setting for a release pipeline
where a moving source tree means something is wrong.
Warnings¶
The build reports two independent counts.
Indexing warnings are the ordinary project diagnostics —
the same findings ubc check reports.
Build warnings are raised by the render phase itself
and all carry a build.* code:
an unreadable extra_css file, a diagram file that cannot be resolved,
a directive or role ubCode has no renderer for, a search index that has grown large.
The ones tied to a [build.html] setting are documented with that setting
on the [build.html] configuration page.
All of them use the ordinary lint configuration,
so you can silence one by code or by message.
Both counts are summarised, and -w / --show-warnings prints the detail,
one severity-headed block per finding (see Linting on the command line):
$ ubc build html -w
3 page(s): 1 rendered, 2 reused; 1 written, 2 unchanged; 6 asset(s).
Found 1 build warning(s).
warning[build.directive_unhandled]
acks: 1 site rendered as a placeholder — no handler for this directive yet (at index:35)
Site written to: /home/me/project/_build/html
Found 1 indexing warning(s).
warning[std.ref]
--> index.rst:39:10
undefined label: 'nowhere-at-all'
Root page: /home/me/project/_build/html/index.html
Done in 0.08s
Important
Both counts feed one quality gate.
Any warning-or-worse finding — from either count — fails the build
with exit code 1, and prints its detail without needing -w.
See Building for production for the bar and how to move it.
That last point is why you will usually see the detail without asking for it.
Under the default bar, a warning both fails the build and prints itself,
so a failing run is self-contained —
you never have to repeat it with -w just to find out what went wrong.
The flag comes into its own once the bar is lowered
(--deny error, --deny none, or [build.html] deny),
where warnings are reported without failing the build
and the summary is otherwise all you would get.
Note
ubc build index does not share the second half of that behaviour:
it gates the detail strictly on -w,
so a failing build index prints only the counts.
Redirecting moved pages¶
Added in version 0.33.0.
When a page moves, every link anyone already has to it breaks. List the move and the build keeps the old URL working:
[build.html.redirects]
"ubc/introduction" = "basics/what_is_ubcode"
"ubc/installation" = "basics/installation"
The build writes a small forwarding page where the old one used to be,
so ubc/introduction.html still resolves
and carries the reader on to basics/what_is_ubcode.html —
keeping the ?query and #fragment they arrived with.
Nothing else about the site changes:
the forwarding pages are ordinary output files,
they are pruned when you delete the entry,
and a rebuild leaves an unchanged one untouched.
The full grammar, the four warnings a faulty entry raises, and what happens with no JavaScript are under redirects.
Building for production¶
Added in version 0.31.2.
Declare your project’s quality bar once, in ubproject.toml:
[build.html]
deny = "warning"
and let CI just run the command:
$ ubc build html
deny takes none, info, warning or error,
and warning — the default, so the snippet above is what the build already does —
fails on any warning-or-worse finding.
error lets warnings through and fails only on errors;
none never fails the threshold
(an explicit --max-warnings budget still applies).
It is one bar over both counts together:
a broken cross-reference from the index
and a degraded page from the render phase
are both defects in the site you are about to publish.
The same bar is what ubc check and ubc build index
have always applied, so the three commands now agree by default.
The site is still written. The gate is a judgement on the artifact, not a refusal to produce it — the pages, assets and search index are all on disk before the exit code is decided. A pipeline can therefore publish a failing build for inspection; the CI/CD guide has a worked GitHub Actions job that does.
Note
A ubc binary built from source without the embedded client bundles
reports build.client_asset_missing — a property of that binary, not
of your project (released binaries embed the bundles). When developing
against such a build, silence it with
ignore = ["build.client_asset_missing"] under [lint],
or relax the bar for the run.
When it fires, the run names the knob that set the bar, and lists the findings without a second run:
$ ubc build html
Found 1 build warning(s).
warning[build.need_view_truncated]
index:16: view directive needlist #0 was truncated: showing the first 2 of 3 needs ...
Site written to: /home/me/project/_build/html
Root page: /home/me/project/_build/html/index.html
Build failed the quality gate: 1 warning(s) found, and any warning-or-worse finding fails this build (build.html.deny = "warning" in ubproject.toml).
Silence a code with ignore = ["<code>"] under [lint] in ubproject.toml.
Or relax the bar: --deny error (errors only), --deny none (never fail).
Done with warnings in 0.42s
Overriding for one run.
--deny on the command line wins over the configuration key,
in both directions:
$ ubc build html --deny none # I know — just build it
$ ubc build html --deny error # errors only, without editing tracked config
$ ubc build html --deny warning # strict, in a project that declared no bar
--max-warnings <N> adds a count budget over the two counts summed —
a ratchet for working an existing project down to zero.
When both are given the stricter one wins.
Narrowing beats relaxing.
A code silenced through lint configuration —
by code, by page or by message — never reaches the gate at all,
which is usually a better answer than lowering the bar for the whole project.
--lint-extend-ignore <CODES> does the same for a single run.
--strict-sources is a different axis and composes with all of this:
it fails a build whose source tree moved underneath it,
whatever the findings say.
Note
ubc build html is still in alpha (see the caution at the top of this page).
This gate is about the quality of your project’s content;
it says nothing about the stability of the emitted markup.
Configuring the site¶
Everything about how the site looks and what it contains
is configured under [build.html] in ubproject.toml:
[build.html]
title = "My Project Docs"
logo = "_static/logo.svg"
extra_css = ["_static/theme.css"]
extra_static = ["_static"]
extra_css names your stylesheets;
extra_static publishes the files those stylesheets reference —
background images, fonts, icons —
copying a listed directory’s contents into the site’s _static/ directory
with their structure preserved.
Listing the whole _static directory above means a source file at
_static/img/bg.png is published at _static/img/bg.png,
so url(img/bg.png) in theme.css resolves.
Each file is still published only once:
the stylesheet and the logo are named by their own keys as well,
and naming a file twice does not copy it twice.
See the HTML site configuration page for every option, and in particular:
Theming with extra_css — the
--ubc-*custom properties and theub-*class vocabulary, which are the two surfaces a re-brand is expected to use.Search — what the search indexes, its query syntax, and how to turn it off.
Math typesetting — the bundled, offline KaTeX.
Unrendered directives, roles and diagram files — what the
build.*coverage warnings mean.
Where it differs from Sphinx¶
A site built by ubc is not yet a drop-in replacement
for the output of a full sphinx-build.
The user-visible differences are registered, one entry each,
on Differences from a Sphinx build —
read that page before switching a published site over.