Skip to content

API

Most users only need conf.py settings and the command line. These modules are the public surface for extending or embedding the builder. This page is itself produced by the builder it documents.

Index

sphinx_vitepress.setup(app)Register the vitepress builder and its configuration values.
sphinx_vitepress.builder.VitepressBuilder(app)
sphinx_vitepress.translator.VitepressTranslator(...)Emit VitePress-flavored markdown instead of plain GitHub markdown.
sphinx_vitepress.escape.escape_vue(text)Escape text so Vue's template compiler treats it as plain prose.
sphinx_vitepress.prune.prune_virtual_page_links(...)Remove links to pages this builder does not generate.
sphinx_vitepress.sidebar.build_sidebar(env)Nested VitePress sidebar mirroring the root document's toctrees.
sphinx_vitepress.sidebar.build_nav(sidebar)Top navigation: home, then each sidebar group as a dropdown.
sphinx_vitepress.accents.resolve(value)Normalize vitepress_accent into {"light": stops, "dark": stops}.
sphinx_vitepress.accents.render_css(value)CSS defining the accent variables the bundled theme reads.
sphinx_vitepress.frontmatter.render(data)Render a frontmatter block, or "" when there is nothing to emit.
sphinx_vitepress.inventory.write_inventory(builder)Write objects.inv for the built site.
sphinx_vitepress.linkcode.make_resolver(base_url)Build a linkcode_resolve for a URL prefix ending in a ref.
sphinx_vitepress.versions.determine_bases(...)Deploy folder names for a build.
sphinx_vitepress.versions.collect_versions(...)Every deployed base (folders carrying a siteinfo.js), picker order: stable first, then dev, then releases newest-first.
sphinx_vitepress.deploy.run_deploy(source, ...)Build source into deploy_dir/<base> for every deploy base, then refresh versions.js and the root redirect.
sphinx_vitepress.nodejs.run_vitepress(site, ...)Run vitepress <command> (build/dev) in site; returns the exit code.

The extension

sphinx-vitepress: a Sphinx builder that renders documentation with VitePress.

setup functionsource
python
sphinx_vitepress.setup(app)

Register the vitepress builder and its configuration values.

  • Parameters: app (Sphinx)
  • Return type: dict[str, Any]

The builder

The vitepress Sphinx builder.

Subclasses sphinx-markdown-builder’s MarkdownBuilder (MIT, Liran Funaro): the base class provides outdated-doc tracking, .md writing, and get_target_uri (extension-suffixed links, which VitePress resolves). This class swaps in the VitePress translator; sidebar/config generation and objects.inv emission land here in finish() during M2/M4.

VitepressBuilder classsource
python
class sphinx_vitepress.builder.VitepressBuilder(app, env=None)
VitepressBuilder.name attribute
python
name = 'vitepress'

The builder’s name. This is the value used to select builders on the command line.

VitepressBuilder.epilog attribute
python
epilog = i'The VitePress markdown files are in %(outdir)s.'

The message emitted upon successful build completion. This can be a printf-style template string with the following keys: outdir, project

VitepressBuilder.default_translator_class attributesource
python
default_translator_class

alias of VitepressTranslator

VitepressBuilder.supported_linkcode attribute
python
supported_linkcode = 'vitepress'

sphinx.ext.linkcode gates its [source] links behind only:: html unless a builder claims support. Ours become “source” badges on the docstring cards, so opt in under this builder’s own tag.

VitepressBuilder.init methodsource
python
init()

Load necessary templates and perform initialization. The default implementation does nothing.

  • Return type: None
VitepressBuilder.get_outdated_docs methodsource
python
get_outdated_docs()

Return an iterable of output files that are outdated, or a string describing what an update build will build.

If the builder does not output individual files corresponding to source files, return a string here. If it does, return an iterable of those files that need to be written.

VitepressBuilder.write_doc methodsource
python
write_doc(docname, doctree)

Write one page, then prepend its configured frontmatter.

  • Parameters:
    • docname (str) – Sphinx name of the document being written.
    • doctree (docutils.nodes.document) – Its resolved doctree.
  • Return type: None
VitepressBuilder.finish methodsource
python
finish()

Finish the building process.

The default implementation does nothing.

  • Return type: None

VitePress-flavored markdown translator.

