Skip to content

Markdown rendering

Converts markdown documents to HTML using marked, then compresses the output with Brotli. A straightforward transform pipeline — parse, render, compress — that shows how well workers handle chained operations.

The host generates markdown documents. Both the host and worker paths parse the markdown, render HTML, then Brotli-compress the result. Compressed byte totals are compared for parity before the benchmark runs.

Three files:

  • run_markdown_to_html.ts — a small runnable example that compares host and worker output
  • bench_markdown_to_html.ts — the optional host-vs-worker benchmark
  • utils.ts — markdown rendering, compression tasks, and shared helpers
deno.sh
deno add --npm jsr:@vixeny/knitting
deno add npm:marked npm:mitata
bun.sh
bun src/run_markdown_to_html.ts --threads 2

Example markdown in:

# Knitting markdown example
This example renders markdown on the host and in a worker.
## Checklist
- Parse markdown
- Render HTML
- Compare outputs

HTML out:

<h1>Knitting markdown example</h1>
<p>This example renders markdown on the host and in a worker.</p>
<h2>Checklist</h2>
...
bun.sh
bun src/bench_markdown_to_html.ts

Expected output:

byte parity check: host=18,720 worker=18,720 OK match
benchmark avg (ns) min ... max (ns)
host 32,100 29,400 ... 41,200
knitting 17,800 15,600 ... 24,300
run_markdown_to_html.ts
import { createPool, isMain } from "@vixeny/knitting";
import { markdownToHtml, markdownToHtmlHost } from "./utils.ts";
function intArg(name: string, fallback: number): number {
const i = process.argv.indexOf(`--${name}`);
if (i !== -1 && i + 1 < process.argv.length) {
const value = Number(process.argv[i + 1]);
if (Number.isFinite(value) && value > 0) return Math.floor(value);
}
return fallback;
}
const THREADS = intArg("threads", 2);
const SAMPLE_MARKDOWN = [
"# Knitting markdown example",
"",
"This example renders markdown on the host and in a worker.",
"",
"## Checklist",
"",
"- Parse markdown",
"- Render HTML",
"- Compare outputs",
"",
"```ts",
"const status = 'ready';",
"```",
].join("\n");
async function main() {
const hostHtml = markdownToHtmlHost(SAMPLE_MARKDOWN);
const pool = createPool({ threads: THREADS })({ markdownToHtml });
try {
const workerHtml = await pool.call.markdownToHtml(SAMPLE_MARKDOWN);
console.log("Markdown -> HTML example");
console.log("threads :", THREADS);
console.log("same html :", hostHtml === workerHtml);
console.log("html length :", workerHtml.length);
console.log("html preview :", workerHtml.slice(0, 120), "...");
} finally {
pool.shutdown();
}
}
if (isMain) {
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
}

This is the simplest rendering example — no component tree, no JSX, just string in, string out. It’s a good reference if you want to understand the worker pattern without the React SSR complexity. The same approach works for any transform chain: parse input, process it, compress or encode the result.