Performance Engineering
The large-document milestone was not only a benchmark exercise. It changed the runtime architecture and added repeatable correctness, cleanup and memory diagnostics.
The measurements below are historical fixtures. The latest full browser and stress reruns were not part of this docs update; measure your own document on target devices.
Rendering architecture
The package dynamically loads PDF engines and the optional composition engine, resolves a shared template once, reuses unchanged header/footer and styled slot captures, reduces repeated image waiting, and prunes unrelated app DOM while capturing a layer. Oversized splittable Canvas sections are preflight paginated on private DOM, then fitting fragments are reused. Cooperative yields avoid waiting for hidden-tab animation frames. Generation reuses one final Blob for preview and download, with cleanup, cancellation and opt-in timing metrics.
A local nine-page Canvas/slot export with watermark off was inspected: 27 image objects and zero PDF text-showing commands; a separate text-mode PDF contained 423 text commands. One local Canvas slot session changed from 26.89 seconds to 12.55 seconds after the refinements, without a controlled benchmark. A separate nine-page text run was about 4.35 seconds; no text-mode speedup was established. These observations do not predict your document's runtime or fidelity. Record browser/device, page count, renderer, assets, quality and cold/warm state when comparing exports.
Executive outcome
- paginated Canvas documents can render page by page instead of one giant document-height canvas
- 50-page and 100-page Canvas exports are verified as real, non-empty PDFs on the incremental path
- static HTML footer content is rasterized once and reused across pages
- selectable-text mode caches repeated image sources within one generation
- long work can be cancelled and then safely regenerated
- progress can expose
stage,progress,currentPageandtotalPages - temporary DOM, Canvas backing stores and encoded image references are released earlier
- browser yielding was added between expensive chunks
- encrypted raster memory retention was isolated and reproduced directly in jsPDF
Phase map
| Phase | Focus | Result |
|---|---|---|
| Phase 1 | Benchmark/stress foundation | Actual page count, Blob size, Canvas geometry, timing, memory and progress telemetry. |
| Phase 2.1 | Static HTML footer bottleneck | Render once + reuse; major time, output-size and heap reductions in the fixture. |
| Phase 2.2 | Clean memory isolation | Fresh-context methodology separated temporary peaks from retained heap. |
| Phase 2.3A | Security isolation | Basic user-password encryption identified as the trigger for high raster retention. |
| Phase 2.3B | Large-PDF correctness | Page count alone was proven insufficient; Blob size and Canvas telemetry were added. |
| Phase 2.4 | Scaling and cliff diagnostics | Raster payload + jsPDF encryption pattern isolated; legacy long-canvas failure instrumented. |
| Phase 3.1 | Incremental Canvas | Page-bounded captures replaced the giant capture for paginated Canvas documents. |
| Phase 3.2 | Security re-test | Giant-canvas issue addressed; encrypted-raster retention remained dependency-level. |
| Phase 3.2.1 | Raw jsPDF reproduction | Strongest retention pattern reproduced without Vue component lifecycle. |
| Phase 3.3 | Cancellation + progress | Cooperative cancellation, recovery and current-page progress added. |
| Phase 3.4 | Repeated assets + cleanup | Per-generation image cache and shorter DOM/Canvas lifetimes. |
| Phase 3.5 | Routing regression hardening | Correct incremental Canvas branch restored and protected by 50/100-page E2E tests. |
Headline measured results
| Metric | Before | After | Improvement |
|---|---|---|---|
| HTML footer, no logo | 7.82 s | 1.43 s | ~81.7% less time / 5.47× faster |
| HTML footer + logo | 11.81 s | 1.29 s | ~89.1% less time / 9.16× faster |
| Footer-heavy PDF | ~46.7 MB | ~1.0 MB | ~97.9% smaller |
| No-logo peak heap | 102.6 MB | 26.5 MB | ~74.2% lower |
| Giant Canvas capture geometry | ~99.96M px | ~1.74M px/page | ~98.26% lower peak capture area |
These percentages describe specific benchmark fixtures or capture geometry; they are not universal whole-package speed or memory guarantees.
Current incremental Canvas correctness
| Requested pages | Actual pages | Time | PDF size | Largest encoded Canvas |
|---|---|---|---|---|
| 10 | 10 | 1.53 s | 1.5 MB | 1191 × 1461 |
| 25 | 25 | 4.33 s | 3.9 MB | 1191 × 1461 |
| 40 | 40 | 7.54 s | 6.2 MB | 1191 × 1461 |
| 50 | 50 | 9.68 s | 7.8 MB | 1191 × 1461 |
| 60 | 60 | 12.56 s | 9.3 MB | 1191 × 1461 |
| 75 | 75 | 16.87 s | 11.7 MB | 1191 × 1461 |
| 100 | 100 | 25.25 s | 15.8 MB | 1191 × 1461 |
The maximum encoded Canvas remained page-sized as the requested page count increased.
Encrypted raster PDFs
The strongest high-retention behavior was reproduced with raw jsPDF, so the project documents it as memory retention rather than mislabeling it as a permanent Vue memory leak.
Upstream issue: jsPDF #4017 - encrypted raster PDF memory retention
For large text-heavy secured documents whose CSS is supported by the vector renderer, selectable-text mode can be much lighter than raster Canvas mode. This is workload-dependent, not a universal renderer benchmark.
Verification mindset
Large exports are checked with more than “the Promise resolved”: actual page count, Blob size, Canvas dimensions, cancellation/recovery and cleanup signals are part of the regression strategy.
Testing & Browser Support
Review vue-pdf-export browser support and testing guidance across Chromium, Firefox, WebKit, Safari, SSR fixtures and npm, pnpm, Yarn, Yarn PnP and Bun consumers.
Full Performance Engineering Report
Read the complete vue-pdf-export performance engineering report covering large documents, memory behavior, timing, cancellation, image reuse and regression hardening.
