At Smartagent, we faced a challenge that might sound familiar to many developers: our client-side PDF generation feature was struggling under the weight of massive user demands. Our customers love customization—they want to generate various reports, tweaking everything from formats to the data columns they see. To give you an idea, here's a glimpse into the level of customization we provide:
Using react-pdf, we crafted a solution that allowed users to manipulate their reports with an impressive degree of flexibility. But, as data grew (imagine trying to cram an entire financial year's worth of invoices, up to 22,000 rows, into one PDF), our solution began to falter, especially on older PCs with limited resources.
The "Aw, Snap!" error became a common sight, frustrating users trying to generate their reports:
The Quest for a Solution
Initially, we experimented with the idea of shifting PDF generation to the server side. However, this approach would require us to rewrite our entire PDF generation logic a daunting task given the time-sensitive nature of the issue.
So, we turned our attention back to the client side, aiming for a solution that could gracefully handle large datasets even on low-spec PCs.
Diving into Experiments
Our journey led us to explore two promising technologies: WebAssembly (Wasm) and web workers.
- Experiment 1: Wasm-PDF
We combined Wasm with Faker to create a demo for high-performance PDF generation. The results were eye-opening: generating a PDF with 1,000 rows took just 200ms, a task that previously took over a minute and often led to crashes. For 22,000 rows, the process took a mere 6 seconds.
- Experiment 2: Web-worker
We discovered that our application was crashing because PDF generation was blocking the main thread. By leveraging web workers, we could offload this task, allowing the app to remain responsive.
With web workers, generating 1,000 rows took only 3 seconds.
What We Learned
Our exploration revealed valuable insights:
Performance vs. Practicality: While Wasm offered incredible speed, it required a significant time to rewrite our PDF logic. Given our tight schedule and the learning curve associated with Wasm and Rust, we had to consider alternative solutions.
The Power of Web Workers: Web workers provided a practical way to improve performance without needing to rewrite our existing logic. By moving PDF generation off the main thread, we could prevent crashes and improve user experience, even if the process took a bit longer.
Our Choice and Why
In the end, we opted for the web worker solution. It addressed our immediate needs without sacrificing the user experience. Adding a progress bar gave users visual feedback, reassuring them that their reports were on their way.
This decision was a compromise, shaped by our constraints and our commitment to delivering a reliable service. However, our exploration of Wasm opened up exciting possibilities for future optimizations.
Top comments (17)
One of my clients wanted PDF generation and we realized: literally just
window.print()
does this. Saved us probably months of development time and architectural heartache.yes but sometime we need assembled data
@media print
Wtf. Why you are generating PDFs on the frontend, not backend? Especially for 22k rows. I understand you send those rows to the client? My god.
"this approach would require us to rewrite our entire PDF generation logic a daunting task "
Yes, because you made a mistake in the beginning. Honestly you should get it straight ASAP. Those PDFs were generating for at least 30 seconds, and im sure you had a lot of time previously to tackle that problem.
The solution is cool though, anyway
From my own experience I can confirm that frontend client side web worker solution is the way to go.
client side loading 22k rows, chances are high of rendering a users machine unusable while it's processing the PDF, isn't that going to affect user experiences?
tanstack table handles this in very good way, it has virtualization and other UI related optimization and obviously, we use pagination!
I believe @j0nimost is talking about pdf-creation & rendering.
In a web-worker, it takes longer than the main thread but we didnt face that issue. Phones did heat up though...
lol 😂, i can imagine it on older laptops 4th gen intel laptops with 4GB ram, or tablets.
You talked about 22k rows. How much time did 22k rows take?
It must have taken longer time.
I thought 22 is a smaller number :|
Well ofcourse watson.
What wasm pdf library did you use?
Thanks for sharing!