-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update README and implement Workbox Service Worker
Improved structure and clarity in README for better understanding of manifest configuration. Also added implementation of a Workbox-based Service Worker, providing offline capabilities and push notifications, improving overall robustness of the web application.
- Loading branch information
Showing
5 changed files
with
196 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SpomkyLabs\PwaBundle\Command; | ||
|
||
use Symfony\Component\Console\Attribute\AsCommand; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Style\SymfonyStyle; | ||
use Symfony\Component\DependencyInjection\Attribute\Autowire; | ||
use Symfony\Component\Filesystem\Filesystem; | ||
use Symfony\Component\Filesystem\Path; | ||
use Symfony\Component\HttpKernel\Config\FileLocator; | ||
|
||
#[AsCommand( | ||
name: 'pwa:sw', | ||
description: 'Initializes the Workbox-based Service Worker.', | ||
)] | ||
class WorkboxInitCommand extends Command | ||
{ | ||
public function __construct( | ||
#[Autowire('%kernel.project_dir%')] | ||
private readonly string $rootDir, | ||
private readonly Filesystem $filesystem, | ||
private readonly FileLocator $fileLocator, | ||
) { | ||
parent::__construct(); | ||
} | ||
|
||
protected function configure(): void | ||
{ | ||
$this | ||
->addOption( | ||
'public_folder', | ||
'p', | ||
InputOption::VALUE_OPTIONAL, | ||
'Public folder', | ||
$this->rootDir . '/public' | ||
) | ||
->addOption('output', 'o', InputOption::VALUE_OPTIONAL, 'Output file', 'sw.js') | ||
; | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output): int | ||
{ | ||
$io = new SymfonyStyle($input, $output); | ||
$io->title('Workbox Service Worker'); | ||
|
||
$publicFolder = Path::canonicalize($input->getOption('public_folder')); | ||
$outputFile = '/' . trim((string) $input->getOption('output'), '/'); | ||
|
||
if (! $this->filesystem->exists($publicFolder)) { | ||
$this->filesystem->mkdir($publicFolder); | ||
} | ||
|
||
$resourcePath = $this->fileLocator->locate('@SpomkyLabsPwaBundle/Resources/workbox.js', null, false); | ||
if (count($resourcePath) !== 1) { | ||
$io->error('Unable to find the Workbox resource.'); | ||
return self::FAILURE; | ||
} | ||
$resourcePath = $resourcePath[0]; | ||
$this->filesystem->copy($resourcePath, $publicFolder . $outputFile); | ||
|
||
|
||
$io->success('Workbox is ready to use!'); | ||
|
||
return self::SUCCESS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
importScripts( | ||
'https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js' | ||
); | ||
|
||
const { | ||
pageCache, // Cache pages with a network-first strategy. | ||
imageCache, // Cache images with a cache-first strategy. | ||
staticResourceCache, // Cache CSS, JS, and Web Worker requests with a cache-first strategy for 1 year. | ||
offlineFallback, // Serve an offline fallback page when the user is offline and try to revalidate the request when the user is online. | ||
warmStrategyCache, // Warm the cache with URLs that are likely to be visited next or during offline navigation. | ||
} = workbox.recipes; | ||
const { CacheFirst } = workbox.strategies; | ||
const { registerRoute } = workbox.routing; | ||
const { CacheableResponsePlugin } = workbox.cacheableResponse; | ||
const { ExpirationPlugin } = workbox.expiration; | ||
|
||
const PAGE_CACHE_NAME = 'pages'; | ||
const FONT_CACHE_NAME = 'fonts'; | ||
const STATIC_CACHE_NAME = 'assets'; | ||
const IMAGE_CACHE_NAME = 'images'; | ||
const OFFLINE_URI = '/offline'; // URI of the offline fallback page. | ||
const warmCacheUrls = [ // URLs to warm the cache with. | ||
'/', | ||
]; | ||
|
||
// *** Recipes *** | ||
// Cache pages with a network-first strategy. | ||
pageCache({ | ||
cacheName: PAGE_CACHE_NAME | ||
}); | ||
// Cache CSS, JS, and Web Worker requests with a cache-first strategy. | ||
staticResourceCache({ | ||
cacheName: STATIC_CACHE_NAME, | ||
}); | ||
// Cache images with a cache-first strategy. | ||
imageCache({ | ||
cacheName: IMAGE_CACHE_NAME, | ||
maxEntries: 60, // Default 60 images | ||
maxAgeSeconds: 60 * 60 * 24 * 30, // Default 30 days | ||
}); | ||
// Serve an offline fallback page when the user is offline and try to revalidate the request when the user is online. | ||
offlineFallback({ | ||
pageFallback: OFFLINE_URI, | ||
}); | ||
|
||
// Cache the underlying font files with a cache-first strategy. | ||
registerRoute( | ||
({request}) => request.destination === 'font', | ||
new CacheFirst({ | ||
cacheName: FONT_CACHE_NAME, | ||
plugins: [ | ||
new CacheableResponsePlugin({ | ||
statuses: [0, 200], | ||
}), | ||
new ExpirationPlugin({ | ||
maxAgeSeconds: 60 * 60 * 24 * 365, | ||
maxEntries: 30, | ||
}), | ||
], | ||
}), | ||
); | ||
|
||
// Warm the cache with URLs that are likely to be visited next or during offline navigation. | ||
const strategy = new CacheFirst(); | ||
warmStrategyCache({urls: warmCacheUrls, strategy}); |