Hugo¶
Hugo renders Markdown with Goldmark, not Python-Markdown, so the markwright extensions cannot run inside it.
Instead, the mw CLI brackets Hugo: the pre stage runs on your content before Hugo builds, and the post stage runs on Hugo's output HTML.
This is the same pre/render/post model described in the Pipeline Guide, with Hugo as the renderer in the middle.
This page mirrors the project's own end-to-end integration test, so the configuration and commands below are exactly what is exercised in CI.
How It Fits Together¶
flowchart LR
A[content/*.md] --> B[mw pre]
B --> C[hugo build]
C --> D[mw post]
D --> E[public/**/index.html]
The pre stage expands the embed directives and extracts the fence directives into mw-fence comments.
Hugo's Goldmark renderer turns the Markdown into HTML, passing the raw HTML and the comments through.
The post stage applies the fence labels and prefixes, resolves the in-code highlights, and injects the embed scripts.
Prerequisites¶
markwrightinstalled, so themwcommand is on your path. See the CLI Reference.- A Hugo site.
Hugo Configuration¶
Two settings in hugo.toml are required. Without them Hugo silently strips what markwright produces, with no error.
[markup.goldmark.renderer]
unsafe = true
[markup.highlight]
noClasses = false
unsafe = true lets Goldmark pass raw HTML through, which the expanded embeds and the mw-fence comment depend on.
This is Goldmark's only way to preserve them; the default drops every raw-HTML node and the marker comment along with it.
noClasses = false makes Chroma, Hugo's syntax highlighter, emit CSS classes rather than inline styles.
The fence styling and the line prefixes hook onto those classes, so class-based highlighting is required.
See Renderer Requirements for the full contract and what degrades if a requirement is unmet.
Running the Pipeline¶
For a single page, run the pre stage on the source, build, then run the post stage on the rendered page:
mw pre < content/posts/deploy.md > content/posts/deploy.md.tmp && mv content/posts/deploy.md.tmp content/posts/deploy.md
hugo
mw post < public/posts/deploy/index.html > public/posts/deploy/index.html.tmp && mv public/posts/deploy/index.html.tmp public/posts/deploy/index.html
The pre stage rewrites the content in place, Hugo builds it, and the post stage rewrites the rendered HTML in place.
To run a subset of the extensions, set enable or disable in a markwright.toml that both stages discover (see Configuration), or pass the same --exclude flags to both stages.
Wrapping It in a Build Script¶
A real site applies the pre stage to every content file before the build and the post stage to every rendered page after it:
#!/usr/bin/env bash
set -euo pipefail
# Pre-process every Markdown file in place.
find content -name '*.md' -print0 | while IFS= read -r -d '' file; do
mw pre < "$file" > "$file.tmp" && mv "$file.tmp" "$file"
done
hugo
# Post-process every rendered page in place.
find public -name '*.html' -print0 | while IFS= read -r -d '' file; do
mw post < "$file" > "$file.tmp" && mv "$file.tmp" "$file"
done
Run this against a copy of content/, or commit only the original source, since the pre stage rewrites the files.
markwright special-cases nothing about Hugo: it is a pair of stdin-to-stdout filters, and Hugo is one renderer in the middle.
What You Get¶
A source file looks like any other Markdown, with markwright syntax mixed in:
[youtube dQw4w9WgXcQ]
A <^>highlighted<^> word.
```command
[label deploy.sh]
./deploy.sh --prod
```
After the full pipeline:
[youtube dQw4w9WgXcQ]becomes a responsive iframe.- The prose
<^>highlighted<^>becomes<mark>highlighted</mark>. - The command fence renders with its
deploy.shlabel and a$prompt on each line, and thecommandinfo string is highlighted as Bash.
The mw-fence comment that carried the fence directives is consumed by the post stage and does not appear in the final HTML.