# Laravel Google Fonts This Laravel package enables self-hosting Google Fonts with minimal friction, eliminating the need for external DNS lookups and reducing privacy concerns. When fonts are requested for the first time, the package automatically scrapes the CSS from Google Fonts, downloads the font files, stores them locally, and serves them inline or via local URLs. The package handles WOFF2 font formats, supports multiple font configurations, and provides automatic fallback to Google's CDN if local hosting fails. The core functionality revolves around a Blade directive `@googlefonts` that intelligently manages font loading. Fonts are stored in Laravel's filesystem (default: public disk), and the package automatically localizes all font URLs in the CSS. It supports CSP nonce attributes for security, preload tags for performance optimization, and customizable user agents for controlling which font formats are downloaded from Google's servers. ## APIs and Key Functions ### @googlefonts Blade Directive Renders Google Fonts in Blade templates by loading configured fonts from local storage or fetching them from Google Fonts API on first use. ```blade {{-- resources/views/layouts/app.blade.php --}}
const hello = 'world';
```
### Configuration Setup
Define Google Fonts URLs and package behavior in the configuration file to control font loading, storage, and rendering.
```php
[
'default' => 'https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,700;1,400;1,700&display=swap',
'code' => 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,700;1,400&display=swap',
'display' => 'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&display=swap',
],
// Storage disk (must be publicly accessible)
'disk' => 'public',
// Path prefix for font files
'path' => 'fonts',
// Inline CSS to reduce HTTP requests (true) or use tag (false)
'inline' => true,
// Generate preload tags for faster font loading
'preload' => false,
// Fallback to Google's CDN on errors (disable in debug mode to see exceptions)
'fallback' => ! env('APP_DEBUG'),
// User agent determines font format (WOFF2, WOFF, TTF, etc.)
'user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15',
];
```
### GoogleFonts::load() Method
Loads a font configuration and returns a Fonts object with methods for rendering HTML tags or retrieving URLs.
```php
googleFonts->load();
// Load named font
$codeFonts = $this->googleFonts->load('code');
// Load with options array
$secureFonts = $this->googleFonts->load([
'font' => 'display',
'nonce' => 'random-nonce-value'
]);
// Force re-download (useful for updates)
$freshFonts = $this->googleFonts->load('default', forceDownload: true);
return [
'default_inline' => (string) $defaultFonts->inline(),
'code_link' => (string) $codeFonts->link(),
'display_url' => $secureFonts->url(),
'fallback' => (string) $freshFonts->fallback(),
];
}
}
```
### Fonts Rendering Methods
The Fonts class provides multiple rendering options for including font stylesheets in HTML with different strategies.
```php
load('default');
// Inline CSS (fastest, no additional HTTP request)
$inlineHtml = $fonts->inline();
// Output:
// External stylesheet link
$linkHtml = $fonts->link();
// Output:
// Fallback to Google's CDN (used when local hosting fails)
$fallbackHtml = $fonts->fallback();
// Output:
// Get direct URL to local CSS file
$cssUrl = $fonts->url();
// Output: https://example.com/storage/fonts/952ee985ef/fonts.css
// Automatic rendering based on config (inline or link)
$autoHtml = $fonts->toHtml();
// Output depends on 'inline' config setting
// With nonce for Content Security Policy
$secureInline = app(GoogleFonts::class)->load(['font' => 'default', 'nonce' => 'abc123'])->inline();
// Output:
echo $inlineHtml;
```
### Artisan Command: google-fonts:fetch
Pre-download all configured fonts to local storage before deployment or during build process to avoid first-request delays.
```bash
# Fetch all fonts defined in config/google-fonts.php
php artisan google-fonts:fetch
# Example output:
# Start fetching Google Fonts...
# Fetching `default`...
# Fetching `code`...
# Fetching `display`...
# All done!
# Integrate into deployment script
cat > deploy.sh << 'EOF'
#!/bin/bash
composer install --no-dev --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan google-fonts:fetch
php artisan storage:link
EOF
# Use in CI/CD pipeline (GitHub Actions example)
cat > .github/workflows/deploy.yml << 'EOF'
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: composer install
- name: Cache Google Fonts
run: php artisan google-fonts:fetch
- name: Deploy to server
run: ./deploy.sh
EOF
```
### Package Installation
Install and configure the package in a Laravel application with optional configuration publishing.
```bash
# Install via Composer
composer require spatie/laravel-google-fonts
# Publish configuration file (optional)
php artisan vendor:publish --provider="Spatie\GoogleFonts\GoogleFontsServiceProvider" --tag="google-fonts-config"
# Create storage link for public disk
php artisan storage:link
# Verify storage/app/public/fonts directory is writable
ls -la storage/app/public/
# Test font loading in tinker
php artisan tinker
>>> app(\Spatie\GoogleFonts\GoogleFonts::class)->load('default');
>>> exit
```
### Advanced Configuration Examples
Customize font loading behavior for different environments, CDN hosting, and legacy browser support.
```php
[
'default' => 'https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap',
'headings' => 'https://fonts.googleapis.com/css2?family=Montserrat:wght@600;700;800&display=swap',
],
// Use custom disk for CDN deployment
'disk' => env('GOOGLE_FONTS_DISK', 'public'),
// Custom path for multi-tenant applications
'path' => 'assets/fonts/' . config('app.tenant_id'),
// External links in production, inline in development
'inline' => env('APP_ENV') === 'local',
// Enable preload in production only
'preload' => env('APP_ENV') === 'production',
// Always fallback in production, throw exceptions in development
'fallback' => env('APP_ENV') === 'production',
// Legacy browser support (WOFF instead of WOFF2)
'user_agent' => env('LEGACY_BROWSER_SUPPORT', false)
? 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'
: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15',
];
```
### Custom Disk Configuration for CDN
Configure a custom filesystem disk to serve fonts from a CDN like AWS CloudFront or DigitalOcean Spaces.
```php
[
// ... other disks
'fonts-cdn' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_FONTS_BUCKET'),
'url' => env('AWS_CLOUDFRONT_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'visibility' => 'public',
],
],
// config/google-fonts.php
return [
'disk' => 'fonts-cdn',
'path' => 'fonts',
'inline' => false, // Use links for CDN
'preload' => true, // Preload from CDN
// ... other settings
];
```
### Programmatic Font Loading in Services
Use the GoogleFonts service directly in application code for dynamic font management or API responses.
```php
'default',
'classic' => 'display',
'code' => 'code',
default => 'default',
};
return Cache::remember("theme_font_{$theme}", 3600, function () use ($fontKey) {
try {
$fonts = $this->googleFonts->load($fontKey);
return (string) $fonts->inline();
} catch (\Exception $e) {
report($e);
return $this->googleFonts->load($fontKey)->fallback();
}
});
}
public function preloadAllThemeFonts(): void
{
$themes = ['modern', 'classic', 'code'];
foreach ($themes as $theme) {
$fontKey = match($theme) {
'modern' => 'default',
'classic' => 'display',
'code' => 'code',
};
$this->googleFonts->load($fontKey, forceDownload: true);
}
}
}
```
### Testing Font Loading
Example test cases demonstrating font loading verification and snapshot testing for rendered output.
```php
load('default', forceDownload: true);
// Verify CSS file exists
Storage::disk('public')->assertExists('fonts/952ee985ef/fonts.css');
// Verify font files downloaded
$files = Storage::disk('public')->allFiles('fonts/952ee985ef');
$woff2Files = array_filter($files, fn($f) => str_ends_with($f, '.woff2'));
$this->assertGreaterThan(0, count($woff2Files));
// Verify HTML output
$inlineHtml = (string) $fonts->inline();
$this->assertStringContainsString('