Rendering LaTeX in Hakyll
What is Hakyll?
Hakyll is a Haskell library for generating static sites, aimed at small-to-medium sites and personal blogs. It is highly configurable and uses an xmonad-like DSL for configuration.
When I first put this site together, I wanted more control over how posts were rendered than plain Markdown gave me. LaTeX offered exactly the expressiveness I needed — math, theorem environments, custom macros — while still compiling down to clean HTML.
Markdown vs. LaTeX: when to reach for each
Hakyll happily renders both, so the question is what you need:
-
Markdown is perfect for prose: headers, lists, links, and fenced code blocks with syntax highlighting.
-
LaTeX wins when you need real mathematical notation, numbered theorem-style environments, or macros you want to reuse across posts.
The good news: because both go through pandoc, you can mix and match per file.
Rendering Markdown
Hakyll is integrated with pandoc, so Markdown with proper formatting "just
works". Headers double as a table of contents when toc is set to true:
# Header Text ## Subheader Text
Fenced blocks get syntax highlighting:
```haskell main :: IO () main = putStrLn "Hello, world!" ```
Compiling Markdown to HTML
Place your posts in a directory (say posts/) and compile:
match "posts/*.md" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= relativizeUrls
Rendering LaTeX
TeX files are supported too, but the pipeline differs slightly. In its simplest
form, a .tex source looks like:
\title{Some Title}
\section{Some Section}
Some text.
Theorem environments
This is where LaTeX earns its keep. Define reusable environments once:
\newtheorem{theorem}{Theorem}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{lemma}[theorem]{Lemma}
\theoremstyle{definition}
\newtheorem{definition}[theorem]{Definition}
\theoremstyle{remark}
\newtheorem{remark}{Remark}
…then use them with real mathematical notation inside:
\begin{definition}[Prime numbers]
A \emph{prime number} is a natural number greater than 1 that
has no positive divisors other than 1 and itself.
\end{definition}
\begin{lemma}[Infinitude of primes]
There are infinitely many prime numbers.
\end{lemma}
Compiling LaTeX to HTML
The trick is to run pandoc as a filter, going from latex to html5 and asking
it to emit MathJax-friendly markup with --mathjax:
match "*/*.tex" $ do
route $ constRoute "*/index.html"
compile $ getResourceString
>>= withItemBody (unixFilter "pandoc"
["-f", "latex", "-t", "html5", "--mathjax"])
>>= relativizeUrls
Making the math actually render
--mathjax only tells pandoc to emit math in a form a JavaScript typesetter can
read — you still need to load the typesetter in your template. Drop
MathJax (or the lighter
KaTeX) into your HTML <head>:
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
async></script>
With that in place, pair a little CSS for the theorem environments with MathJax for the formulas, and the LaTeX above renders like this:
Rendered output
The boxes come from CSS targeting the environment class names pandoc emits; the
equations are typeset live by MathJax from the \(…\) and \[…\] delimiters.
Wrapping up
Hakyll's pandoc integration makes LaTeX a first-class citizen alongside
Markdown: write prose in Markdown, switch to .tex when you need theorems and
math, and let a single MathJax include tie the formulas together. Even though
this site now runs on Verso, the same pandoc-as-a-filter idea carries over to
just about any static-site generator.
