dompdf / dompdf

HTML to PDF converter for PHP
https://dompdf.github.io/
GNU Lesser General Public License v2.1
10.54k stars 1.8k forks source link

Latency issues for large style sheets: Caching style sheets in php/dompdf for successive calls in production env? #3374

Open gidzr opened 10 months ago

gidzr commented 10 months ago

Hi Brian

Quick one: I've noticed when adding style sheets (like bootstrap) to the pdfing process, dompdf goes from a millisecond to create a pdf to a few seconds. Once I've added all my style sheets, it takes around 7 seconds per pdf, which is quite a bit.

Is there some way to cache or load the style sheets in through the composer / vendor / dompdf library? or is there a cache setting that once in production, I can lock down the styles so they are just loaded once and for each successive pdf, it doesn't take 7 seconds to pdf?

Cheers!

bsweeney commented 10 months ago

Dompdf doesn't provide any type of functionality to support this. It's also a challenging question. There are actually two parts to the problem:

  1. downloading/parsing the stylesheet
  2. applying the stylesheet to the document

While it may be possible to support something for the first part, there's no getting around the second. It's likely the second part that's eating up most of the rendering time. Still, if you wanted to try you would do it something like the following:

$dompdf_styles = new Dompdf();
$dompdf_styles->loadHtml($empty_doc); // only has stylesheet references
$dompdf_styles->render();
$css = $dompdf_styles->getCss();
$dompdf = new Dompdf();
$dompdf->loadHtml($content_doc); // no stylesheets, only content
$dompdf->setCss($css);
$dompdf->render();

I have not tested that code and I'm not sure it will work (and expect it would not).


If the content you're rendering is fairly static (e.g., a "frame" around some content) then you might consider PDF templating or merging. Not something Dompdf supports but you could use it in conjunction with another library.

gidzr commented 10 months ago

ok.. reading your algorithm, I have a couple of questions:

  1. Is there a getCSS and setCSS method for dompdf. I've found this: https://github.com/dompdf/dompdf/blob/ae691fbbcb0204d29d6809f2c2ae6646e770961c/tests/DompdfTest.php. I'll play around with your code to see what it does and if I can get something along those lines to work.

  2. I'm not sure if your code creates a css object that applied to the dompdf instance, OR if it creates a persistent global dompdf instance that is appended to later or both? Is it possible to append to an existing rendered instance

Is this what you're indicating?

Possible approach 1 - applying rendered styles (have I understood this re scoping?) GLOBAL SCOPE onload $dompdf_styles = new Dompdf(); $dompdf_styles->loadHtml($empty_doc); // only has stylesheet references $dompdf_styles->render();

// in function $css = $dompdf_styles->getCss(); $dompdf = new Dompdf(); $dompdf->loadHtml($content_doc); // no stylesheets, only content $dompdf->setCss($css); $dompdf->render();

Possible approach 2 - modular appending GLOBAL SCOPE onload $global_dompdf = new Dompdf(); $global_dompdf->loadHtml(); $global_dompdf->render();

// in function $dompdf = $global_dompdf->loadHtml($content_inner); //<-- from client $dompdf->loadHtml(''); $dompdf->render();

bsweeney commented 10 months ago

getCss and setCss are in the main Dompdf class.

Your first approach is what I had in mind. The second approach won't work because data from each document will pollute impact the previous one. So, you just want the styles generated by an initial, global instance.