html-pdf-engine
v1.1.2
Published
Lightweight, deterministic HTML/CSS-to-PDF engine for structured documents — zero runtime dependencies, pure TypeScript
Maintainers
Readme
html-pdf-engine
Lightweight, dependency-free HTML & CSS to PDF engine for Node.js, designed for invoices, receipts, reports, and structured documents.
Overview
html-pdf-engine is a pure TypeScript library that compiles HTML and CSS directly into PDF 1.7 binary documents in Node.js with zero runtime dependencies.
Scope & Rendering Model
html-pdf-engine is not a browser runtime (such as Chromium, WebKit, or Firefox). It is designed specifically for fast, deterministic server-side document rendering.
- No Browser Process: Generates PDF binary streams natively without invoking Chromium or external subprocesses.
- No JavaScript Execution:
<script>tags are parsed and visually hidden to guarantee security and deterministic execution. - Default Offline Security & Opt-In Asset Resolution: By default, the engine makes zero implicit network requests for external stylesheets, images, or web fonts. Applications can explicitly configure an opt-in
AssetResolver(including the built-increateNetworkAssetResolver()) with SSRF protection, timeout, and byte limits. - Targeted Document CSS Subset: Implements a CSS subset tailored for structured business layouts (Block, Inline, Table, Flexbox with wrapping, CSS Grid, CSS Custom Properties /
var(), Media Queries,position: relative / absolute / fixed, andz-indexpaint ordering).
Key Technical Highlights
- Zero Runtime Dependencies: Built entirely from scratch in TypeScript, relying solely on Node's native
node:zlibfor FlateDecode stream compression. - Node.js Requirement: Requires Node.js
>= 18.0.0. - Package Size: ~169.1 kB packed tarball (~945.0 kB unpacked, verified via
npm pack --dry-run). - Low-Millisecond Rendering: Generates structured document PDFs in low milliseconds with minimal memory overhead.
- TrueType Font Subsetting: Embeds only the used glyphs for custom
.ttffonts into Type0/CIDFontType2 objects with/ToUnicodeCMaps, minimizing output file size. - 1D/2D Modern Layout: 1D Flexbox (with
flex-wrap) and 2D CSS Grid support for complex document structures. - CSS Custom Properties & Variables: Supports
--custom-propertydefinitions,var()resolution, fallbacks, inheritance, nested references, and cycle detection. - CSS
@mediaQueries: Evaluates@media print,@media all, and width-based(min-width: ...)/(max-width: ...)queries against page content width. - CSS Sizing Constraints:
min-width,max-width,min-height,max-heightsupported across block boxes, images, table cells, flex/grid items, and positioned elements. - PDF Container Clipping (
overflow: hidden): PDF-native graphics clipping (q/Q/W) for content containment, overflow-aware pagination suppression, and link annotation cropping. - CSS
@pageRule Support: Parses@page { size: A4 landscape; margin: 20pt; }at-rules for document dimensions, orientation, and margins directly from CSS. - Practical CSS Positioning & Stacking:
position: relative,position: absolute, andposition: fixed(repeats element across pages for headers/footers/watermarks) withz-indexpaint ordering. - Advanced PDF Pagination: Modern
break-before: page,break-after: page,break-inside: avoid, and legacypage-break-*aliases for reliable document page fragmentation across Block, Table, Flexbox, and Grid layouts. - Clickable PDF Hyperlinks & Internal Anchors: Renders external URLs (
http://,https://,mailto:,tel:) into/URIannotations and internal fragment links (href="#anchor") into PDF/GoTodestinations. - PDF Document Metadata & Preferences: Embeds metadata into PDF
/Infodictionaries (Title,Author,Subject,Keywords,Creator,Producer), catalog/ViewerPreferences,/Lang, and/PageLabels.
Installation
npm install html-pdf-engineOr using yarn or pnpm:
yarn add html-pdf-engine
# or
pnpm add html-pdf-engineBasic Usage Example
import { HtmlToPdf } from "html-pdf-engine";
import * as fs from "node:fs";
const pdfBuffer = await HtmlToPdf.generateBuffer({
html: `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Helvetica, sans-serif; padding: 20px; }
h1 { color: #0284c7; font-size: 24pt; margin-bottom: 8px; }
p { color: #334155; font-size: 11pt; line-height: 1.5; }
</style>
</head>
<body>
<h1>Order Confirmation</h1>
<p>Thank you for your purchase. Your order has been processed successfully.</p>
</body>
</html>
`,
page: "A4",
orientation: "portrait",
margin: { top: 36, right: 36, bottom: 36, left: 36 },
});
fs.writeFileSync("./confirmation.pdf", pdfBuffer);Real-World Invoice Example
This example demonstrates dynamic header layout using Flexbox, summary calculations using CSS Grid, embedded image asset mapping, metadata, and page footers:
import { HtmlToPdf } from "html-pdf-engine";
import * as fs from "node:fs";
const logoBuffer = fs.readFileSync("./assets/logo.png");
const pdfBuffer = await HtmlToPdf.generateBuffer({
html: `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Helvetica, sans-serif; margin: 0; color: #1e293b; }
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #0284c7; padding-bottom: 12px; margin-bottom: 20px; }
.title { color: #0369a1; font-size: 22pt; margin: 0; }
.meta { font-size: 10pt; color: #64748b; text-align: right; }
.grid-summary { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 10px; margin-top: 20px; font-size: 10pt; }
.grid-header { font-weight: bold; background-color: #f1f5f9; padding: 8px; }
.grid-cell { padding: 8px; border-bottom: 1px solid #e2e8f0; }
.total-box { margin-top: 20px; text-align: right; font-size: 12pt; font-weight: bold; color: #0f172a; }
a { color: #0284c7; text-decoration: underline; }
</style>
</head>
<body>
<div class="header">
<div>
<img src="logo.png" width="120" />
<h1 class="title">INVOICE #INV-2026-892</h1>
</div>
<div class="meta">
<strong>Date:</strong> August 15, 2026<br/>
<strong>Due Date:</strong> September 15, 2026<br/>
<strong>Support:</strong> <a href="mailto:[email protected]">[email protected]</a>
</div>
</div>
<div class="grid-summary">
<div class="grid-header">Service Description</div>
<div class="grid-header">Hours</div>
<div class="grid-header">Amount</div>
<div class="grid-cell">Cloud Architecture Advisory</div>
<div class="grid-cell">12 hrs</div>
<div class="grid-cell">$1,800.00</div>
<div class="grid-cell">PDF Generation Engine Setup</div>
<div class="grid-cell">8 hrs</div>
<div class="grid-cell">$1,200.00</div>
</div>
<div class="total-box">
Total Due: $3,000.00
</div>
</body>
</html>
`,
images: {
"logo.png": logoBuffer,
},
meta: {
title: "Invoice INV-2026-892",
author: "Acme Consulting Services",
subject: "Monthly Statement",
keywords: "invoice, consulting, cloud",
},
footer: {
text: "Page {{pageNumber}} of {{totalPages}}",
align: "center",
showDividerLine: true,
},
});
fs.writeFileSync("./invoice.pdf", pdfBuffer);Asset Handling Guide
By default, html-pdf-engine operates entirely server-side and performs no implicit network requests for external HTTP/HTTPS assets. Applications can supply assets via options.images / options.fonts, local filesystem paths, base64 data URLs, or an opt-in AssetResolver.
Remote Asset Loading (Opt-In)
For environments requiring dynamic remote asset resolution, html-pdf-engine provides the AssetResolver interface and a built-in createNetworkAssetResolver() factory with strict SSRF protections and resource limits:
import { HtmlToPdf, createNetworkAssetResolver } from "html-pdf-engine";
const assetResolver = createNetworkAssetResolver({
maxSizeBytes: 5 * 1024 * 1024, // 5 MB limit
timeoutMs: 3000,
maxRedirects: 3,
allowPrivateIPs: false, // SSRF protection: blocks local/private IP ranges (default)
});
const pdf = await HtmlToPdf.generateBuffer({
html: '<img src="https://cdn.example.com/logo.png" />',
assetResolver,
});1. Images
Supported image formats:
- PNG (
image/png) - JPEG (
image/jpeg) - SVG (
image/svg+xml) - See SVG documentation below for supported subset
Image sources can be specified in HTML <img src="..."> using:
- Base64 Data URLs:
<img src="data:image/png;base64,iVBORw0KGgo..." /> - Local Filesystem Paths:
<img src="./assets/logo.png" />or<img src="../images/photo.jpg" />(resolved relative tobasePathorprocess.cwd()) - Explicit Image Map (
options.images): Pass Node.jsBufferobjects or base64 strings mapped by identifier:
const pdf = await HtmlToPdf.generateBuffer({
html: '<img src="./images/company-logo.png" width="150" />',
basePath: "./public", // Base directory for resolving relative image and @font-face assets
images: {
// Explicit options.images take precedence over local filesystem paths
"company-logo.png": fs.readFileSync("./assets/company-logo.png"),
},
});2. SVG Vector Images
html-pdf-engine includes a dedicated SVG renderer. SVGs can be included via <img>, Data URLs, options.images, or directly as inline <svg> HTML tags.
Supported SVG Subset:
- Primitives:
rect(withrx/ry),circle,ellipse,line,polyline,polygon,path. - Transforms:
translate,scale,rotate,matrixon SVG elements. - Styling:
fill,stroke,stroke-width,stroke-linecap,stroke-linejoin,stroke-dasharray,opacity. - ViewBox:
viewBoxattribute is fully supported with scaling.
Unsupported in SVG:
<text>elements.- Gradients (
<linearGradient>,<radialGradient>), Filters, and Clipping paths. - Embedded raster images (
<image>) inside SVG.
3. Font Support & Embedding
The built-in font pipeline supports:
- System TrueType Fonts: Automatically discovers and embeds high-quality system TTF fonts (Liberation, DejaVu, FreeFont) for standard font families if available, falling back to standard Type1 fonts.
- TrueType (
.ttf) — fully supported - OpenType with TrueType outlines (
.otfwithglyftable) — accepted by the parser (same binary table structure) - WOFF / WOFF2 — not supported; the
@font-faceparser throws aFontErrorfor these formats - Remote
@font-faceURLs (http/https) — not supported; throws aFontError. Fonts must be supplied as local file paths, data URLs, or Buffers.
Network font imports (@font-face with URL) are not supported. Pass font file paths or Node.js Buffer objects via options.fonts:
const pdf = await HtmlToPdf.generateBuffer({
html: '<p style="font-family: Inter; font-weight: bold;">Custom Font Headline</p>',
fonts: {
Inter: {
regular: "./fonts/Inter-Regular.ttf",
bold: "./fonts/Inter-Bold.ttf",
italic: fs.readFileSync("./fonts/Inter-Italic.ttf"),
},
},
});Font Subsetting: Custom fonts are automatically subsetted during PDF compilation. Only the character glyphs referenced in the document are embedded into the PDF binary, resulting in compact output file sizes.
Feature Capabilities & API Reference
PDF Document Metadata
PDF document metadata can be provided via options.meta (or the legacy alias options.metadata):
const pdf = await HtmlToPdf.generateBuffer({
html: "<h1>Document</h1>",
meta: {
title: "Annual Report 2026",
author: "Finance Department",
subject: "Financial Analysis",
keywords: "finance, report, 2026",
creator: "Internal Reporting Suite",
},
});PDF Hyperlinks & Internal Document Navigation
Clickable HTML anchor tags (<a href="...">) are parsed into native PDF Link Annotations (/Subtype /Link):
<!-- External Web URLs & Protocol Schemes -->
<a href="https://example.com">Visit Website</a>
<a href="mailto:[email protected]">Contact Support</a>
<a href="tel:+18005550199">Call Support</a>
<!-- Internal Document Fragment Links -->
<a href="#section-2">Jump to Section 2</a>
<!-- Target Anchor Destination -->
<h2 id="section-2">Section 2</h2>- External Links: Generated as
/A /S /URIactions supportinghttp://,https://,mailto:, andtel:schemes. - Internal Fragment Links: Fragment URLs (
href="#id") are resolved against matching DOM element IDs (id="id") and compiled into PDF/A /S /GoTointernal destination actions. - Bounding Boxes & Wrapping: Hyperlink bounding boxes are computed from laid-out inline text lines, supporting multi-line wrapped links across pages.
CSS Sizing Constraints & Container Clipping
html-pdf-engine supports standard CSS dimension constraints (min-width, max-width, min-height, max-height) and overflow: hidden container clipping across all layout models:
<style>
/* Responsive image scaling while preserving aspect ratio */
img.hero { max-width: 100%; max-height: 200pt; }
/* Canned card container with overflow clipping */
.badge-card {
min-width: 200pt;
max-height: 120pt;
overflow: hidden;
border: 1pt solid #cbd5e1;
}
</style>- Sizing Constraints:
min-width/max-widthandmin-height/max-heightwork across Block boxes, Images, Table cells, Flex items, Grid items, and Positioned elements. - PDF-Native Container Clipping:
overflow: hiddenemits PDF graphics state clipping commands (q,W n), ensuring content and clickable hyperlink annotations do not spill outside container boundaries. - Pagination Protection: Content overflowing inside
overflow: hiddencontainers is clipped visually without triggering spurious multi-page document pagination.
CSS @page At-Rules
Documents can specify page dimensions, orientation, and margins directly in CSS via @page rules:
@page {
size: A4 landscape;
margin: 20pt 30pt;
}
/* Custom dimensions */
@page {
size: 8.5in 11in;
margin-top: 0.5in;
margin-bottom: 0.5in;
}Explicit JavaScript options (page, orientation, margin) provided to HtmlToPdf.generate() will override CSS @page declarations if specified.
Layout Support Matrix
Flexbox (display: flex / display: inline-flex)
| Flex Property | Supported Values |
| :--- | :--- |
| flex-direction | row, column, row-reverse, column-reverse |
| flex-wrap | nowrap, wrap, wrap-reverse |
| flex-flow | Shorthand combination of flex-direction and flex-wrap |
| justify-content | flex-start, center, flex-end, space-between, space-around, space-evenly |
| align-items | flex-start, center, flex-end, stretch |
| gap / row-gap / column-gap | Explicit gap sizing in px, pt, mm, cm, in, % |
| flex-grow / flex-shrink / flex-basis | Item flexibility coefficients and base size resolution |
CSS Grid (display: grid / display: inline-grid)
| Grid Property | Supported Values |
| :--- | :--- |
| grid-template-columns | Fixed (px, pt, mm, cm, in), percentage (%), flexible (fr), auto, repeat(count, track) |
| grid-template-rows | Fixed (px, pt, mm, cm, in), percentage (%), flexible (fr), auto, repeat(count, track) |
| grid-column / grid-column-start / grid-column-end | Explicit column index placement and span N coverage |
| grid-row / grid-row-start / grid-row-end | Explicit row index placement and span N coverage |
| gap / row-gap / column-gap | Track spacing between grid columns and rows |
| justify-items / align-items | Grid container item alignment (start, center, end, stretch) |
| justify-self / align-self | Individual grid item self-alignment (start, center, end, stretch) |
| Item Placement | Automatic placement algorithm for unplaced items into available grid cells |
CSS Positioning (position: relative / position: absolute)
html-pdf-engine supports practical CSS positioning for document overlays, badges, watermarks, stamps, and structured report layouts.
<div style="position: relative; width: 100%; height: 120px;">
<div style="position: absolute; top: 10px; right: 20px; background-color: #22c55e; color: #ffffff; padding: 4px 8px; border-radius: 4px;">
PAID
</div>
</div>position: relative: Preserves the element's space in normal document flow while applying visualtop,right,bottom,leftoffsets.position: absolute: Removes the element from normal document flow and positions it relative to its nearest positioned ancestor (relativeorabsolute).- Containing Block Resolution: Un-parented absolute elements resolve against the document/page printable coordinate area.
- Offsets: Supports explicit units (
px,pt,mm,cm,in) and percentage values (%).
| Positioning Property | Supported Values / Behavior |
| :--- | :--- |
| position | static, relative, absolute |
| top / right / bottom / left | Fixed units (px, pt, mm, cm, in) and percentages (%) |
| Containing Block | Nearest positioned ancestor (relative / absolute) or document printable area |
| Layout Integration | Positioned elements inside Flexbox (display: flex) and CSS Grid (display: grid) |
| Supported Children | Text nodes, custom TTF fonts, PNG/JPEG images, and clickable PDF hyperlinks |
| Pagination | Multi-page aware page index propagation across page breaks |
Advanced PDF Pagination & Page-Break Control
html-pdf-engine provides practical PDF pagination and page-break control for structured multi-page documents such as invoices, reports, statements, and forms.
<section style="break-before: page;">
<h2>Invoice Summary</h2>
</section>
<div style="break-inside: avoid;">
<h3>Payment Details</h3>
<p>Important content that should remain together.</p>
</div>Modern CSS Fragmentation Properties
break-before: auto | page;
break-after: auto | page;
break-inside: auto | avoid;Legacy CSS Page-Break Aliases
page-break-before: auto | always;
page-break-after: auto | always;
page-break-inside: auto | avoid;Behavior & Layout Rules
break-before: page(orpage-break-before: always): Starts an element on a new PDF page (suppressed if the element is already positioned at the start of a page).break-after: page(orpage-break-after: always): Forces following content onto the next PDF page (suppressed if applied to the final element in the document).break-inside: avoid(orpage-break-inside: avoid): Attempts to keep a block container, table row (tr), Flexbox container/item, Grid container/item, image, or text group together on the current page if vertical space permits.- Oversized Content Fallback: If an element's total height exceeds a single page's printable height,
break-inside: avoidpermits normal multi-page splitting to prevent infinite pagination loops. - Practical PDF Pagination: Designed for deterministic server-side document rendering. Advanced browser CSS fragmentation features (such as
break-before/after: left | right | recto | verso, column fragmentation, CSS regions, or subpage fragmentation) are intentionally unsupported.
Dynamic Headers and Footers
Top headers and bottom footers can be attached via options.header and options.footer:
const pdf = await HtmlToPdf.generateBuffer({
html: "<div>Content across multiple pages...</div>",
header: {
text: "Confidential Financial Report",
align: "left",
fontSize: 9,
showDividerLine: true,
},
footer: {
text: (page, total) => `Page ${page} of ${total}`,
align: "center",
fontSize: 9,
showDividerLine: true,
},
});Public TypeScript API & Error Handling
Primary Methods (HtmlToPdf)
HtmlToPdf.generateBuffer(options: HtmlToPdfOptions): Promise<Buffer>: Compiles HTML/CSS options into a Node.jsBuffer.HtmlToPdf.generateFile(options: HtmlToFileOptions): Promise<void>: Compiles HTML/CSS options and writes directly to disk.HtmlToPdf.generate(options: HtmlToPdfOptions): Promise<PDFDocument>: Low-level API returning the structuredPDFDocumentinstance.
Exported Types & Interfaces
import type {
HtmlToPdfOptions,
HtmlToFileOptions,
PDFMetadataOptions,
PageSizeName,
PageOrientation,
PageMargins,
PageSize,
HeaderFooterOptions,
HeaderFooterTextResolver,
CustomFontMap,
FontVariantSource,
ImageMap,
ParsedImageData,
ColorRGB,
} from "html-pdf-engine";Error Hierarchy
All custom errors extend PdfError:
import {
PdfError,
FontError,
ImageError,
HtmlParseError,
CssParseError,
LayoutError,
UnsupportedFeatureError,
} from "html-pdf-engine";
try {
const pdfBuffer = await HtmlToPdf.generateBuffer({ html });
} catch (error) {
if (error instanceof FontError) {
console.error("Font resolution failure:", error.message);
} else if (error instanceof ImageError) {
console.error("Image processing failure:", error.message);
} else if (error instanceof PdfError) {
console.error("PDF engine error:", error.message);
}
}Feature Matrix
| Feature | Support Level | Implementation Notes |
| :--- | :--- | :--- |
| HTML Parsing | Supported | Valid standard HTML5 structure (<div>, <p>, <span>, <h1>–<h6>, <table>, <ul>, <ol>, <a>, <img>). |
| Block & Inline Layout | Supported | Text wrapping, line height, margins, padding, border shorthand & individual sides. |
| HTML Tables | Supported | <table>, thead, tbody, tfoot, tr, th, td with borders, padding, cell text-wrapping, automatic <thead> repeating headers across multi-page breaks, multi-row header repetition, and break-inside: avoid on tr. |
| Lists | Supported | <ul>, <ol>, <li> with standard bullet and numbered layout spacing. |
| PNG, JPEG & SVG Images | Supported | Base64 Data URLs, local file paths, and Node.js Buffer mapping (options.images). SVG vector rendering supported for common primitives (path, rect, circle, etc). |
| System TTF Fonts | Supported | Automatically discovers and embeds high-quality system TrueType fonts (Liberation, DejaVu, FreeFont) if available. Falls back to standard Type1 fonts. |
| Custom TTF Fonts | Supported | Custom .ttf embedding via options.fonts (regular, bold, italic, boldItalic). |
| TTF Subsetting | Supported | Embeds subsetted CIDFontType2 / Type0 glyph maps with /ToUnicode CMaps. |
| Flexbox Layout | Supported | 1D & multi-line layout (flex-direction, flex-wrap, justify-content, align-items, gap, flex-grow/shrink/basis). |
| CSS Grid Layout | Supported | 2D track layout (px, pt, %, fr, auto, repeat()), explicit placement (grid-column, grid-row, span), auto placement, item alignment. |
| CSS Positioning & Stacking | Supported | Practical position: static, relative, absolute, and fixed (repeated across pages for headers/footers/watermarks) with containing block resolution and z-index paint ordering. position: sticky and 2D/3D transforms unsupported. |
| PDF Pagination & Page Breaks | Supported | Practical break-before: page, break-after: page, break-inside: avoid, and legacy page-break-* aliases across Block, multi-page Table (<thead> automatic repeating headers across page breaks), Flexbox, Grid, and positioned elements. |
| PDF Hyperlinks & Anchors | Supported | Clickable /URI link annotations (http://, https://, mailto:, tel:) and internal fragment link annotations (href="#id") resolved to PDF /GoTo destinations. |
| PDF Metadata & Preferences | Supported | Custom /Info dictionary entries (Title, Author, Subject, Keywords, Creator, Producer), catalog /ViewerPreferences, /Lang, and /PageLabels. |
| Headers & Footers | Supported | Dynamic {{pageNumber}} & {{totalPages}} text resolvers with alignment and divider lines. |
| CSS Variables | Supported | Custom properties (var(--name)), fallback values, inheritance, nested variable resolution, and cycle protection. |
| Media Queries | Supported | @media print, @media all, and width-based (min-width: ...) / (max-width: ...) query blocks evaluated against PDF page content width. |
| JavaScript Execution | Not Supported | <script> tags parsed and visually hidden for security. |
| Remote Asset Loading | Opt-In | Default renderer executes offline without network calls. Opt-in AssetResolver (createNetworkAssetResolver()) supported with SSRF protection, timeout, and byte limits. |
Technical Limitations & Non-Goals
The following features are intentionally unsupported or limited to maintain a deterministic, lightweight server architecture:
- Image Formats: The built-in image pipeline supports PNG, JPEG, and SVG (subset). WebP, AVIF, GIF, and BMP are not decoded and will throw an
ImageError. - Font Formats: Custom font embedding supports TrueType (
.ttf) and OpenType-with-TTF-outlines. WOFF and WOFF2 are not supported. Remote@font-faceHTTP/HTTPS URLs are not supported. - CSS Transforms: The
transformproperty (rotate,scale,translate,matrix) is not parsed or applied to standard HTML elements. Note: SVG<svg>elements do support thetransformattribute.text-transform(uppercase/lowercase) is a separate supported property. position: sticky: Not implemented; scroll-relative positioning is not meaningful in static PDFs.- Unsupported Layout: CSS Multi-column layout (
columns), CSS regions, andfloat/clearhave partial or no layout effect. - Grid Template Areas & Subgrid: Named
grid-template-areas,subgrid,minmax(),auto-fit, andauto-fillare not supported. - Interactive Features: JavaScript execution (
<script>), CSS animations (@keyframes), hover states (:hover), and interactive form controls are excluded. - Canvas: No built-in Canvas API.
- Tagged PDF & Accessibility: No
StructTreeRoot,MarkInfo, or marked-content sequences are generated. The/Langcatalog entry is a metadata field only — its presence does not produce a tagged or PDF/UA-compliant PDF. - Filters & Shadows:
filter,box-shadow, andtext-shadoware not implemented.
For a complete reference on supported properties and limitations, see the Feature Matrix and Limitations documentation on GitHub.
Performance Benchmarks
Measured using the repository benchmark suite (npm run benchmark) on Node.js v22 (x86_64 Linux, single process execution). Run npm run benchmark to reproduce:
| Workload | Iterations | Avg Time per PDF | Throughput (ops/sec) | | :--- | ---: | ---: | ---: | | Simple HTML | 100 | ~0.73 ms | ~1,366 | | Invoice | 100 | ~2.18 ms | ~458 | | Complex Layout | 100 | ~1.67 ms | ~598 | | Multi-page Report | 50 | ~8.05 ms | ~124 | | Local Images | 50 | ~1.40 ms | ~715 | | Large Table (100 rows) | 20 | ~25.41 ms | ~39 | | Large Table (500 rows) | 5 | ~150.89 ms | ~7 |
- Methodology: Measurements reflect engine execution only — HTML parsing, CSS cascade, layout box generation, paint command emission, and FlateDecode stream compression. Disk I/O and network asset fetching time are excluded.
- Warm-up: Initial renders are performed before measurement to allow V8 JIT optimization.
- Determinism: Output byte-for-byte identical across repeated executions (verified by benchmark suite).
- Concurrency: Linear throughput scaling observed across 1–25 concurrent renders.
Package Footprint
- Published Tarball Size: ~169.1 kB packed (
npm pack --dry-run) - Unpacked Size: ~945.0 kB
- Runtime Dependencies: 0
Development & Test Commands
# Install development dependencies
npm install
# Run Vitest integration test suite (143 tests)
npm test
# Typecheck TypeScript codebase
npm run test:typecheck
# Compile production distribution (dist/)
npm run build
# Run local benchmark suite
npm run benchmark
# Dry-run package distribution
npm pack --dry-run