Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Weasyprint Bundle Laravel Package

pontedilana/weasyprint-bundle

Symfony bundle that integrates WeasyPrint to turn HTML and CSS into high-quality PDFs. Render Twig templates through a simple service, with configurable binary path and clean Symfony integration for invoices, reports, and printable documents.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Framing correction (blocking, unchanged by 3.1.0): The premise describes this as a Laravel/PHP package. It is not. pontedilana/weasyprint-bundle is a Symfony bundle — it ships a DependencyInjection/Extension, a Configuration tree, and autowired services intended to be registered in a Symfony kernel. Laravel will not discover or boot it. Any "integration" in a Laravel codebase is a DIY adapter, not a package install. This reframes the decision from "adopt a library" to "reference an implementation." Nothing in 3.1.0 changes this.

Architecture fit

  • The package is a thin wrapper over the WeasyPrint Python CLI binary, invoked through symfony/process, with Twig rendering HTML upstream of the call. Roughly: render template → write temp HTML → shell out → return PDF bytes.
  • The actual capability lives in Python, not PHP. The PHP layer is a few hundred lines of glue; the bundle's value is configuration ergonomics and Symfony wiring, both inert in Laravel.
  • 3.1.0 adds a third component to the co-pinning problem: the bundle, php-weasyprint (the underlying library), and the WeasyPrint binary must now all be version-aligned. Two of the three release-note items are explicitly gated on php-weasyprint versions (2.5.1+ for ExecutableFinder path resolution, 2.6+ for allowed_schemes). This is no longer a two-body problem.
  • Fit in a Laravel app remains indirect: reimplement the glue (Blade/HTML renderer plus a symfony/process invocation), treat this repo as a reference design, not a dependency.

Integration feasibility

  • Feasible and small: symfony/process is already a transitive Laravel dependency, so the process layer costs nothing new. The real cost is the system runtime: Python 3, WeasyPrint, plus native libraries (Pango, HarfBuzz, fontconfig, GDK-Pixbuf, cffi/pydyf). This is a container-image problem, not a Composer problem.
  • Consuming the bundle directly would pull Symfony DI/config/Twig machinery into a Laravel app for no functional gain. Note that 3.1.0 raises minimum symfony/http-foundation, symfony/http-kernel, and symfony/process versions to patched releases — correct for Symfony shops, but it further narrows the already-unlikely intersection with a given Laravel version's pinned Symfony set. Expect conflicts; the upgrade makes the install path marginally worse, not better.
  • The security and path-resolution changes are library-level behaviors, so they are reproducible in a hand-rolled Laravel adapter without the bundle. That is the useful takeaway: the release improves the pattern, not the package's adoptability.

Technical risk

  • Adoption risk (unchanged): ~40 stars, 0 dependents, single maintainer. Bus-factor-one glue code. Acceptable as reference; unacceptable as a critical-path dependency.
  • Version coupling (worsened): the wrapper hardcodes CLI flags, and 3.1.0 introduces configuration whose effect is silently conditional on the php-weasyprint version. pdf.allowed_schemes is accepted by config but inert below php-weasyprint 2.6 — a security control that no-ops without error is worse than no control, because it manufactures false assurance. Similarly, ExecutableFinder behavior differs at 2.5.1. Mitigation: assert the resolved library and binary versions at boot and fail fast.
  • SSRF (partially mitigated, opt-in, default-permissive): the new allowed_schemes knob is the right shape of control, but it is scheme-level only, it must be explicitly configured, and the default posture should be assumed unchanged. Restricting to file/data only breaks legitimate remote CSS/image/font references, so most teams will allowlist https and remain exposed to remote-fetch stalls and internal-address probing. Egress-block the worker network namespace regardless; treat allowed_schemes as defense in depth, not the primary control.
  • Timeouts (new footgun): process_timeout: false disables the generator timeout entirely. This is a legitimate escape hatch for queue workers governed by an external supervisor timeout, and a production hazard everywhere else. It must be forbidden on any synchronous request path and permitted only with a documented outer timeout.
  • Binary resolution (new subtlety): resolving a bare pdf.binary via PATH improves DX but makes the invoked interpreter/binary a function of the worker's environment — which can differ between web and queue containers, or change silently on image rebuild. Absolute paths are still used as-is; production config should use them.
  • Capability ceiling (unchanged): no JavaScript execution; client-side charts, map tiles, and JS pagination will not render. CSS is Paged Media-first — excellent for documents, weaker than Chromium for modern web CSS.
  • Performance (unchanged): per-render Python cold start (~0.5–2s) plus CPU-bound rasterization; long tables degrade non-linearly in some versions.

Key questions

  1. Is Python already part of the deployment image, or does this introduce a second runtime to the platform?
  2. If we mirror 3.1.0's allowed_schemes, do our templates need remote https resources — and if so, is egress already locked down?
  3. Will we enforce an absolute binary path and assert php-weasyprint / WeasyPrint versions at boot, given the silent-no-op behavior below 2.6?
  4. Do our templates depend on JavaScript, modern flex/grid, or web fonts fetched at runtime?
  5. Is the output a document (invoices, reports, statements) or a pixel-faithful web page? WeasyPrint wins the former, loses the latter.
  6. Can renders be queued and async with an external timeout, or is there a synchronous user-facing deadline?
  7. What is the acceptable per-document latency and monthly volume? At high volume a managed API may beat self-hosting on TCO.
  8. Are we willing to own a Python base image, font packages, and CVE patching?

Integration Approach

