Shipping a tiny HTML parser
Most HTML parsers are big. That’s fine on a server,
but painful in a 1 MB edge worker. This post covers what we
learned building one that fits in ~20 KB of wasm.
Goals
- Never panic – on any input.
- Zero dependencies:
- no
regex - no
html5ever- (it’s great, just big)
- no
Forgiving recovery.
Unclosed
<p>and<li>tags are everywhere.
The core loop
The tree builder keeps an explicit stack, so 100k nested
<div>s can’t overflow it:
fn build(tokens: &[Token]) -> Dom {
let mut open = Vec::new();
for tok in tokens {
// `match` on every token kind
handle(&mut open, tok);
}
finish(open)
}
Numbers
| Parser | Size (gzip) | Deps |
|---|---|---|
| dom-tree-rs | 19.5 KB | 0 |
| html5ever | ~180 KB | 12 |
| a | b | pipes are escaped | |
Make it work, make it right, make it fast.
— Kent Beck
Read the API docs or open issues. Questions?