Because I don’t want to continue using wkthmlpdf or chromium/chrome for only exporting a HTML to PDF, I decided to create a library called Press that lets us convert an HTML document directly to PDF. This library was designed for use inside Conta, where we need to generate invoices, and it works very well.
Press is a dependency-free Elixir library for rendering HTML+CSS into PDF, targeting structured business documents: invoices, delivery notes, payslips, and reports. “Dependency-free” means zero runtime dependencies — only modules that ship with OTP itself (e.g. :zlib) are used.
Well, it’s not the first time"crazy" project I do, previously I did myproto to simulate a MySQL server, ephp for putting PHP on top of Erlang, and I rewrote Lambdapad for getting a good website static generator. This time my pain was I don’t want to install chrome on my server and get timeouts when generating a PDF or even worse, dedicate 1GB only for that.
This is great - I was looking for something a while ago and wasn’t really happy with the options. Ended up skipping PDF and just exporting a markdown file as a result. I would definitely have been happier with this!
This is great! We had another pdf library for directly working with pdfs and now this one which converts html and css to pdf. Big ups to you and every body else who’s made working with pdfs in Elixir a breeze! Many thanks!
Personally, with AI, I just use https://typst.app/. It’s a fast and maintainable way to generate PDFs. It has drastically reduced resource consumption and gives me a more standard way to write documents without having to use HTML.
Not a bad solution, but I’d like to avoid dependencies on third-party elements for the project where I’m using Press, that’s because I created it. Keep in mind that it was created for even drop internal dependencies like Chrome. Thanks for the info.
Yes, but as I said, I don’t like to run third-party dependencies. If I wanted to do that, I could continue using chromic_pdf using chrome/chromium or wkthmltopdf under the hood. I’m not saying it’s not a good solution, but it’s not the solution I was looking for.
That comparison makes it seem like you haven’t looked closely at what typst actually is? The “third party dependency” is an OSS rust nif through rustler that runs super lightweight.
How can you compare that with deploying chromium on the runtime?
Chromic is orders of magnitude better than the other chrome based pdf solutions out there, but it is still an operational nightmare compared to the embedded typst nif.
A dependency could be integrated into the code, or you could use it as an external command. If we use chromic_pdf, we depend on Chrome, Chromium, or wkhtmltopdf. If we use typst, we have a dependency on typst; even if that’s not integrated into the code, we need to use it, so we depend on it.
Besides that, I want you to understand I’m not saying Typst is a bad product. I know it’s great for generating nice PDFs from specifications, and it’s very valuable. But my point is: I don’t like internal or external dependencies. That’s all.
And above all, thanks for giving us this heads-up about this tool. For sure, I’ll use it for other projects.
Even a Rust NIF is too much for a bunch of people, so that’s the difference and the selling point for many in the BEAM ecosystem.
While I don’t share that skepticism (my SQLite library that heavily steps on a Rust NIF is still coming sometime this year and not like it’s not been 99% done for months, I am just burning tokens to find problems in it before my users do), I also get it because theoretically you throw away BEAM’s stability guarantees, and how many people truly inspect their Rust code for .unwrap() and .expect()?
Cloudflare themselves made that mistake.
Even worse, how many people heavily audit their C code for use-afrer-free / double-free et. al.?
Pure Elixir alternatives, even if they end up 50x slower – @manuel-rubio, I make ZERO claims about your excellent tool, just raising a hypothetical – many people would welcome NIF-free dependencies for what is viewed as a necessary evil by many otherwise.
Just to clarify, because people bring this up whenever someone talks about Rust NIFs (even people that should know better): Rustler will not make your BEAM crash just because something in your NIF panicked. We use catch_unwind to catch panics and re-raise them as Erlang exceptions. This does of course not prevent everything, but a simple .unwrap or .except is not enough to break anything. For the next release, I have also fixed the detection of a panic = "abort" configuration and rustler will refuse to compile if that is set.