Install the package:
composer require erag/laravel-pwa
Publish configuration:
php artisan erag:install-pwa
This generates config/pwa.php and sets up the PWA structure.
Add Blade directives to your main layout (resources/views/layouts/app.blade.php):
<head>
@PwaHead
<!-- Other head tags -->
</head>
<body>
<!-- Your content -->
@RegisterServiceWorkerScript
</body>
Verify HTTPS (required for PWA functionality) and test on Chrome/Firefox.
config/pwa.php with your app’s name, icons, and theme colors.php artisan erag:update-manifest to generate manifest.json and sw.js in public/pwa/.Configuration-Driven Setup:
config/pwa.php (e.g., name, icons, theme_color).PWA::update(['name' => 'My App', 'theme_color' => '#3b82f6']);
php artisan erag:update-manifest.Frontend Integration:
@PwaHead: Injects <link rel="manifest">, theme color, and other meta tags.@RegisterServiceWorkerScript: Adds the service worker registration script before </body>.Dynamic Logo Updates:
public function updateLogo(Request $request) {
$response = PWA::processLogo($request);
return $response['status'] ? back()->with('success', $response['message']) : back()->withErrors($response['errors']);
}
Offline Support:
resources/views/vendor/pwa/offline.blade.php for offline fallback pages.@RegisterServiceWorkerScript directive works seamlessly. For Alpine.js, ensure the script runs after Livewire’s Alpine initialization.main.js/main.jsx after the app mounts to avoid conflicts:
// main.js
import { registerSW } from '/pwa/sw.js';
import { createApp } from 'vue';
const app = createApp(App);
app.mount('#app');
if ('serviceWorker' in navigator) {
registerSW();
}
npx lighthouse https://your-app.test) to audit PWA compliance.php artisan erag:update-manifest to your deploy script to ensure manifest.json is always up-to-date.HTTPS Requirement:
trustproxy middleware in app/Http/Kernel.php for local development:
'trustProxies' => true,
https://localhost via Laravel Valet or laravel serve --secure.Service Worker Caching:
resources/js/pwa/sw.js to exclude certain routes:
const urlsToCache = [
'/',
'/dashboard',
// Exclude API routes
'!/api/*'
];
<link rel="stylesheet" href="{{ asset('css/app.css?v=' . filemtime(public_path('css/app.css')) }}">
iOS Quirks:
config/pwa.php:
'install-button' => true,
File Permissions:
public/pwa/ is writable by the web server:
chmod -R 755 public/pwa/
processLogo(), verify storage/app/public/pwa/ exists and is writable.Livewire Debugging:
@once block:
@once
@RegisterServiceWorkerScript
@endonce
Service Worker Errors:
Failed to register a ServiceWorker errors. Common causes:
sw.js (should be /pwa/sw.js).navigator.serviceWorker.register('/pwa/sw.js').catch(e => console.error('SW reg error:', e));
Manifest Validation:
manifest.json.short_name (required for iOS).display mode (use standalone or fullscreen for best results).Offline Debugging:
/offline or simulating a network error.Custom Service Worker:
sw.js by publishing the template:
php artisan vendor:publish --tag=pwa-assets
resources/js/pwa/sw.js to add custom caching logic (e.g., Stale-While-Revalidate for APIs).Dynamic Manifest Updates:
event(new PWAUpdated($newManifestData));
PWAUpdated::dispatch($data);
Push Notifications:
// sw.js
self.addEventListener('push', (event) => {
const data = event.data.json();
self.registration.showNotification(data.title, data.options);
});
Background Sync:
navigator.serviceWorker.ready.then((sw) => {
sw.sync.register('sync-tasks');
});
sw.js:
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-tasks') {
// Retry failed requests
}
});
debug Mode:
'debug' => true in config/pwa.php to log service worker events to the console. Disable in production.Livewire App Mode:
'livewire-app' => true if using Livewire’s SPA mode. This adjusts the service worker registration strategy.Icon Paths:
public/pwa/icons/ and referenced in config/pwa.php:
'icons' => [
['src' => 'icons/icon-192x192.png', 'sizes' => '192x192'],
['src' => 'icons/icon-512x512.png', 'sizes' => '512x512'],
],
icons/logo.png) for assets in the same directory.How can I help you explore Laravel packages today?