package soupault

  1. Overview
  2. Docs
Static website generator based on HTML element tree rewriting

Install

dune-project
 Dependency

Authors

Maintainers

Sources

5.2.0.tar.gz
sha512=ad490894f052c0bedd1f2687afc0f042af377ed751002599b8d03a2335bd4ffe23db339c98cc78bb1406071f5c38b292afea8624f9390a96d5582d877c482fbb

Description

A website generator that works with page element trees rather than text and allows you to manipulate pages and retrieve metadata from existing HTML using arbitrary CSS selectors.

With soupault you can:

  • Generate ToC and footnotes.
  • Insert file content or an HTML snippet in any element.
  • Preprocess element content with external programs (e.g. run <pre> tags through a highlighter)
  • Extract page metadata (think microformats) and render it using a Jingoo template, a Lua plugin, or an external script.

Soupault is extensible with Lua (2.5) plugins and provides an API for element tree manipulation, similar to web browsers.

The website generator mode is optional, you can use it as post-processor for existing sites.

Published: 25 Nov 2025

README

soupault

maintenance-status Build GitHub all releases

Soupault is an HTML manipulation tool. It can be a static site generator or an HTML (post-)processor for existing websites and allows you to define your own content model and page processing rules using built-in actions, external executables, templates, or Lua plugins.

Soupault works with the HTML element tree of the page, so it can do many things that traditionally could be done with client-side JS: inject new HTML into existing complete pages, create a table of contents that respects and uses id's of HTML headings and more.

It also doesn't use front matter but extracts metadata from HTML instead: you tell it what to extract using CSS3 selectors, so even hand-written static pages can be indexed rather than treated as opaque assets.

For example, here's what a content model for a blog may look like:

# Post title
[index.fields.title]
  # Try to find <h1 id="post-title">,
  # else use the first <h1> 
  selector = ["h1#post-title", "h1"]

  # Fail the build if post title cannot be found
  required = true

# Post excerpt
[index.fields.excerpt]
  # Use <p id="post-excerpt"> if a page has it,
  # else use the first paragraph.
  # This allows using a paragraph other than the first one
  # as the post excerpt.
  selector = ["p#post-excerpt", "p"]

# Post date
[index.fields.date]
  selector = ["time#post-date", "time"]

  # Extract the datetime="" attribute from the <time> element,
  # if it's set.
  extract_attribute = "datetime"

  # If there's no datetime attribute in <time>,
  # then use that element's content
  fallback_to_content = true

Extracted metadata can then be rendered and injected into pages:

[index.views.blog]
  # Insert rendered data into the element that matches "#blog-index" CSS selector.
  index_selector = "#blog-index"
  index_item_template = """
    <h2><a href="{{url}}">{{title}}</a></h2>
    <p><strong>Last update:</strong> {{date}}.</p>
    <p>{{excerpt}}</p>
    <a href="{{url}}">Read more</a>
  """

Soupault is...

  • Durable and easy to upgrade or roll back: it's available as a statically-linked binary with no dependencies.
  • Extensible: you can bring your own page preprocessors (e.g., Markdown to HTML convertors), define asset processors (e.g., a Sass/Less compiler, an image optimizer), pipe HTML elements through external programs, and load Lua plugins.
  • Flexible: most options are configurable, most built-in features can be reimplemented as Lua plugins, and there are page processing hooks.

Soupault is named after Philippe Soupault, a French dadaist and surrealist writer and poet, because it uses lambdasoup library to work with tag soups.

Visit soupault.net for details.

For support and discussion, write a message to the mailing list.

Installation

Prebuilt binaries are available for Linux (x86-64 and Aarch64), Windows, and macOS (x86-64). You can download them from https://files.baturin.org/software/soupault and from GitHub releases (https://github.com/PataphysicalSociety/soupault/releases).

You can verify release archive integrity using this minisign key:

minisign -VP RWRfW+gkhk/+iA7dOUtTio6G6KeJCiAEp4Zfozw7eqv2shN90+5z20Cy -m <file>

You can also install stable release versions from OPAM:

opam install soupault

Finally, you can build the latest development version with:

opam pin add git+https://github.com/PataphysicalSociety/soupault

To build static binaries, you need to install OCaml with musl runtime, then use the static Dune profile:

# For OCaml 5.3.0, adjust for your desired version
opam switch create 5.3.0-musl ocaml-variants.5.3.0+options ocaml-option-musl ocaml-option-static
opam switch 5.3.0-musl

# Build static binaries
dune build --profile=static

Contributing

Bug reports and patches are always welcome. Feature requests and new features are also welcome, but please consider discussing them with the maintainer first.

You can contribute either through GitHub or through Codeberg.

Dependencies (22)

  1. cmarkit >= "0.3.0"
  2. lua-ml >= "0.9.3"
  3. tsort >= "2.2.0"
  4. digestif >= "0.7.3"
  5. camomile >= "2.0.0"
  6. jingoo >= "1.4.2"
  7. base64 >= "3.0.0"
  8. spelll >= "0.4"
  9. odate >= "0.6"
  10. re >= "1.9.0"
  11. csv >= "2.4"
  12. yaml >= "2.0.0"
  13. ezjsonm >= "1.2.0"
  14. otoml >= "1.0.5"
  15. markup >= "1.0.0-1"
  16. lambdasoup >= "1.1.1"
  17. fmt >= "0.8.9"
  18. logs >= "0.7.0"
  19. fileutils >= "0.6.3"
  20. containers >= "3.9"
  21. dune >= "2.0.0"
  22. ocaml >= "5.3.0"

Dev Dependencies

None

Used by

None

Conflicts (1)

  1. result < "1.5"