Subclasses sphinx-markdown-builder’s MarkdownTranslator (MIT, Liran Funaro) and overrides emission where VitePress markdown diverges from plain GitHub markdown: admonitions become ::: containers, text is Vue-safe escaped, headings carry explicit {#id} anchors, raw HTML is fenced off from Vue, and code-fence languages unknown to shiki are remapped.

The behavioral reference is DocumenterVitepress.jl’s src/writer.jl (local copy in the repo root); the rules are documented in DESIGN.md §B/§C.

ADMONITIONS data
python
sphinx_vitepress.translator.ADMONITIONS: dict[str, tuple[str, str]] = {'attention': ('warning', 'Attention'), 'caution': ('warning', 'Caution'), 'danger': ('danger', 'Danger'), 'error': ('danger', 'Error'), 'hint': ('tip', 'Hint'), 'important': ('warning', 'Important'), 'note': ('tip', 'Note'), 'seealso': ('info', 'See also'), 'tip': ('tip', 'Tip'), 'warning': ('warning', 'Warning')}

Sphinx/docutils admonition name -> (VitePress container kind, title). VitePress kinds are limited to: info | tip | warning | danger | details.

VIRTUAL_PAGES data
python
sphinx_vitepress.translator.VIRTUAL_PAGES = frozenset({'genindex', 'modindex', 'py-modindex', 'search'})

Pages the Sphinx HTML builders synthesize but that have no VitePress equivalent (its built-in local search replaces them). Nearly every Sphinx project’s index page links to these, and VitePress fails builds on dead links, so the links are emitted as plain text instead. Genuinely broken links are left alone, since VitePress should catch those.

VitepressTranslator classsource
python
class sphinx_vitepress.translator.VitepressTranslator(document, builder)

Emit VitePress-flavored markdown instead of plain GitHub markdown.

VitepressTranslator.visit_note methodsource
python
visit_note(_node)

Sphinx note directive.

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.visit_hint methodsource
python
visit_hint(_node)

Sphinx hint directive.

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.visit_important methodsource
python
visit_important(_node)

Sphinx important directive.

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.visit_warning methodsource
python
visit_warning(_node)

Sphinx warning directive.

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.visit_seealso methodsource
python
visit_seealso(_node)

Sphinx see also directive.

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.visit_admonition methodsource
python
visit_admonition(node)

Generic .. admonition:: Custom Title -> info container.

  • Parameters: node (Element)
  • Return type: None
VitepressTranslator.visit_versionmodified methodsource
python
visit_versionmodified(node)

Node for version change entries. Currently used for “versionadded”, “versionchanged” and “deprecated” directives. Type will hold something like ‘deprecated’

  • Parameters: node (Element)
  • Return type: None
VitepressTranslator.visit_desc_signature methodsource
python
visit_desc_signature(node)

API object signature: always anchored so cross-references resolve.

  • Parameters: node (Element)
  • Return type: None
VitepressTranslator.visit_math_block methodsource
python
visit_math_block(_node)

docutils math block

  • Parameters: _node (Element)
  • Return type: None
VitepressTranslator.depart_math_block methodsource
python
depart_math_block(_node)

docutils math block

  • Parameters: _node (Element)
  • Return type: None

Escaping and pruning

Vue-safe escaping for VitePress markdown output.

VitePress compiles every markdown page as a Vue template, so three things in plain prose are hazards that classic markdown escaping does not cover:

  • < / > start HTML/component tags. dict[str, int] is safe but Callable<T>-style text or a stray <Response> is a build error.
  • {{ starts a Vue interpolation, so {{ placeholder }} text either errors or silently evaluates.
  • Fenced code blocks are auto-v-pre by VitePress and need no treatment; inline code is handled separately by the translator (wrapped in <span v-pre> only when it contains {{).

Following DocumenterVitepress.jl’s writer (writer.jl ~L1144), & is deliberately NOT escaped: VitePress copies heading text verbatim into per-page search JSON, and double-escaping there reads worse than the rare literal &lt; a user may type.

escape_vue functionsource
python
sphinx_vitepress.escape.escape_vue(text)

Escape text so Vue’s template compiler treats it as plain prose.

  • Parameters: text (str)
  • Return type: str

Drop navigation that points at pages VitePress does not have.

Nearly every Sphinx project ends its index with the stock “Indices and tables” block linking to genindex/modindex/search. Only the HTML builders synthesize those pages, so in a VitePress site the block is a heading over two or three inert bullets.

Whole list items (or paragraphs) that consist of nothing but such a link are removed, along with any list or section left empty as a result. A link used inside a sentence is left in place. The translator renders it as plain text, so the sentence still reads correctly.

prune_virtual_page_links functionsource
python
sphinx_vitepress.prune.prune_virtual_page_links(doctree, suffix)

Remove links to pages this builder does not generate.

  • Parameters:
    • doctree (docutils.nodes.document) – The resolved doctree, modified in place.
    • suffix (str) – The URI suffix internal links carry, so a target can be matched against the virtual page names.
  • Return type: None

Site generation

Sidebar and nav generation from Sphinx’s toctree structure.

Each .. toctree:: becomes a VitePress sidebar group: its :caption: is the group heading and its entries are the items, recursing into the toctrees those entries declare. Captioned groups also become nav dropdowns, which is how a multi-section manual reads as a menu rather than a flat row.

Titles come from the toctree entries themselves where the author supplied one, and from env.titles otherwise.

build_sidebar functionsource
python
sphinx_vitepress.sidebar.build_sidebar(env)

Nested VitePress sidebar mirroring the root document’s toctrees.

  • Parameters: env (BuildEnvironment)
  • Return type: list[dict[str, Any]]
build_nav functionsource
python
sphinx_vitepress.sidebar.build_nav(sidebar)

Top navigation: home, then each sidebar group as a dropdown.

A captioned group (one with items but no page of its own) becomes a VitePress nav dropdown; a plain page becomes a direct link.

User-selectable accent palettes.

The bundled theme paints links, buttons, active nav items and hero gradients from four accent stops, supplied as CSS variables. Projects pick a palette with vitepress_accent: either a preset name (sampled from the matplotlib colormap of the same name, so the site can match the figures in it) or explicit colors.

Stops run dark to light and are used by role, not position, so both themes stay readable: light mode links use deep (high contrast on white) while dark mode uses bright/glow.

PRESETS data
python
sphinx_vitepress.accents.PRESETS: dict[str, tuple[str, str, str, str]] = {'afmhot': ('#a93000', '#e66600', '#ff8000', '#ffb333'), 'blue': ('#0060a8', '#0087d7', '#0c9ff4', '#5fd7ff'), 'cividis': ('#00204d', '#31446b', '#666970', '#a69d75'), 'inferno': ('#781c6d', '#bb3754', '#ed6925', '#fbb61a'), 'magma': ('#6b1d81', '#b63679', '#f1605d', '#fe9f6d'), 'ocean': ('#005b7f', '#0087b3', '#00a9c4', '#57cfd6'), 'plasma': ('#6a00a8', '#b12a90', '#e16462', '#fca636'), 'viridis': ('#3b528b', '#21918c', '#5ec962', '#a0da39')}

name -> (deep, mid, bright, glow), sampled from matplotlib colormaps.

resolve functionsource
python
sphinx_vitepress.accents.resolve(value)

Normalize vitepress_accent into {"light": stops, "dark": stops}.

Accepts a preset name, a single hex color, a 4-color sequence, or a mapping with light/dark keys holding any of those.

render_css functionsource
python
sphinx_vitepress.accents.render_css(value)

CSS defining the accent variables the bundled theme reads.

  • Parameters: value (Any)
  • Return type: str

Per-page VitePress frontmatter.

VitePress reads a YAML block at the top of each page; the important use is layout: home, which turns a page into the hero/features landing page.

The block is emitted as JSON, which is valid YAML (a flow mapping), so no YAML emitter is needed and no escaping bugs are possible. VitePress’s frontmatter parser accepts it.

render functionsource
python
sphinx_vitepress.frontmatter.render(data)

Render a frontmatter block, or "" when there is nothing to emit.

Emit a Sphinx objects.inv for the built VitePress site.

Only Sphinx’s HTML builders write an inventory natively, so we do it ourselves: every documented object (py:* roles, std:doc pages, std:label targets) becomes resolvable FROM other Sphinx projects via ordinary intersphinx. The file goes to public/ under the source root (VitePress’s static-assets directory), which is copied verbatim to the site root, exactly where intersphinx looks (<site>/objects.inv).

write_inventory functionsource
python
sphinx_vitepress.inventory.write_inventory(builder)

Write objects.inv for the built site.

Link each documented object to the exact lines that define it.

sphinx.ext.linkcode asks the project for a URL per object but leaves the work of finding one to conf.py, so most projects either copy the same twenty lines of inspect handling or settle for linking to the top of a module. Setting vitepress_source_url installs a resolver that finds the object’s file and line range and produces, for example:

python
https://github.com/you/project/blob/main/src/pkg/core.py#L42-L57

The file path is taken relative to the git working tree the source lives in, so it matches the repository layout without further configuration.

make_resolver functionsource
python
sphinx_vitepress.linkcode.make_resolver(base_url)

Build a linkcode_resolve for a URL prefix ending in a ref.

  • Parameters: base_url (str) – Everything up to the repository-relative path, for example https://github.com/you/project/blob/main. Pin a commit rather than a branch if the links should keep pointing at the code the documentation was built from.
  • Returns: A resolver suitable for linkcode_resolve in conf.py.
  • Return type: callable

Deployment

Versioned-docs bookkeeping, ported from DocumenterVitepress.jl’s model.

A deployed site is a tree of independent VitePress builds:

python
gh-pages/
  stable/     # full build, base=/repo/stable/
  v1/         # full build, base=/repo/v1/
  dev/        # full build from the dev branch
  versions.js # var DOC_VERSIONS = [...]  (read by VersionPicker.vue)
  index.html  # redirect to stable/ (or dev/ if no release yet)

Each build folder carries a siteinfo.js declaring its own version; the root versions.js is regenerated by scanning for those files, so old versions keep working without being rebuilt.

determine_bases functionsource
python
sphinx_vitepress.versions.determine_bases(version, <abbr title="Keyword-only parameters separator (PEP 3102)">*</abbr>, keep='breaking', devurl='dev')

Deploy folder names for a build.

None means a dev build -> [devurl]. A release tag like v1.2.3 expands according to keep:

  • "breaking" (default): ["v1", "stable"] (["v0.2", "stable"] for 0.x, where the minor is the breaking line)
  • "minor": ["v1.2", "v1", "stable"]
  • "patch": ["v1.2.3", "v1.2", "v1", "stable"]
write_siteinfo functionsource
python
sphinx_vitepress.versions.write_siteinfo(base_dir, name)

Stamp a build folder with its own version name.

  • Parameters:
  • Return type: None
collect_versions functionsource
python
sphinx_vitepress.versions.collect_versions(deploy_dir, <abbr title="Keyword-only parameters separator (PEP 3102)">*</abbr>, devurl='dev')

Every deployed base (folders carrying a siteinfo.js), picker order: stable first, then dev, then releases newest-first.

Assemble a versioned deploy tree (the DocumenterVitepress model).

Each base gets its own full VitePress build (asset URLs embed base, so folders cannot be copies of one another). The markdown workdir is reused across bases, so npm install runs at most once per deploy.

Pushing the resulting tree to gh-pages is left to CI (see .github/workflows/docs.yml for the reference workflow).

run_deploy functionsource
python
sphinx_vitepress.deploy.run_deploy(source, deploy_dir, <abbr title="Keyword-only parameters separator (PEP 3102)">*</abbr>, version, repo_base='/', keep='breaking', devurl='dev')

Build source into deploy_dir/<base> for every deploy base, then refresh versions.js and the root redirect. Returns an exit code.

  • Parameters:
  • Return type: int

Locate and drive the Node toolchain.

Only the CLI touches Node. The Sphinx builder itself always finishes with markdown + config on disk, so docs can be generated on machines without Node and built elsewhere.

NodeToolchainError exceptionsource
python
exception sphinx_vitepress.nodejs.NodeToolchainError

A required Node tool is missing from PATH.

ensure_node_modules functionsource
python
sphinx_vitepress.nodejs.ensure_node_modules(site)

Install the site’s Node dependencies if they are missing or stale.

The install is repeated when package.json changes, so upgrading sphinx-vitepress (which may pin a newer VitePress) does not keep building an existing output directory against the old dependencies.

  • Parameters: site (Path)
  • Return type: None
run_vitepress functionsource
python
sphinx_vitepress.nodejs.run_vitepress(site, command, extra=None)

Run vitepress <command> (build/dev) in site; returns the exit code.