<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="350267" data-post-id="350267">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="harrisi" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/harrisi/120/33003_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  harrisi
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="onebox allowlistedgeneric" data-onebox-src="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Counter_styles/Using_counters">
  <header class="source">
      <img src="https://developer.mozilla.org/favicon.ico" class="site-icon" alt="" width="48" height="48">

      <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Counter_styles/Using_counters" target="_blank" rel="noopener nofollow ugc">MDN Web Docs</a>
  </header>

  <article class="onebox-body">
    <img width="690" height="690" src="https://developer.mozilla.org/mdn-social-image.46ac2375.png" class="thumbnail onebox-avatar" alt="">

<h3><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Counter_styles/Using_counters" target="_blank" rel="noopener nofollow ugc">Using CSS counters - CSS | MDN</a></h3>

  <p>CSS counters let you adjust the appearance of content based on its location in a document.
For example, you can use counters to automatically number the headings on a webpage or to change the numbering on ordered lists.</p>


  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>CSS for printed media is pretty good these days, and only getting better. MDN has a lot more on it, but this seems like it’s maybe getting  off topic.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350267" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-350267" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350267"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="350525" data-post-id="350525">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jfpedroza" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jfpedroza/120/32425_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jfpedroza
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>We use weasyprint (Python library) and erlport to call Python code.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350525" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-350525" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350525"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="350527" data-post-id="350527">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="arun1" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  arun1
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks to everyone who replied, I ended up choosing Typst. The markdown is pretty powerful and easy to learn. There free online editor makes it easy to experiment with the markdown as well.</p>
<p>I don’t have any data to back this up but figured a rust library would be more performant than weasyprint in python</p>
<p>I could not get ex_typst to work, so I just called the typst compiler using System.cmd.</p>
<p>I have a base .typ file that has the layout and template variables. I use elixir’s EEx to fill out the data and write a .typ file to a temporary location. Finally I execute the typst compiler using the shell.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350527" data-batch-url="/posts/batch_likers">
                        7
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-350527" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350527"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-most-liked cat-most-liked" title="One of the top 3 liked posts in this thread!"></div>
  </section>
</div>
    <div class="postbit" id="350550" data-post-id="350550">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="marceldegraaf" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/marceldegraaf/120/35597_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  marceldegraaf
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/arun1" rel="nofollow">@arun1</a> not sure if you still need a solution here, but in case it helps: we’re using <a href="https://gotenberg.dev/" rel="noopener nofollow ugc">Gotenberg</a> to generate PDF’s from HTML/CSS. We’re running the default Gotenberg Docker image and use the HTTP API to convert rendered Phoenix templates to PDF.</p>
<p>This is especially nice because we can use all the normal view helpers and Tailwind styling that we have throughout our application, and these days things like a table of contents or page numbering is pretty much solved in CSS.</p>
<p>Let me know if you’re interested in some example code of our setup, and the resulting PDF file!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350550" data-batch-url="/posts/batch_likers">
                        6
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-350550" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350550"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-most-liked cat-most-liked" title="One of the top 3 liked posts in this thread!"></div>
  </section>
</div>
    <div class="postbit" id="350551" data-post-id="350551">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="acrolink" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/acrolink/120/8985_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  acrolink
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="marceldegraaf" data-post="15" data-topic="68211">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/marceldegraaf/48/35597_2.png" class="avatar"> marceldegraaf:</div>
<blockquote>
<p>We’re running the default Gotenberg Docker image and use the HTTP API to convert rendered Phoenix templates to PDF.</p>
</blockquote>
</aside>
<p>Welcome to the forum. Do you generate multiple PDF files simultaneously?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350551" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-350551" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350551"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #15"></div>
  </section>
</div>
    <div class="postbit" id="350553" data-post-id="350553">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="marceldegraaf" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/marceldegraaf/120/35597_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  marceldegraaf
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hm, good question, I don’t know if Gotenberg allows creating multiple PDF’s at once, but we haven’t ran into any issues so far (and have this setup in production for over a year).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350553" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-350553" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350553"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #16"></div>
  </section>
</div>
    <div class="postbit" id="350554" data-post-id="350554">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m absolutely interested, can you post a complete and working example, please?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350554" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-350554" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350554"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #17"></div>
  </section>
</div>
    <div class="postbit" id="350557" data-post-id="350557">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="marceldegraaf" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/marceldegraaf/120/35597_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  marceldegraaf
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Definitely!</p>
<p>To start of, <a href="https://gist.github.com/marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1#file-gotenberg-yaml" rel="noopener nofollow ugc">this is how we deploy Gotenberg in Kubernetes</a>. Any other platform should work as long as it can run Docker containers. We don’t change any configuration; this is just the vanilla Gotenberg 7 image.</p>
<p>Then we define <a href="https://gist.github.com/marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1#file-options-ex" rel="noopener nofollow ugc">some options</a> for Gotenberg that are used in the API call when creating a PDF.</p>
<p>We then define <a href="https://gist.github.com/marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1#file-gotenberg-ex" rel="noopener nofollow ugc">a module</a> that interacts with the Gotenberg API. It does an HTTP POST to the <code>/forms/chromium/convert/html</code> endpoint with our HTML page as a <code>form/multipart</code> request body.</p>
<p>Finally, <a href="https://gist.github.com/marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1#file-your_module-ex" rel="noopener nofollow ugc">define a module</a> in your application that takes some data, renders an HTML file (from a Phoenix View), and then calls the previously defined Gotenberg API module to render it to PDF.</p>
<p>Hope this helps! Let me know if you have any questions <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350557" data-batch-url="/posts/batch_likers">
                        6
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-350557" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350557"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #18"></div>
  </section>
</div>
    <div class="postbit" id="350562" data-post-id="350562">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Super helpful, thank you. I’ll need something 99% similar very soon and will let you know if it works.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350562" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-350562" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350562"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #19"></div>
  </section>
</div>
    <div class="postbit" id="350610" data-post-id="350610">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Lucassifoni" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Lucassifoni/120/39057_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Lucassifoni
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m running Chromium in production, with apps that are almost constantly generating PDFs when users are using it. Over the years I tried keeping a “hot” chromium instance always ready to convert things, but the risk of memory leaks was just too high.</p>
<p>Today I have either a thin puppeteer wrapper on separate infra, or this same wrapper on the same host as my app. This is because some of my clients want to run on-prem and cut off from the internet.</p>
<p>So I run N concurrent instances of Chromium with N consuming at most 4GB of memory simultaneously, behind N queues, so there are no more than N concurrent conversion jobs, and each chrome instance is killed after each job.</p>
<p>As a very popular blog post states (I think it was this one : <a href="https://www.browserless.io/blog/headless-browser-practices" class="inline-onebox" rel="noopener nofollow ugc">Phantom pain: the first year running headless Chrome in production</a> but it is different than what I recall), there’s just no guaranteed way to keep RAM usage on check long term on fixed-size infra without fully stopping chrome from time to time.</p>
<p>I am at very low scale but high resource usage, think of 200+ pages PDFs with a lot of high definition pictures for printing.</p>
<p>No incidents in a few years since I abandoned the “hot chrome instance” approach.</p>
<p>This Gothenberg setup looks like it could be my next step, thanks a lot for sharing this link !</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="350610" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/pdf-generation-without-chromium-dependency/68211/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-350610" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="350610"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #20"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/68211/load_more?page=3">Load more posts (1 remaining)</a>
</div></template></turbo-stream>