Server-rendered Markdown with syntax highlighting
This entire block was parsed on a Cloudflare Worker using
marked, with code blocks highlighted
by shiki. The rendered HTML is streamed to the
browser — neither library ships to the client.
Why this is interesting
marked(~50KB) converts markdown to HTML.shiki(~2MB when you include themes and grammars) colorizes code blocks using real TextMate grammars — the same engine VSCode uses.
Doing syntax highlighting client-side means every visitor downloads shiki's WASM, grammars, and themes up front. Doing it on a server component means the browser only receives pre-styled HTML — no runtime cost, no bundle bloat.
Code blocks
import { createServerFn } from "@tanstack/react-start";
import { renderServerComponent } from "@tanstack/react-start-rsc";
import { Marked } from "marked";
import markedShiki from "marked-shiki";
import { createHighlighter } from "shiki";
const highlighter = await createHighlighter({
themes: ["github-dark"],
langs: ["tsx", "typescript", "bash", "json"],
});
const md = new Marked().use(
markedShiki({
highlight: (code, lang) =>
highlighter.codeToHtml(code, { lang: lang || "text", theme: "github-dark" }),
}),
);
const renderMd = createServerFn().handler(async () => {
const html = await md.parse(SAMPLE_MARKDOWN);
return { Result: await renderServerComponent(<div dangerouslySetInnerHTML={{ __html: html }} />) };
});
# No shiki in the browser:
curl https://tss-cf-ws-app.babsonmatt.workers.dev/server/markdown \
| grep -o 'shiki' # (empty)
{
"server": "parses + highlights",
"client": "receives pre-styled HTML",
"bundle_savings": "~2MB"
}
Try it yourself
- Open DevTools → Network → JS — search for 'shiki' or 'marked'. You won't find them.
- View source — the
<pre>blocks are already highlighted with inline styles. - Reload the page — this is recomputed each request on the worker.
The highlighter is created lazily and cached for the worker's lifetime, so only the first request pays the grammar-load cost.