v0.14.0 - HTML + print-CSS input path
The release that adds a second front door to the engine: @formepdf/html, an HTML + print-CSS input path — "Satori for paginated documents." Write HTML with @page rules, feed it to renderHtml() or the forme-html CLI, get a paginated, deterministic PDF from the same Rust engine that renders JSX. No headless browser anywhere in the pipeline. Also: a layout-shape contract change for tables, four engine layout fixes, and HTML preview support across the renderer, CLI dev server, and VS Code extension.
Added
@formepdf/html — first public release. The engine compiled to WASM behind an HTML front end:
- Stylesheets, not just inline styles: type/class/id/universal selectors, compounds, descendant/child combinators, grouping, the
:nth-childand:nth-of-typefamilies — with full cascade semantics including!important. - Paged media:
@pagesize and margins,:firstvariants, margin boxes withcounter(page)/counter(pages),break-*(plus legacypage-break-*aliases),orphans/widows, and@mediamedia-type evaluation — print is the native media type. - Tables:
border-collapseemulation,<thead>repetition across page breaks, colspan/rowspan,vertical-align(and legacyvalign). - Typography: justified text,
text-transform,letter-spacing, and provided fonts viaoptions.fonts/--font, with a documented migration recipe for web fonts. - The warnings contract: everything outside the supported subset is named — skipped stylesheet links,
@imports,@font-facefamilies, unsupported properties. Nothing is silently dropped.
Determinism is load-bearing: CI renders the fixture corpus through both the native binary and the WASM build and requires byte-identical PDFs.
Engine — @page :first, vertical-align, min/max constraints. Page one can carry its own PageConfig (size, margins, fixed-element filtering via First/NotFirst); table cells align content top/middle/bottom; and max-width/min-width/min-height now clamp properly — auto width + finite max-width + auto margins is the centered-column idiom, and it works.
Renderer / CLI / VS Code — HTML preview everywhere. renderHtmlFromFile / renderHtmlFromSource in @formepdf/renderer return the same PDF-bytes + LayoutInfo shape as the JSX pipeline, so every preview surface lights up unchanged: the CLI dev server and the VS Code extension both live-preview .html files with the full component tree, inspector, and layout overlays. The extension now bundles two WASM snapshots and hash-verifies both against their package sources at build time.
⚠️ Layout-shape contract change — Table wrapper node
ElementNodeType gains 'Table'. Layout used to unwrap <Table> into loose sibling TableRow nodes; it now emits a Table container element per page fragment with the rows nested inside. Two reasons: table-level border/background finally have a paint target, and structural consumers (tagged PDF /Table, extractors) get a real table node. If you walk LayoutInfo for TableRow nodes directly, look inside Table wrappers now — or use getTableRows() from @formepdf/core/layout, which handles both shapes (loose rows from stored pre-0.14 layouts still return).
Fixed
- Runs-based text measured zero intrinsic width.
measure_intrinsic_widthignoredruns(and measured leafHeadings as 0, and whole multi-line strings instead of the widest line) — flex rows could collapse styled text to one character per line. col_spanwas ignored when indexing column widths. Every cell after a colspan cell sat one column too far left; the spanning cell now consumes its columns' combined width in both layout and row-height measurement.wrap: falseon tables was silently ignored. Row-by-row pagination never consulted breakability; an unbreakable table that fits a fresh page now moves there whole (break-inside: avoidin the HTML path).- A flex line taller than the page emitted a blank leading page before overflowing anyway; the break check now skips when the current page is empty.
Docker images — security refresh
formepdf/forme and formepdf/rasterizer are published again at 0.14.0 (multi-arch, amd64 + arm64), rejoining the shared version line after being frozen at 0.10.5. Rebuilt on Alpine/musl with PDFium chromium/8021 — Docker Scout reports zero vulnerable packages on both, and the server image dropped from 150 MB to 24 MB.
Full changelog
@formepdf/html · engine · @formepdf/core · @formepdf/renderer · vscode · @formepdf/svelte
All other @formepdf/* packages, the forme-pdf crate on crates.io, the Python SDK, and the Go SDK got version-alignment bumps to 0.14.0.