Skip to content

Commit 266bccc

Browse files
committed
Optionally pre-render the Graphviz diagrams
Since the WebAssembly version of Graphviz is not exactly light (1.4MB at the time of writing), and since it is a waste to let everybody re-render the SVG client-side over and over again even though the diagram's definition hasn't changed, let's add a script that performs that rendering "on the server side" (more precisely: during deployment). This script takes no arguments and post-processes the output of Hugo in `public/`. For performance reasons, it requires the list of files that contain Graphviz diagrams. With this here site, it might not matter much because there are only a handful images here. However, I want to reuse the same method on git-scm.com where there _are_ thousands of files that do not contain any Graphviz diagrams, and therefore it is a necessary optimization to process only the files that _do_ contain Graphviz diagrams. To get that list, a new layout and page are added that Hugo processes, identifyng said list of files and writing the result to `public/diagram-list.html`. Since this script runs via Node.JS and therefore lacks the convenient built-in HTML parser of browser-based JavaScript engines, a prerequisite is now to run `npm install` so that the `node-html-parser` package is available. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent af226bb commit 266bccc

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

content/diagram-list.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
layout: diagram-list
3+
---

layouts/diagram-list.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<pre>
2+
{{- range .Site.RegularPages -}}
3+
{{- if in .RawContent "```graphviz" -}}
4+
public{{ .Path }}.html
5+
{{- end }}
6+
{{ end -}}
7+
</pre>

package-lock.json

Lines changed: 145 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"node-html-parser": "^7.0.1"
4+
}
5+
}

script/graphviz-ssr.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env node
2+
3+
import { readFileSync, writeFileSync } from "node:fs"
4+
import { parse } from "node-html-parser"
5+
import Viz from "../static/js/viz-global.js"
6+
7+
/*
8+
* This script post-processes the site as generated via Hugo, replacing the
9+
* `<pre class="graphviz">` elements with inline `<svg>` ones, pre-rendered
10+
* via `viz-js`.
11+
*/
12+
;(async () => {
13+
const opts = { format: "svg" }
14+
for (const path of readFileSync("public/diagram-list.html", "utf-8")
15+
.split("\n")
16+
.filter((x) => x.startsWith("public/"))) {
17+
const contents = readFileSync(path, "utf-8")
18+
const html = parse(contents)
19+
const vizImport = html.querySelector('script[src$="viz-global.js"]')
20+
if (!vizImport) {
21+
console.error(`No 'viz-global.js' import found in ${path}; skipping`)
22+
continue
23+
}
24+
vizImport.nextElementSibling.remove() // remove the inline script
25+
vizImport.remove() // remove the import
26+
27+
for (const pre of html.querySelectorAll("pre.graphviz")) {
28+
const svg = (await Viz.instance()).renderString(pre.textContent, opts)
29+
pre.replaceWith(svg.substring(svg.indexOf("<svg")))
30+
}
31+
console.log(`Rewriting ${path}`)
32+
writeFileSync(`${path}`, html.toString())
33+
}
34+
})().catch((e) => {
35+
console.error(e)
36+
process.exitCode = 1
37+
})

0 commit comments

Comments
 (0)