jbtronics/dompdf-font-loader-bundle
A Symfony bundle that simplifies using custom fonts with Dompdf. Configure your font directories or assets and it automatically registers them, so generated PDFs can use custom fonts without manual font installation or @font-face setup.
Architecture fit. The package is a Symfony bundle, and that is the central fact of this evaluation. Its value is not the font-loading logic (which is thin) but the packaging: DI configuration plus a WarmableInterface cache warmer that pre-registers custom fonts into dompdf's font metrics cache during Symfony's cache warmup. Laravel has no bundle system and no cache-warming contract, so the packaging layer is inert in a Laravel app. What transfers is the pattern: register fonts into a writable font directory, generate the .ufm metrics files ahead of first render, and do it at deploy/build time rather than at request time. Adopting the package as a dependency buys nothing; adopting the pattern is worth roughly 60–120 lines of Laravel code (a service provider binding a registrar, a config file, and an Artisan command).
Integration feasibility. Three viable paths, in descending order of preference:
barryvdh/laravel-dompdf. Configure font_dir / font_cache / temp_dir in config/dompdf.php to point at storage/app/dompdf, register families from a config/pdf-fonts.php, and expose php artisan pdf:fonts:warm invoked from the deploy pipeline or container entrypoint.Technical risk. Low severity, narrow blast radius. Failure means wrong typography or missing glyphs in generated PDFs, not data loss or outage. The real risks are integration details, not the package:
.ufm files plus installed-fonts.json; 0.8.x used a different metrics format. The bundle's constraint must match whatever barryvdh/laravel-dompdf pins. A mismatch produces metrics that silently don't apply.vendor/ default is not writable in most production images), every render silently falls back to core fonts. This is the single most common production failure in this area and it is invisible without a visual regression test..otf. Remote @font-face loading is disabled by default (isRemoteEnabled=false), another silent-fallback source.Key questions for the team.
laravel-dompdf pin resolve to, and does the bundle's constraint overlap?Stack fit. Laravel 11/12 + barryvdh/laravel-dompdf + dompdf 2.x. The bundle is a design reference, not a dependency. The target shape is:
config/pdf-fonts.php — family name → font file paths, mirroring the bundle's config schema so the mental model transfers.FontRegistrar singleton that calls FontMetrics::registerFont() and is idempotent (skip if the .ufm exists and the source mtime/hash is unchanged).php artisan pdf:fonts:warm — the analogue of the bundle's cache warmer, safe to run repeatedly, with a lock to prevent concurrent writes.Migration path. Inventory first: grep every Blade/PDF template for font-family declarations and every @font-face block, and produce the family → file map before touching config. Then relocate font_dir/font_cache out of vendor/ into storage/app/dompdf, register families, warm, and compare output against a captured pre-change PDF. Only after a clean diff should the old fallback path be removed. If pulling the bundle's class, do it as a fork under our namespace with MIT attribution retained.
Compatibility. Verify against the resolved dompdf version, not the constraint string. Check that the fork's composer.json drops symfony/framework-bundle and symfony/dependency-injection entirely — otherwise the point of forking is lost. Confirm font file formats are TTF (or convert OTF → TTF upstream of the build). Confirm the PHP version matrix; the bundle targets Symfony's supported PHP range, which is generally a superset of ours.
Sequencing.
pdf:fonts:warm command with idempotency and a lock.Maintenance. The package has 2 stars, 0 dependents, and a single maintainer. Treat it as unsupported code you are reading, not a dependency you are tracking. The compensating factor is scope: the logic is small enough to own outright, and MIT licensing makes forking a non-event. If the team forks, budget roughly one day per year for dompdf-version drift and nothing else. Do not add it to a dependency-vulnerability or upgrade cadence as if it were infrastructure.
Support. No community, no issue backlog to lean on, no security response process. Acceptable only because the failure mode is cosmetic-to-functional PDF breakage in a non-critical path. If PDFs are a contractual deliverable (invoices, statements, regulated documents), that calculus shifts: the output correctness becomes business-critical even though the package isn't.
Scaling. The font cache is per-node filesystem state, so the scaling question is really a deployment question. Immutable images: bake the cache at build time — best option, zero runtime cost, deterministic. Mutable VMs or shared volumes: warm on boot, accepting a per-node startup cost. Warm time scales linearly with the number of faces and superlinearly with coverage; a Latin-only set is seconds, a CJK set can be tens of seconds and produces large artifacts. Runtime memory is dompdf's problem, not this package's — dompdf loads metrics per process, and rendering is memory-hungry regardless.
Failure modes, ranked by how hard they are to notice:
.ufm files exist.--force flag in the deploy..ufm files. Mitigation: file lock, or build-time-only warming which eliminates the race entirely.Ramp-up. Low. A mid-level Laravel developer who has not seen this bundle can implement the pattern in one to two days including tests, and needs zero familiarity with Symfony's DI or cache-warmer contracts. The bundle's contribution is confirming that the "warm at deploy, not at request" approach is the right shape — a design decision worth citing, not a library worth installing. Net recommendation: do not adopt as a dependency; adopt as a reference and reimplement natively, with a fork of the service class only if it demonstrably handles edge cases (font subsetting flags, metrics invalidation) faster than writing them fresh.
How can I help you explore Laravel packages today?