-
-
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.
Merge pull request #9 from Spomky-Labs/features/service-worker
Features/service worker
- Loading branch information
Showing
7 changed files
with
267 additions
and
14 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
* text=auto | ||
|
||
/.github export-ignore | ||
/doc export-ignore | ||
/tests export-ignore | ||
/.gitattributes export-ignore | ||
/.gitignore export-ignore | ||
/.php_cs.dist export-ignore | ||
/.scrutinizer.yml export-ignore | ||
/.travis.yml export-ignore | ||
/CODE_OF_CONDUCT.md export-ignore | ||
/README.md export-ignore | ||
/ecs.php export-ignore | ||
/infection.json.dist export-ignore | ||
/link export-ignore | ||
/Makefile export-ignore | ||
/phpstan.neon export-ignore | ||
/phpstan-baseline.neon export-ignore | ||
/phpunit.xml.dist export-ignore | ||
/rector export-ignore |
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,68 @@ | ||
#!/usr/bin/env php | ||
<?php | ||
|
||
if (!file_exists(__DIR__.'/vendor/autoload.php')) { | ||
echo "Run `composer install` before you run the `link` script.\n"; | ||
exit(1); | ||
} | ||
|
||
require __DIR__.'/vendor/autoload.php'; | ||
|
||
use Symfony\Component\Filesystem\Filesystem; | ||
|
||
/** | ||
* Links dependencies to components to a local clone of the main spomky-labs/phpwa GitHub repository. | ||
* Inspired by symfony/symfony and async-aws/aws | ||
*/ | ||
|
||
$copy = false !== $k = array_search('--copy', $argv, true); | ||
$copy && array_splice($argv, $k, 1); | ||
$pathToProject = $argv[1] ?? getcwd(); | ||
|
||
if (!is_dir("$pathToProject/vendor/spomky-labs/phpwa")) { | ||
echo 'Link (or copy) dependencies to components to a local clone of the spomky-labs/phpwa GitHub repository.'.PHP_EOL.PHP_EOL; | ||
echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; | ||
echo ' Use `--copy` to copy dependencies instead of symlink'.PHP_EOL.PHP_EOL; | ||
echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; | ||
exit(1); | ||
} | ||
|
||
$packages = []; | ||
|
||
$filesystem = new Filesystem(); | ||
$directories = glob(__DIR__.'/src/*', GLOB_ONLYDIR | GLOB_NOSORT); | ||
|
||
foreach ($directories as $dir) { | ||
if ($filesystem->exists($composer = "$dir/composer.json")) { | ||
$packages[json_decode(file_get_contents($composer))->name] = $dir; | ||
} | ||
} | ||
|
||
if (is_dir("$pathToProject/vendor/spomky-labs/phpwa")) { | ||
if ($filesystem->exists($composer = "$pathToProject/vendor/spomky-labs/phpwa/composer.json")) { | ||
$packages[json_decode(file_get_contents($composer))->name] = realpath(__DIR__); | ||
} | ||
} | ||
|
||
foreach (glob("$pathToProject/vendor/spomky-labs/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { | ||
$package = 'spomky-labs/'.basename($dir); | ||
if (!$copy && is_link($dir)) { | ||
echo "\"$package\" is already a symlink, skipping.".PHP_EOL; | ||
continue; | ||
} | ||
|
||
if (!isset($packages[$package])) { | ||
continue; | ||
} | ||
|
||
$packageDir = ('\\' === DIRECTORY_SEPARATOR || $copy) ? $packages[$package] : $filesystem->makePathRelative($packages[$package], dirname(realpath($dir))); | ||
$filesystem->remove($dir); | ||
|
||
if ($copy) { | ||
$filesystem->mirror($packageDir, $dir); | ||
echo "\"$package\" has been copied from \"$packages[$package]\".".PHP_EOL; | ||
} else { | ||
$filesystem->symlink(rtrim($packageDir, '/'), $dir); | ||
echo "\"$package\" has been linked to \"$packages[$package]\".".PHP_EOL; | ||
} | ||
} |
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,69 @@ | ||
<?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; | ||
use function count; | ||
|
||
#[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}); |