ryangjchandler/laravel-bunny-fonts
Laravel integration for Bunny Fonts, the privacy-friendly Google Fonts alternative. Add Bunny Fonts stylesheets to your Blade views and register font families from a single config file, with no Google tracking and no cookie banners.
ryangjchandler/laravel-bunny-fonts lets you serve Bunny Fonts (a Google Fonts–API-compatible, privacy-friendly CDN) from your own domain instead of relying on a third-party request from the visitor's browser. v2.1.1 is a maintenance release that adds Laravel 13 support on top of 2.1.0 — no API changes, no deprecations.
Minimum steps:
composer require ryangjchandler/laravel-bunny-fonts
php artisan vendor:publish --tag="bunny-fonts-config"
Look here first:
config/bunny-fonts.php — the only real knobs are where downloaded font files and the generated stylesheet live (typically under public/). Read it before touching anything else; the defaults assume a writable public/ directory.family, weight, display, text).RyanChandler\BunnyFonts\Facades\BunnyFonts — that's where the fluent builder lives.First use case, in your layout <head>:
{{ BunnyFonts::font('Inter')->weights([400, 600, 700])->display('swap')->load() }}
That call resolves any not-yet-downloaded files, writes them to the configured public path, and emits the markup referencing your own domain. Drop it above your own stylesheet so your CSS overrides win.
Treat the stylesheet as a deploy artifact. The package downloads fonts lazily on first render. The pattern that works in production is: render your layout once during deploy (a php artisan tinker one-liner, a warm-up route, or a smoke-test request), then either commit the generated files or bake them into the image. After that, request-time rendering is a no-op read.
Centralise in a layout/component, never call it per-view. Build one Blade component (<x-fonts /> or a partial included from your base layout) so there's exactly one place families are declared and one place to bump weights. Scattering BunnyFonts:: calls across views makes cache invalidation guesswork.
One call per family, ordered by criticality. Chain weights() for the full range you actually use, and pick display('swap') for body text and display('optional') for decorative faces. Requesting weights you don't use in CSS is pure waste — the CSS API returns a @font-face block per weight and the downloader fetches every one.
Local development via a warm cache. Since the first hit does network I/O against fonts.bunny.net, either accept the one-off latency or pre-render the stylesheet as part of your composer setup/seed script. In Docker, mount or chown the fonts directory; a read-only public/ fails silently into an unstyled page if you're not watching logs.
Tests. Because fetching goes through Laravel's HTTP client, Http::fake() with a canned Google-format CSS response is the cheapest way to assert your layout renders the right <link> without hitting the network. Faking is preferable to pre-warming here — you also get to test the fallback path when a family is misspelled.
Multi-tenant / multi-site. Point the config at a per-tenant subdirectory (e.g. public/fonts/{tenant}) and keep a small map of family → directory. The generated CSS path becomes cache-key material; don't let it be user-controllable.
Upgrading across v2.x. v2.1.1 is drop-in from 2.1.0. The only actionable item is the constraint: if you're on Laravel 13, require ^2.1.1 explicitly — ^2.1.0 would resolve fine today but pin your reasoning; if you're below Laravel 10, this major line isn't for you.
fonts.bunny.net (proxy, firewall, no DNS in a build container) or an unwritable directory typically degrades to a missing/empty stylesheet rather than an exception. Always eyeball the rendered <head> and the fonts directory on a new environment before blaming your CSS.config:cache is mandatory after config edits. With a cached config the published paths are frozen; editing config/bunny-fonts.php and seeing no effect is the classic false alarm.public/ aren't fingerprinted or versioned by the Vite manifest. If you serve assets through a CDN, either include the fonts directory in the same bucket/sync or configure long-lived immutable caching on the generated filenames.text subset parameter end up in a remote URL and in filesystem paths. Whitelist families in a config array.ital handling, text= subsetting) can behave differently. If a build looks wrong, curl the equivalent fonts.bunny.net/css2?... URL directly and compare it against what got generated.public/fonts re-downloads everything on the next request. Include the directory in your deploy artifact/backup and be deliberate about php artisan optimize:clear-adjacent cleanup scripts.fetch-metadata 2.4.0 → 2.5.0) is CI-only. Neither change affects runtime behaviour, so there is nothing to re-test beyond a standard composer update on Laravel 13.How can I help you explore Laravel packages today?