Stack fit

  • Strong fit if: Symfony-adjacent or polyglot shop, existing Python in the stack, document-centric output (invoices, statements, compliance reports), need for print-grade pagination, headers/footers, and PDF/A.
  • Weak fit if: pure-PHP team with no container ownership, Chrome already available, or pixel-perfect web-page capture is required — spatie/browsershot or a hosted API (DocRaptor, PDFShift) has materially lower TCO.

Migration path (Laravel)

  1. Spike first, install nothing. Build a Docker image with WeasyPrint pinned; render three of your real, hardest templates via Process::run('weasyprint ...') from an artisan command. Measure latency, memory, and fidelity. Gate everything on this.
  2. If green, port the pattern, not the package — and port 3.1.0's pattern too: pass an explicit scheme allowlist into the invocation wrapper, resolve the binary by absolute path, and require an explicit timeout value. Create app/Services/Pdf/WeasyPrintDriver.php behind a PdfRenderer contract; render Blade → temp file → symfony/process → validate %PDF magic bytes → cleanup.
  3. Add a startup assertion that the pinned php-weasyprint-equivalent behavior and binary version are what config assumes. This is the single highest-value lesson from 3.1.0: never let a security or timeout setting degrade silently.
  4. Optional: vendor the bundle's WeasyPrint service class if its argument/flag handling is worth keeping; do not register it via Composer.
  5. Only if Symfony is genuinely in the estate does installing the bundle make sense — and then it should be a standalone Symfony service, not embedded. If so, 3.1.0 is a straightforward upgrade: no breaking changes, additive config only, but it pairs with a php-weasyprint bump and a Symfony patch-level floor — treat all three as one tested change.

Compatibility

  • Verify composer.json PHP and symfony/* constraints against the target Laravel version before assuming installability. 3.1.0's raised Symfony minimums increase the chance of conflict; prefer avoiding the install entirely.
  • Pin the WeasyPrint binary version in the image and record it in config; use an absolute path. Treat binary or php-weasyprint upgrades as a tested change, not a rebuild side effect.
  • Confirm at runtime, not just at review time, that allowed_schemes is actually honored (i.e., that the underlying library is ≥2.6).
  • License chain is clean: bundle MIT, WeasyPrint BSD-3-Clause — confirm both at the exact pinned versions.

Sequencing Infra (Python runtime, fonts, network egress lockdown) → feasibility spike → PdfRenderer contract + driver (scheme allowlist, absolute binary, explicit timeout, boot-time version assertion) → queue worker + retry/timeout policy → golden-file visual regression tests → cutover.

Operational Impact

Maintenance

  • You own the Python runtime, native library set, and font corpus regardless of whether you use the bundle. Font packages are the most common silent-breakage source: a missing font yields substituted glyphs, not an error.
  • The bundle itself is small and needs little upkeep. 3.1.0 is maintenance-hygiene work plus two configuration affordances — evidence the project is alive, not evidence it is production-grade. The surrounding image still needs scheduled rebuilds for base-OS and library CVEs. Budget recurring engineering time, not a one-off.

Support

  • No vendor, no SLA. Upstream WeasyPrint has solid docs and an active maintainer; the PHP wrapper has a single maintainer and near-zero community. Expect to debug at the CLI layer, not the PHP layer — design logs to capture stderr, the exact command line, and the resolved binary path and version.
  • The 3.1.0 release notes themselves are the best support artifact available: they show the maintainers are tracking php-weasyprint releases and security patches. Weigh that positively, but it does not constitute a support commitment.

Scaling

  • Embarrassingly parallel but CPU-bound: scale by worker count, not concurrency-per-worker. Never render inline in a request cycle; put it behind a queue with a dedicated worker pool so PDF load cannot starve web traffic.
  • Memory is roughly proportional to document size and embedded image count; cap input size and page count defensively.

Failure modes to instrument

  • Binary missing or version-mismatched → nonzero exit; surface stderr verbatim.
  • Config silently inert (e.g., allowed_schemes set but underlying library < 2.6) → security posture believed-but-not-applied; assert versions at boot, alarm on drift.
  • process_timeout: false leaking into a request path → unbounded worker occupancy and queue collapse; lint config in CI and require an external supervisor timeout wherever the generator timeout is disabled.
  • PATH-resolved binary selecting an unexpected interpreter → divergent output between web and queue containers; pin absolute paths and log the resolved path per render.
  • Timeout on pathological documents (long tables, thousands of rows) → enforce a hard process timeout and a page cap.
  • Temp-file and /tmp accumulation → always unlink in finally; alert on disk pressure.
  • SSRF / remote-resource stalls from user-supplied HTML → egress-block the worker network namespace; scheme allowlisting is secondary, not sufficient.
  • Silent quality regressions after image rebuilds → maintain a golden-PDF visual regression suite comparing rendered output, not just exit codes.
  • Exit code 0 with truncated output → validate %PDF header and page count before persisting.

Ramp-up

  • PHP developers need 1–2 days to be productive with the process plumbing, and 1–2 weeks to become fluent in CSS Paged Media (@page rules, margin boxes, counters, break-inside, widow/orphan control) — this is the real skill gap, and it is unrelated to the bundle.
  • Document the supported CSS subset and a house style template so product teams stop expecting browser-equivalent rendering. This expectation gap is the most likely source of stakeholder friction.
  • Net TPM recommendation: the update does not change the decision. Treat this repository as a reference implementation and a signal that the Laravel/WeasyPrint adapter space is unoccupied. 3.1.0 is a genuine, security-relevant improvement to the design — scheme allowlisting and path resolution are worth copying into an in-house adapter behind a PdfRenderer interface — but the Symfony framing, bus-factor-one maintenance, and three-way version coupling all stand. Build in-house, or choose Chromium/headless or a managed API if the Python runtime footprint is unacceptable.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels