Custom Service Worker Rule
If needed, you can define custom sections in the service worker appended by your own services and depending on your application configuration or requirements.
To do so, you can create a service that implements SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRuleInterface.
Basic Example
<?php
declare(strict_types=1);
namespace App\ServiceWorkerRule;
use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRuleInterface;
final readonly class MyCustomRule implements ServiceWorkerRuleInterface
{
public function __construct(
private ServiceWorker $serviceWorker,
) {}
public function process(bool $debug = false): string
{
return <<<JS
// This will be added to the Service Worker
console.log('FOO-BAR from the Service Worker!');
JS;
}
}When using Symfony's service autoconfiguration, your rule will be automatically registered. If autoconfiguration is disabled, tag your service with spomky_labs_pwa.service_worker_rule.
Manual Service Registration
If you need to manually register your service:
services:
App\ServiceWorkerRule\MyCustomRule:
tags: ['spomky_labs_pwa.service_worker_rule']Advanced Example with Configuration
You can access the service worker configuration to conditionally generate JavaScript:
<?php
declare(strict_types=1);
namespace App\ServiceWorkerRule;
use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\Dto\Workbox;
use SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRuleInterface;
final readonly class ConditionalAnalyticsRule implements ServiceWorkerRuleInterface
{
public function __construct(
private ServiceWorker $serviceWorker,
) {}
public function process(bool $debug = false): string
{
// Access Workbox configuration
$workbox = $this->serviceWorker->workbox;
if (!$workbox->enabled) {
return '';
}
$analyticsCode = $debug
? "console.log('Analytics tracking (debug mode)');"
: "// Production analytics code";
return <<<JS
// Custom Analytics Tracking
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
{$analyticsCode}
}
});
JS;
}
}Rule Execution Order
Service worker rules are executed in a specific order based on their priority. The bundle's built-in rules have predefined priorities:
WorkboxImport
1024
Imports Workbox library
WorkboxHelpers
1023
Helper functions
Custom Rules
0 (default)
Your custom rules
Cache Strategies
-512
Cache configuration
Other Rules
Various
Specialized functionality
To control when your rule executes, you can implement additional logic or structure your JavaScript to work regardless of execution order.
Best Practices
Return empty string for disabled features: If your rule depends on configuration, return an empty string when it shouldn't be active
Use heredoc for multi-line JavaScript: Makes the code more readable
Respect the debug flag: Provide additional logging or different behavior when
$debug === trueAccess configuration through the ServiceWorker DTO: Don't rely on external configuration sources
Test thoroughly: Service workers run in a different context and can be hard to debug
Example: Custom Cache Invalidation
<?php
declare(strict_types=1);
namespace App\ServiceWorkerRule;
use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\ServiceWorkerRule\ServiceWorkerRuleInterface;
final readonly class CacheInvalidationRule implements ServiceWorkerRuleInterface
{
public function __construct(
private ServiceWorker $serviceWorker,
private string $appVersion,
) {}
public function process(bool $debug = false): string
{
$debugLog = $debug ? "console.log('Cache invalidation rule active');" : '';
return <<<JS
// Cache Invalidation - Version: {$this->appVersion}
{$debugLog}
self.addEventListener('activate', (event) => {
const currentVersion = '{$this->appVersion}';
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((cacheName) => !cacheName.includes(currentVersion))
.map((cacheName) => caches.delete(cacheName))
);
})
);
});
JS;
}
}Be careful when manipulating the service worker lifecycle events (install, activate, fetch). Improper handling can break your application's offline functionality.
Last updated
Was this helpful?