foxws/laravel-pwa

PWA manifest and Blade directives for Laravel.

Maintainers

Package info

github.com/foxws/laravel-pwa

pkg:composer/foxws/laravel-pwa

Fund package maintenance!

Foxws

Statistics

Installs: 413

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.0.8 2026-03-07 11:05 UTC

This package is auto-updated.

Last update: 2026-03-07 11:07:06 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A minimal, opinionated Progressive Web App (PWA) package for Laravel. It provides Blade directives for the PWA head and service worker registration, and an Artisan command to generate your manifest.json and publish a sw.js stub.

The included service worker uses a network-first strategy for navigation and cache-first for static assets, while intentionally bypassing the cache for Inertia.js (X-Inertia) and Livewire (X-Livewire) requests to prevent stale responses.

Installation

composer require foxws/laravel-pwa

Publish the config file:

php artisan vendor:publish --tag="pwa-config"

Usage

Blade directives

Add @pwaHead inside your <head> and @pwaSw just before </body>:

<head>
    @pwaHead
</head>

<body>
    ...
    @pwaSw
</body>

This renders the theme-color meta tag, apple-touch-icon, manifest link, and the service worker registration script.

Both directives accept optional overrides:

@pwaHead(['themeColor' => '#ff0000', 'manifest' => '/custom.json'])

@pwaSw(['swPath' => '/sw.js', 'scope' => '/', 'debug' => true])

Or use them as Blade components:

<x-pwa-head theme-color="#ff0000" />

<x-pwa-sw sw-path="/sw.js" scope="/" />

The @pwaSw directive automatically picks up the CSP nonce from Vite::cspNonce() when set.

Icons

Icons are defined in a dedicated icons array in config/pwa.php, separate from the manifest. Each entry supports a disk key pointing to any configured Laravel filesystem disk. The src URL is resolved at generation time via Storage::disk()->url(). Set disk to null to fall back to path used as-is.

The default configuration assumes three icons — a mobile icon (192×192), a desktop icon (512×512), and an apple-touch-icon. Create the storage symlink and place all files there:

php artisan storage:link
$ ls storage/app/public/images/icons
storage/app/public/images/icons/apple-touch-icon.png
storage/app/public/images/icons/icon-192x192.png
storage/app/public/images/icons/icon-512x512.png

You can override each icon independently via .env:

PWA_ICON_MOBILE_PATH=/storage/images/icons/icon-192x192.png
PWA_ICON_DESKTOP_PATH=/storage/images/icons/icon-512x512.png
PWA_APPLE_TOUCH_ICON=/storage/images/icons/apple-touch-icon.png

For S3 or other remote disks, set the respective _DISK variable to the disk name — the URL will be resolved accordingly. Each icon can live on a different disk.

Generating the manifest and service worker

php artisan pwa:generate

This writes public/manifest.json from your config, and copies the sw.js stub to public/sw.js. Both paths are configurable via config/pwa.php.

The service worker serves an offline fallback page from public/offline.html. You must create this file yourself — see examples/offline.html for a starting point.

Configuration

// config/pwa.php

return [
    'manifest_path' => env('PWA_MANIFEST_PATH', 'manifest.json'),
    'sw_path'       => env('PWA_SW_PATH', 'sw.js'),
    'ignore_paths'  => ['/api/', '/livewire/', '/_inertia/'],
    'manifest' => [
        'id'             => env('PWA_ID', '/'),
        'name'           => env('APP_NAME', 'Laravel'),
        'short_name'     => env('PWA_SHORT_NAME', 'Laravel'),
        'description'    => env('PWA_DESCRIPTION', 'A Progressive Web Application setup for Laravel projects.'),
        'start_url'      => env('PWA_START_URL', '/'),
        'scope'          => env('PWA_SCOPE', '/'),
        'display_override' => ['fullscreen', 'standalone'],
        'display'        => env('PWA_DISPLAY', 'fullscreen'),
        'orientation'    => env('PWA_ORIENTATION', 'any'),
        'background_color' => env('PWA_BACKGROUND_COLOR', '#ffffff'),
        'theme_color'    => env('PWA_THEME_COLOR', '#6777ef'),
        'lang'           => env('PWA_LANG', 'en'),
        'dir'            => env('PWA_DIR', 'ltr'),
    ],
    'icons' => [
        // Mobile icon
        [
            'disk'  => env('PWA_ICON_DISK', null),
            'path'  => env('PWA_ICON_MOBILE_PATH', '/storage/images/icons/icon-192x192.png'),
            'sizes' => env('PWA_ICON_MOBILE_SIZES', '192x192'),
            'type'  => env('PWA_ICON_MOBILE_TYPE', 'image/png'),
        ],
        // Desktop icon
        [
            'disk'  => env('PWA_ICON_DISK', null),
            'path'  => env('PWA_ICON_DESKTOP_PATH', '/storage/images/icons/icon-512x512.png'),
            'sizes' => env('PWA_ICON_DESKTOP_SIZES', '512x512'),
            'type'  => env('PWA_ICON_DESKTOP_TYPE', 'image/png'),
        ],
    ],
    'apple_touch_icon' => env('PWA_APPLE_TOUCH_ICON', '/storage/images/icons/apple-touch-icon.png'),
];

Any key set to null in the manifest array is omitted from the generated JSON. Advanced keys such as shortcuts, screenshots, and categories can be added to the manifest array as needed.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.