From e5c94c5c40e554248f09ca43fbe19768ec65a86a Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:09:22 +0100 Subject: [PATCH 1/6] Better Service Worker --- phpstan-baseline.neon | 2 +- src/DependencyInjection/Configuration.php | 43 ++++--- src/Dto/Asset.php | 17 +++ src/Dto/Icon.php | 2 +- src/Dto/Screenshot.php | 2 +- src/Dto/ServiceWorker.php | 2 +- src/Dto/Workbox.php | 26 +++-- src/Normalizer/AssetNormalizer.php | 66 +++++++++++ src/Normalizer/IconNormalizer.php | 15 +-- src/Normalizer/ScreenshotNormalizer.php | 8 +- src/Resources/sw-skeleton.js | 2 - src/Service/ServiceWorkerCompiler.php | 135 ++++++++++------------ src/Twig/PwaRuntime.php | 29 ++++- 13 files changed, 225 insertions(+), 124 deletions(-) create mode 100644 src/Dto/Asset.php create mode 100644 src/Normalizer/AssetNormalizer.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 81a2adf..a242c4b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -483,4 +483,4 @@ parameters: - message: "#^Parameter \\#1 \\$string of function mb_strlen expects string, string\\|null given\\.$#" count: 1 - path: src/Subscriber/PwaDevServerSubscriber.php + path: src/Subscriber/PwaDevServerSubscriber.php \ No newline at end of file diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 511cfa8..5912978 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -130,18 +130,6 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void ) ->example('//STANDARD_RULES_PLACEHOLDER') ->end() - ->scalarNode('precaching_placeholder') - ->defaultValue('//PRECACHING_PLACEHOLDER') - ->info( - 'The placeholder for the precaching. Will be replaced by the assets and versions.' - ) - ->example('//PRECACHING_PLACEHOLDER') - ->end() - ->scalarNode('warm_cache_placeholder') - ->defaultValue('//WARM_CACHE_URLS_PLACEHOLDER') - ->info('The placeholder for the warm cache. Will be replaced by the URLs.') - ->example('//WARM_CACHE_URLS_PLACEHOLDER') - ->end() ->scalarNode('offline_fallback_placeholder') ->defaultValue('//OFFLINE_FALLBACK_PLACEHOLDER') ->info('The placeholder for the offline fallback. Will be replaced by the URL.') @@ -156,10 +144,37 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void ->end() ->append( $this->getUrlNode( - 'offline_fallback', - 'The URL of the offline fallback. If not set, the offline fallback will be disabled.' + 'page_fallback', + 'The URL of the offline page fallback.' + ) + ) + ->append( + $this->getUrlNode( + 'image_fallback', + 'The URL of the offline image fallback.' ) ) + ->append( + $this->getUrlNode( + 'font_fallback', + 'The URL of the offline font fallback.' + ) + ) + ->scalarNode('image_regex') + ->defaultValue('/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/') + ->info('The regex to match the images.') + ->example('/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/') + ->end() + ->integerNode('max_image_cache_entries') + ->defaultValue(60) + ->info('The maximum number of entries in the image cache.') + ->example([50, 100, 200]) + ->end() + ->integerNode('network_timeout_seconds') + ->defaultValue(3) + ->info('The network timeout in seconds before cache is called (for warm cache URLs only).') + ->example([1, 2, 5]) + ->end() ->arrayNode('warm_cache_urls') ->treatNullLike([]) ->treatFalseLike([]) diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php new file mode 100644 index 0000000..6d7a1be --- /dev/null +++ b/src/Dto/Asset.php @@ -0,0 +1,17 @@ + diff --git a/src/Dto/Screenshot.php b/src/Dto/Screenshot.php index bc71554..0e30627 100644 --- a/src/Dto/Screenshot.php +++ b/src/Dto/Screenshot.php @@ -11,7 +11,7 @@ final class Screenshot { use TranslatableTrait; - public null|string $src = null; + public Asset $src; public null|int $height = null; diff --git a/src/Dto/ServiceWorker.php b/src/Dto/ServiceWorker.php index ca72002..7863830 100644 --- a/src/Dto/ServiceWorker.php +++ b/src/Dto/ServiceWorker.php @@ -10,7 +10,7 @@ final class ServiceWorker { public bool $enabled; - public string $src; + public Asset $src; public string $dest; diff --git a/src/Dto/Workbox.php b/src/Dto/Workbox.php index aa161ef..efa4d2d 100644 --- a/src/Dto/Workbox.php +++ b/src/Dto/Workbox.php @@ -21,27 +21,37 @@ final class Workbox #[SerializedName('workbox_import_placeholder')] public string $workboxImportPlaceholder; - #[SerializedName('warm_cache_placeholder')] - public string $warmCachePlaceholder; - #[SerializedName('standard_rules_placeholder')] public string $standardRulesPlaceholder; - #[SerializedName('precaching_placeholder')] - public string $precachingPlaceholder; - #[SerializedName('offline_fallback_placeholder')] public string $offlineFallbackPlaceholder; #[SerializedName('widgets_placeholder')] public string $widgetsPlaceholder; - #[SerializedName('offline_fallback')] - public null|Url $offlineFallback = null; + #[SerializedName('page_fallback')] + public null|Url $pageFallback = null; + + #[SerializedName('image_fallback')] + public null|Url $imageFallback = null; + + #[SerializedName('font_fallback')] + public null|Url $fontFallback = null; /** * @var array */ #[SerializedName('warm_cache_urls')] public array $warmCacheUrls = []; + #[SerializedName('network_timeout_seconds')] + public int $networkTimeoutSeconds = 3; + #[SerializedName('max_image_cache_entries')] + public int $maxImageCacheEntries = 60; + + #[SerializedName('image_regex')] + public string $imageRegex = '/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/'; + + #[SerializedName('static_regex')] + public string $staticRegex = '/\.(css|js|json|xml|txt|woff2|ttf|eot|otf|map|webmanifest)$/'; } diff --git a/src/Normalizer/AssetNormalizer.php b/src/Normalizer/AssetNormalizer.php new file mode 100644 index 0000000..e93d538 --- /dev/null +++ b/src/Normalizer/AssetNormalizer.php @@ -0,0 +1,66 @@ +src, '/')) { + $asset = $this->assetMapper->getAsset($object->src); + $url = $asset?->publicPath; + } + if ($url === null) { + $url = $object->src; + } + + return $url; + } + + public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed + { + assert(is_string($data)); + + return Asset::create($data); + } + + public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool + { + return $data instanceof Asset; + } + + public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool + { + return $type === Asset::class; + } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + Asset::class => true, + ]; + } +} diff --git a/src/Normalizer/IconNormalizer.php b/src/Normalizer/IconNormalizer.php index b591849..19beba0 100644 --- a/src/Normalizer/IconNormalizer.php +++ b/src/Normalizer/IconNormalizer.php @@ -24,19 +24,14 @@ public function __construct( public function normalize(mixed $object, string $format = null, array $context = []): array { assert($object instanceof Icon); - $url = null; - $asset = null; - if (! str_starts_with($object->src, '/')) { - $asset = $this->assetMapper->getAsset($object->src); - $url = $asset?->publicPath; + $format = null; + if (! str_starts_with($object->src->src, '/')) { + $asset = $this->assetMapper->getAsset($object->src->src); + $format = $this->getFormat($object, $asset); } - if ($url === null) { - $url = $object->src; - } - $format = $this->getFormat($object, $asset); $result = [ - 'src' => $url, + 'src' => $object->src, 'sizes' => $object->getSizeList(), 'type' => $format, 'purpose' => $object->purpose, diff --git a/src/Normalizer/ScreenshotNormalizer.php b/src/Normalizer/ScreenshotNormalizer.php index 22ef59f..3e042b2 100644 --- a/src/Normalizer/ScreenshotNormalizer.php +++ b/src/Normalizer/ScreenshotNormalizer.php @@ -28,15 +28,15 @@ public function normalize(mixed $object, string $format = null, array $context = assert($object instanceof Screenshot); $url = null; $asset = null; - if (! str_starts_with($object->src, '/')) { - $asset = $this->assetMapper->getAsset($object->src); + if (! str_starts_with($object->src->src, '/')) { + $asset = $this->assetMapper->getAsset($object->src->src); $url = $asset?->publicPath; + $format = $this->getFormat($object, $asset); } if ($url === null) { - $url = $object->src; + $url = $object->src->src; } ['sizes' => $sizes, 'formFactor' => $formFactor] = $this->getSizes($object, $asset); - $format = $this->getFormat($object, $asset); $result = [ 'src' => $url, diff --git a/src/Resources/sw-skeleton.js b/src/Resources/sw-skeleton.js index f7139c9..35ece5a 100644 --- a/src/Resources/sw-skeleton.js +++ b/src/Resources/sw-skeleton.js @@ -1,7 +1,5 @@ // *** Workbox Bundle rules *** //WORKBOX_IMPORT_PLACEHOLDER //STANDARD_RULES_PLACEHOLDER -//PRECACHING_PLACEHOLDER -//WARM_CACHE_URLS_PLACEHOLDER //OFFLINE_FALLBACK_PLACEHOLDER //WIDGETS_PLACEHOLDER diff --git a/src/Service/ServiceWorkerCompiler.php b/src/Service/ServiceWorkerCompiler.php index 1e951a8..6ffa35b 100644 --- a/src/Service/ServiceWorkerCompiler.php +++ b/src/Service/ServiceWorkerCompiler.php @@ -38,12 +38,12 @@ public function compile(): ?string } $serviceWorker = $this->serviceWorker; - if (! str_starts_with($serviceWorker->src, '/')) { - $asset = $this->assetMapper->getAsset($serviceWorker->src); + if (! str_starts_with($serviceWorker->src->src, '/')) { + $asset = $this->assetMapper->getAsset($serviceWorker->src->src); assert($asset !== null, 'Unable to find service worker source asset'); $body = $asset->content ?? file_get_contents($asset->sourcePath); } else { - $body = file_get_contents($serviceWorker->src); + $body = file_get_contents($serviceWorker->src->src); } assert(is_string($body), 'Unable to find service worker source content'); $workbox = $serviceWorker->workbox; @@ -58,8 +58,6 @@ private function processWorkbox(Workbox $workbox, string $body): string { $body = $this->processWorkboxImport($workbox, $body); $body = $this->processStandardRules($workbox, $body); - $body = $this->processPrecachedAssets($workbox, $body); - $body = $this->processWarmCacheUrls($workbox, $body); $body = $this->processWidgets($workbox, $body); return $this->processOfflineFallback($workbox, $body); @@ -71,87 +69,77 @@ private function processStandardRules(Workbox $workbox, string $body): string return $body; } - $declaration = << request.destination === 'style' || request.destination === 'script' || request.destination === 'worker'; -workbox.routing.registerRoute( - matchCallback, - new workbox.strategies.CacheFirst({ - cacheName: 'static-resources', - plugins: [ - new workbox.cacheableResponse.CacheableResponsePlugin({ - statuses: [0, 200], - }), - ], - }) -); -STANDARD_RULE_STRATEGY; - - return str_replace($workbox->standardRulesPlaceholder, trim($declaration), $body); - } - - private function processPrecachedAssets(Workbox $workbox, string $body): string - { - if (! str_contains($body, $workbox->precachingPlaceholder)) { - return $body; - } - $result = []; + $images = []; + $static = []; foreach ($this->assetMapper->allAssets() as $asset) { - $result[] = [ - 'url' => $asset->publicPath, - 'revision' => $asset->digest, - ]; - } - $assets = $this->serializer->serialize($result, 'json', [ - JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR, - ]); - - $declaration = <<precachingPlaceholder, trim($declaration), $body); - } - - private function processWarmCacheUrls(Workbox $workbox, string $body): string - { - if (! str_contains($body, $workbox->warmCachePlaceholder)) { - return $body; - } - $urls = $workbox->warmCacheUrls; - if (count($urls) === 0) { - return $body; + if (preg_match($workbox->imageRegex, $asset->sourcePath) === 1) { + $images[] = $asset->publicPath; + } elseif (preg_match($workbox->staticRegex, $asset->sourcePath) === 1) { + $static[] = $asset->publicPath; + } } - - $routes = $this->serializer->serialize($urls, 'json', [ + $jsonOptions = [ JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR, - ]); + ]; + $imageUrls = $this->serializer->serialize($images, 'json', $jsonOptions); + $staticUrls = $this->serializer->serialize($static, 'json', $jsonOptions); + $routes = $this->serializer->serialize($workbox->warmCacheUrls, 'json', $jsonOptions); - $declaration = <<networkTimeoutSeconds}, + warmCache: {$routes} +}); +workbox.recipes.imageCache({ + cacheName: 'images', + maxEntries: {$workbox->maxImageCacheEntries}, + warmCache: {$imageUrls} +}); +workbox.recipes.staticResourceCache({ + cacheName: 'assets', + warmCache: {$staticUrls} }); -WARM_CACHE_URL_STRATEGY; +STANDARD_RULE_STRATEGY; - return str_replace($workbox->warmCachePlaceholder, trim($declaration), $body); + return str_replace($workbox->standardRulesPlaceholder, trim($declaration), $body); } private function processOfflineFallback(Workbox $workbox, string $body): string { - if (! str_contains($body, $workbox->offlineFallbackPlaceholder) || $workbox->offlineFallback === null) { + if (! str_contains($body, $workbox->offlineFallbackPlaceholder)) { + return $body; + } + if ($workbox->pageFallback === null && $workbox->imageFallback === null && $workbox->fontFallback === null) { return $body; } - $url = $this->serializer->serialize($workbox->offlineFallback, 'json', [ + $jsonOptions = [ JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR, - ]); + ]; + $pageFallback = $workbox->pageFallback === null ? 'null' : $this->serializer->serialize( + $workbox->pageFallback, + 'json', + $jsonOptions + ); + $imageFallback = $workbox->imageFallback === null ? 'null' : $this->serializer->serialize( + $workbox->imageFallback, + 'json', + $jsonOptions + ); + $fontFallback = $workbox->fontFallback === null ? 'null' : $this->serializer->serialize( + $workbox->fontFallback, + 'json', + $jsonOptions + ); $declaration = <<offlineFallbackPlaceholder, trim($declaration), $body); @@ -245,18 +233,13 @@ private function processWorkboxImport(Workbox $workbox, string $body): string } if ($workbox->useCDN === true) { $declaration = <<version}/workbox-sw.js' -); +importScripts('https://storage.googleapis.com/workbox-cdn/releases/{$workbox->version}/workbox-sw.js'); IMPORT_CDN_STRATEGY; } else { $publicUrl = '/' . trim($workbox->workboxPublicUrl, '/'); $declaration = <<importMapConfigReader->findRootImportMapEntry('workbox-window') !== null; - $workboxUrl = $hasWorkboxWindow ? 'workbox-window' : 'https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-window.prod.mjs'; - $declaration = <<workbox->enabled === true) { + $hasWorkboxWindow = $this->importMapConfigReader->findRootImportMapEntry('workbox-window') !== null; + $workboxUrl = $hasWorkboxWindow ? 'workbox-window' : 'https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-window.prod.mjs'; + $declaration = << import {Workbox} from '{$workboxUrl}'; if ('serviceWorker' in navigator) { @@ -89,6 +90,22 @@ private function injectServiceWorker(string $output, bool $injectSW, array $swAt } SERVICE_WORKER; + } else { + $declaration = << + const registerServiceWorker = async () => { + if ("serviceWorker" in navigator) { + try { + await navigator.serviceWorker.register('{$url}'{$registerOptions}); + } catch (error) { + // Nothing to do + } + } + }; + registerServiceWorker(); + +SERVICE_WORKER; + } return $output . sprintf('%s%s', PHP_EOL, $declaration); } @@ -123,13 +140,13 @@ private function getIconInfo(Icon $icon): array { $url = null; $format = $icon->format; - if (! str_starts_with($icon->src, '/')) { - $asset = $this->assetMapper->getAsset($icon->src); + if (! str_starts_with($icon->src->src, '/')) { + $asset = $this->assetMapper->getAsset($icon->src->src); $url = $asset?->publicPath; $format = $this->getFormat($icon, $asset); } if ($url === null) { - $url = $icon->src; + $url = $icon->src->src; } return [ From 0e839f9bc8a2acd2d3d19f86167cf81a578d73cf Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:11:13 +0100 Subject: [PATCH 2/6] Better Service Worker --- src/DependencyInjection/Configuration.php | 25 ++++++----------------- src/Dto/Asset.php | 5 +++-- src/Dto/Workbox.php | 2 ++ src/Normalizer/AssetNormalizer.php | 8 ++++++-- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 5912978..f40a59a 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -142,24 +142,9 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void ) ->example('//WIDGETS_PLACEHOLDER') ->end() - ->append( - $this->getUrlNode( - 'page_fallback', - 'The URL of the offline page fallback.' - ) - ) - ->append( - $this->getUrlNode( - 'image_fallback', - 'The URL of the offline image fallback.' - ) - ) - ->append( - $this->getUrlNode( - 'font_fallback', - 'The URL of the offline font fallback.' - ) - ) + ->append($this->getUrlNode('page_fallback', 'The URL of the offline page fallback.')) + ->append($this->getUrlNode('image_fallback', 'The URL of the offline image fallback.')) + ->append($this->getUrlNode('font_fallback', 'The URL of the offline font fallback.')) ->scalarNode('image_regex') ->defaultValue('/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/') ->info('The regex to match the images.') @@ -172,7 +157,9 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void ->end() ->integerNode('network_timeout_seconds') ->defaultValue(3) - ->info('The network timeout in seconds before cache is called (for warm cache URLs only).') + ->info( + 'The network timeout in seconds before cache is called (for warm cache URLs only).' + ) ->example([1, 2, 5]) ->end() ->arrayNode('warm_cache_urls') diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php index 6d7a1be..d24f9ac 100644 --- a/src/Dto/Asset.php +++ b/src/Dto/Asset.php @@ -6,8 +6,9 @@ final class Asset { - public function __construct(public string $src) - { + public function __construct( + public string $src + ) { } public static function create(string $data): self diff --git a/src/Dto/Workbox.php b/src/Dto/Workbox.php index efa4d2d..a908b43 100644 --- a/src/Dto/Workbox.php +++ b/src/Dto/Workbox.php @@ -44,8 +44,10 @@ final class Workbox */ #[SerializedName('warm_cache_urls')] public array $warmCacheUrls = []; + #[SerializedName('network_timeout_seconds')] public int $networkTimeoutSeconds = 3; + #[SerializedName('max_image_cache_entries')] public int $maxImageCacheEntries = 60; diff --git a/src/Normalizer/AssetNormalizer.php b/src/Normalizer/AssetNormalizer.php index e93d538..e73d55a 100644 --- a/src/Normalizer/AssetNormalizer.php +++ b/src/Normalizer/AssetNormalizer.php @@ -49,8 +49,12 @@ public function supportsNormalization(mixed $data, string $format = null, array return $data instanceof Asset; } - public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool - { + public function supportsDenormalization( + mixed $data, + string $type, + string $format = null, + array $context = [] + ): bool { return $type === Asset::class; } From a3f87c2c65da1cb8f90fe37b6a1e661435ccef34 Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:11:54 +0100 Subject: [PATCH 3/6] Better Service Worker --- phpstan-baseline.neon | 50 ++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a242c4b..d5ec183 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -220,6 +220,11 @@ parameters: count: 1 path: src/Dto/ScopeExtension.php + - + message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Screenshot has an uninitialized property \\$src\\. Give it default value or assign it in the constructor\\.$#" + count: 1 + path: src/Dto/Screenshot.php + - message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Screenshot\\:\\:getLabel\\(\\) should return string\\|Symfony\\\\Contracts\\\\Translation\\\\TranslatableInterface\\|null but returns array\\\\|string\\|Symfony\\\\Contracts\\\\Translation\\\\TranslatableInterface\\|null\\.$#" count: 1 @@ -325,11 +330,6 @@ parameters: count: 1 path: src/Dto/Workbox.php - - - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Workbox has an uninitialized property \\$precachingPlaceholder\\. Give it default value or assign it in the constructor\\.$#" - count: 1 - path: src/Dto/Workbox.php - - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Workbox has an uninitialized property \\$standardRulesPlaceholder\\. Give it default value or assign it in the constructor\\.$#" count: 1 @@ -345,11 +345,6 @@ parameters: count: 1 path: src/Dto/Workbox.php - - - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Workbox has an uninitialized property \\$warmCachePlaceholder\\. Give it default value or assign it in the constructor\\.$#" - count: 1 - path: src/Dto/Workbox.php - - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Workbox has an uninitialized property \\$widgetsPlaceholder\\. Give it default value or assign it in the constructor\\.$#" count: 1 @@ -390,6 +385,31 @@ parameters: count: 1 path: src/ImageProcessor/GDImageProcessor.php + - + message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\AssetNormalizer\\:\\:denormalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Normalizer/AssetNormalizer.php + + - + message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\AssetNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Normalizer/AssetNormalizer.php + + - + message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\AssetNormalizer\\:\\:supportsDenormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Normalizer/AssetNormalizer.php + + - + message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\AssetNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Normalizer/AssetNormalizer.php + + - + message: "#^PHPDoc tag @return with type array\\ is incompatible with native type string\\.$#" + count: 1 + path: src/Normalizer/AssetNormalizer.php + - message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\IconNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" count: 1 @@ -420,21 +440,11 @@ parameters: count: 1 path: src/Normalizer/ScreenshotNormalizer.php - - - message: "#^Parameter \\#1 \\$haystack of function str_starts_with expects string, string\\|null given\\.$#" - count: 1 - path: src/Normalizer/ScreenshotNormalizer.php - - message: "#^Parameter \\#1 \\$image of method SpomkyLabs\\\\PwaBundle\\\\ImageProcessor\\\\ImageProcessor\\:\\:getSizes\\(\\) expects string, string\\|false given\\.$#" count: 1 path: src/Normalizer/ScreenshotNormalizer.php - - - message: "#^Parameter \\#1 \\$logicalPath of method Symfony\\\\Component\\\\AssetMapper\\\\AssetMapperInterface\\:\\:getAsset\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/Normalizer/ScreenshotNormalizer.php - - message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\ServiceWorkerNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" count: 1 From 60cf7c556fb7e6bb0a48bd1259b6c0ec371202b9 Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:13:24 +0100 Subject: [PATCH 4/6] Better Service Worker --- tests/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/config.php b/tests/config.php index 37a94d8..3d55e1d 100644 --- a/tests/config.php +++ b/tests/config.php @@ -227,7 +227,7 @@ 'use_cache' => true, 'workbox' => [ 'warm_cache_urls' => ['privacy_policy', 'terms_of_service'], - 'offline_fallback' => '/offline.html', + 'page_fallback' => '/offline.html', ], ], ]); From cda04c62ba162e4ed1588489ef335e45d45175bf Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:16:48 +0100 Subject: [PATCH 5/6] Better Service Worker --- .github/workflows/coding-standards.yml | 2 +- .github/workflows/rector_checkstyle.yaml | 2 +- .github/workflows/static-analyze.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 8eb33ee..7566d43 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['8.2'] + php-versions: ['8.3'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: diff --git a/.github/workflows/rector_checkstyle.yaml b/.github/workflows/rector_checkstyle.yaml index e8ffdd2..fffbc46 100644 --- a/.github/workflows/rector_checkstyle.yaml +++ b/.github/workflows/rector_checkstyle.yaml @@ -8,7 +8,7 @@ jobs: strategy: matrix: operating-system: [ ubuntu-latest ] - php-versions: ['8.2'] + php-versions: ['8.3'] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/static-analyze.yml b/.github/workflows/static-analyze.yml index 52d9e77..7808228 100644 --- a/.github/workflows/static-analyze.yml +++ b/.github/workflows/static-analyze.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['8.2'] + php-versions: ['8.3'] name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} steps: From adb82b9ee481bebc99b1577ab5f52f3340945eed Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Tue, 6 Feb 2024 22:22:29 +0100 Subject: [PATCH 6/6] Better Service Worker --- phpstan-baseline.neon | 12 +----------- src/Subscriber/PwaDevServerSubscriber.php | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d5ec183..aeb4319 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -95,11 +95,6 @@ parameters: count: 1 path: src/Command/CreateServiceWorkerCommand.php - - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, array\\|string given\\.$#" - count: 1 - path: src/Command/CreateServiceWorkerCommand.php - - message: "#^Parameter \\#2 \\$targetFile of method Symfony\\\\Component\\\\Filesystem\\\\Filesystem\\:\\:copy\\(\\) expects string, mixed given\\.$#" count: 1 @@ -488,9 +483,4 @@ parameters: - message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\UrlNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" count: 1 - path: src/Normalizer/UrlNormalizer.php - - - - message: "#^Parameter \\#1 \\$string of function mb_strlen expects string, string\\|null given\\.$#" - count: 1 - path: src/Subscriber/PwaDevServerSubscriber.php \ No newline at end of file + path: src/Normalizer/UrlNormalizer.php \ No newline at end of file diff --git a/src/Subscriber/PwaDevServerSubscriber.php b/src/Subscriber/PwaDevServerSubscriber.php index a1980d7..e917913 100644 --- a/src/Subscriber/PwaDevServerSubscriber.php +++ b/src/Subscriber/PwaDevServerSubscriber.php @@ -151,7 +151,7 @@ private function serveWorkboxFile(RequestEvent $event, string $pathInfo): void if (str_contains($pathInfo, '/..')) { return; } - $asset = mb_substr($pathInfo, mb_strlen($this->workboxPublicUrl)); + $asset = mb_substr($pathInfo, mb_strlen((string) $this->workboxPublicUrl)); $resource = sprintf('@SpomkyLabsPwaBundle/Resources/workbox-v%s%s', $this->workboxVersion, $asset); $resourcePath = $this->fileLocator->locate($resource, null, false); if (is_array($resourcePath)) {