Installation:
composer require silviolleite/laravelpwa
Publish the package assets:
php artisan vendor:publish --provider="SilvioLeite\LaravelPWA\LaravelPWAServiceProvider" --tag="pwa"
Add the middleware to app/Http/Kernel.php:
'web' => [
// ...
\SilvioLeite\LaravelPWA\Middleware\PWA::class,
],
First Use Case:
/public/manifest.json) and a service worker (/public/sw.js) generated by the package.Key Files to Inspect:
/resources/views/vendor/pwa/ (PWA-specific Blade templates)/config/pwa.php (Configuration for icons, colors, and service worker)/public/manifest.json (Auto-generated PWA manifest)Manifest Customization:
/config/pwa.php to define:
'name' => 'My App',
'short_name' => 'App',
'start_url' => '/',
'display' => 'standalone', // 'fullscreen', 'minimal-ui', etc.
'background_color' => '#ffffff',
'theme_color' => '#4285f4',
'icons' => [
['src' => '/icons/icon-72x72.png', 'sizes' => '72x72', 'type' => 'image/png'],
['src' => '/icons/icon-192x192.png', 'sizes' => '192x192', 'type' => 'image/png'],
// Add more icon sizes as needed
],
/public/icons/ (e.g., icon-192x192.png).Service Worker Integration:
sw.js in /public/sw.js. Extend it by:
/resources/views/vendor/pwa/sw.blade.php.pwa:generate Artisan command to regenerate assets after changes:
php artisan pwa:generate
SPA-Like Navigation:
<a href="{{ route('dashboard') }}" data-pwa-ignore>Dashboard</a>
Use data-pwa-ignore for links that should not trigger the service worker cache.Offline Support:
// In /resources/views/vendor/pwa/sw.blade.php
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('my-app-cache').then((cache) => {
return cache.addAll([
'/',
'/css/app.css',
'/js/app.js',
// Add other critical assets
]);
})
);
});
Dynamic Manifest Updates:
PWA facade to generate the manifest dynamically:
use SilvioLeite\LaravelPWA\Facades\PWA;
$manifest = PWA::manifest();
With Laravel Mix:
webpack.mix.js copies the generated manifest.json and sw.js:
mix.copy('public/manifest.json', 'public/manifest.json')
.copy('public/sw.js', 'public/sw.js');
With Inertia.js:
sw.js caches the root page and Inertia’s entry point:
cache.addAll([
'/',
'/js/app.js', // Inertia entry point
]);
Testing:
Fallback for Non-PWA Browsers:
// In app/Http/Middleware/PWA.php
if (!PWA::isSupported()) {
return response()->view('fallback');
}
HTTPS Requirement:
localhost). Use tools like Laravel Valet or ngrok for local testing.'debug' => env('APP_ENV') === 'local',
in /config/pwa.php.Service Worker Caching Issues:
sw.js aren’t reflected, clear the service worker cache in Chrome DevTools (Application > Service Workers > Unregister).const CACHE_VERSION = 'v2'; // Increment this to bust cache
Manifest Not Updating:
/config/pwa.php, regenerate assets:
php artisan pwa:generate
manifest.json path in your Blade layout is correct:
<link rel="manifest" href="{{ asset('manifest.json') }}">
Android Prompt Delays:
start_url in manifest.json points to a valid, interactive page.iOS Limitations:
Check Console Errors:
Failed to register a ServiceWorker (HTTPS or path issues).Manifest: Line: X, column: Y, Syntax error (invalid JSON in manifest.json).Validate Manifest:
Service Worker Debugging:
sw.js:
self.addEventListener('fetch', (event) => {
console.log('Fetch event:', event.request.url);
});
Lighthouse Audit:
Custom Service Worker Logic:
sw.js by publishing the template:
php artisan vendor:publish --provider="SilvioLeite\LaravelPWA\LaravelPWAServiceProvider" --tag="pwa-views"
/resources/views/vendor/pwa/sw.blade.php and add custom logic (e.g., precaching routes).Dynamic Manifest Data:
PWA facade to inject dynamic data (e.g., user-specific icons):
PWA::extend(function ($manifest) {
$manifest['icons'][] = [
'src' => '/user-avatars/' . auth()->id() . '.png',
'sizes' => '192x192',
];
});
Conditional PWA Enablement:
if (Auth::check() && Auth::user()->is_admin) {
return response()->view('admin.dashboard');
}
// PWA middleware will run otherwise
Custom Icons for Different Devices:
request() helper to serve device-specific icons:
'icons' => collect([
['src' => '/icons/icon-192x192.png', 'sizes' => '192x192'],
])->when(request()->userAgent()->is('iPhone'), function ($icons) {
$icons->push(['src' => '/icons/apple-touch-icon.png', 'sizes' => '180x180']);
})->toArray(),
How can I help you explore Laravel packages today?