Installation
composer require disjfa/pwa-bundle
Add the bundle to config/bundles.php:
return [
// ...
Disjfa\PwaBundle\DisjfaPwaBundle::class => ['all' => true],
];
Configure .env
Set the public path for PWA assets:
PWA_PUBLIC_PATH=/pwa-assets
Copy Default Icon
cp vendor/disjfa/pwa-bundle/Resources/public/pwa-icon.png public/pwa-assets/
Include Meta Tag in Twig
Add to your base template (e.g., base.html.twig):
{{ include('@DisjfaPwa/meta.html.twig') }}
Verify Output
Visit your site in Chrome DevTools (Application > Manifest) to confirm the manifest.json and icons are generated.
For a quick PWA implementation:
pwa-icon.png as a placeholder.config/packages/disjfa_pwa.yaml.php bin/console cache:clear
Configuration
Define PWA settings in config/packages/disjfa_pwa.yaml:
disjfa_pwa:
favicon: /pwa-assets/pwa-icon.png
background_color: '#ffffff'
theme_color: '#3498db'
name: 'My App'
short_name: 'App'
start_url: '/'
display: 'standalone'
{{ app.name }}) for dynamic metadata.Icon Generation
icon-192x192.png) in public/pwa-assets/.manifest.json with references to these icons.liip_imagine filters (configured in config/packages/disjfa_pwa.yaml) to resize icons on-the-fly.Routing
Add PWA routes in config/routes/disjfa_pwa.yaml:
disjfa_pwa:
resource: '@DisjfaPwaBundle/Controller/'
type: annotation
/manifest.json and icon endpoints are accessible.Twig Integration
{% block head %}
{{ parent() }}
{{ include('@DisjfaPwa/meta.html.twig') }}
{% endblock %}
meta.html.twig) in templates/bundles/DisjfaPwa/ for customization.Dynamic Manifest
Extend the DisjfaPwaBundle to fetch metadata from a service:
// src/Service/PwaManifestService.php
class PwaManifestService {
public function getManifestData(): array {
return [
'name' => $this->appNameService->getName(),
'theme_color' => $this->themeService->getColor(),
];
}
}
Override the bundle’s ManifestController to use this service.
Multi-Language Support
Use Symfony’s translation system to localize manifest.json:
# config/packages/disjfa_pwa.yaml
disjfa_pwa:
name: '%app.name%'
short_name: '%app.short_name%'
Define translations in translations/messages.en.yaml:
app:
name: 'My App'
short_name: 'App'
Service Worker Integration While the bundle doesn’t include a service worker, pair it with Workbox or Laravel Mix for offline support.
Missing Public Path
PWA_PUBLIC_PATH not set in .env causes 404s for icons/manifest.PWA_PUBLIC_PATH (e.g., /pwa-assets).Icon Size Requirements
192x192, 512x512, etc., or use liip_imagine to resize dynamically.Caching Headers
manifest.json aggressively, causing stale PWA installs.<link rel="manifest" href="{{ path('disjfa_pwa_manifest', {'version': app.version}) }}">
Twig Template Overrides
meta.html.twig requires the file to exist in templates/bundles/DisjfaPwa/.{{ include('@DisjfaPwa/meta.html.twig') }} with ignore_missing: true to avoid errors during development.Validate manifest.json
Use Google’s Manifest Validator or Chrome DevTools (Application > Manifest) to check for errors.
Check Routes
Run php bin/console debug:router | grep disjfa_pwa to verify PWA routes are registered.
Log Configuration Dump the bundle’s config for debugging:
use Disjfa\PwaBundle\DisjfaPwaBundle;
dump($this->container->getParameter('disjfa_pwa'));
Custom Manifest Controller
Extend the bundle’s ManifestController to add logic:
// src/Controller/CustomManifestController.php
class CustomManifestController extends \Disjfa\PwaBundle\Controller\ManifestController {
public function manifestAction() {
$data = parent::manifestAction();
$data['custom_field'] = 'value';
return $this->json($data);
}
}
Override the route in config/routes/disjfa_pwa.yaml:
disjfa_pwa_manifest:
path: /manifest.json
controller: App\Controller\CustomManifestController::manifestAction
Event Listeners Hook into the bundle’s lifecycle (e.g., modify manifest data before generation):
// src/EventListener/PwaManifestListener.php
class PwaManifestListener implements KernelEventSubscriberInterface {
public static function getSubscribedEvents() {
return [
KernelEvents::CONTROLLER => 'onKernelController',
];
}
public function onKernelController(ControllerEvent $event) {
$controller = $event->getController();
if ($controller instanceof \Disjfa\PwaBundle\Controller\ManifestController) {
// Modify $controller's manifest data here
}
}
}
Asset Management
Use Symfony’s AssetComponent to version PWA assets:
<link rel="manifest" href="{{ asset('manifest.json', {'version': '1.0.0'}) }}">
Optimize Icons
Use liip_imagine to generate optimized icons:
liip_imagine:
filter_sets:
pwa_192x192:
quality: 85
filters:
- resize: { width: 192, height: 192, mode: outbound }
Reference in disjfa_pwa.yaml:
disjfa_pwa:
icons:
- /pwa-assets/icon.png
- /pwa-assets/icon@2x.png
Preload Manifest
Add to your HTML <head>:
<link rel="preload" href="/manifest.json" as="manifest">
Lazy-Load Non-Critical Icons Defer loading non-critical icons (e.g., splash screens) until after the page loads:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(() => {
// Load icons after SW registration
const icon = new Image();
icon.src = '/pwa-assets/splash.png';
});
});
}
How can I help you explore Laravel packages today?