Skip to content

Commit

Permalink
Simplified SW skeleton (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky authored Jan 27, 2024
1 parent cf26563 commit b983496
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 120 deletions.
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ parameters:
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
path: src/Dto/Workbox.php

-
message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Workbox has an uninitialized property \\$useCDN\\. Give it default value or assign it in the constructor\\.$#"
count: 1
Expand Down
7 changes: 7 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,13 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void
)
->example('//WORKBOX_IMPORT_PLACEHOLDER')
->end()
->scalarNode('standard_rules_placeholder')
->defaultValue('//STANDARD_RULES_PLACEHOLDER')
->info(
'The placeholder for the standard rules. Will be replaced by caching strategies.'
)
->example('//STANDARD_RULES_PLACEHOLDER')
->end()
->scalarNode('precaching_placeholder')
->defaultValue('//PRECACHING_PLACEHOLDER')
->info(
Expand Down
3 changes: 3 additions & 0 deletions src/Dto/Workbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ final class Workbox
#[SerializedName('warm_cache_placeholder')]
public string $warmCachePlaceholder;

#[SerializedName('standard_rules_placeholder')]
public string $standardRulesPlaceholder;

#[SerializedName('precaching_placeholder')]
public string $precachingPlaceholder;

Expand Down
47 changes: 2 additions & 45 deletions src/Resources/sw-skeleton.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,6 @@
// *** Workbox ***
// Workbox is imported from a CDN or local files.
// *** Workbox Bundle rules ***
//WORKBOX_IMPORT_PLACEHOLDER

// *** Recipes ***
// You are free to change or remove any of these presets as you wish.
// See https://developer.chrome.com/docs/workbox/modules/workbox-recipes for more information.
const {
pageCache,
imageCache,
googleFontsCache,
} = workbox.recipes;
const {registerRoute} = workbox.routing;
const {CacheFirst} = workbox.strategies;
const {CacheableResponsePlugin} = workbox.cacheableResponse;

pageCache();// => Cache pages with a network-first strategy.
imageCache();// => Cache images with a cache-first strategy.
googleFontsCache();// => Cache the underlying font files with a cache-first strategy.

// *** Assets ***
// Cache CSS, JS, and Web Worker requests with a cache-first strategy.
// We could use staticResourceCache();, but this strategy uses a stale-while-revalidate strategy,
// which is not ideal for static resources served by Asset Mapper (assets are immutable)
const cacheName = 'static-resources';
const matchCallback = ({request}) =>
// CSS
request.destination === 'style' ||
// JavaScript
request.destination === 'script' ||
// Web Workers
request.destination === 'worker';

registerRoute(
matchCallback,
new CacheFirst({
cacheName,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
})
);

// *** Bundle rules ***
//STANDARD_RULES_PLACEHOLDER
//PRECACHING_PLACEHOLDER
//WARM_CACHE_URLS_PLACEHOLDER
//OFFLINE_FALLBACK_PLACEHOLDER
Expand Down
73 changes: 32 additions & 41 deletions src/Service/ServiceWorkerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,41 @@ public function build(): ?string
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);
}

private function processStandardRules(Workbox $workbox, string $body): string
{
if (! str_contains($body, $workbox->standardRulesPlaceholder)) {
return $body;
}

$declaration = <<<STANDARD_RULE_STRATEGY
workbox.recipes.pageCache();
workbox.recipes.imageCache();
workbox.recipes.googleFontsCache();
const matchCallback = ({request}) => 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)) {
Expand All @@ -75,14 +103,9 @@ private function processPrecachedAssets(Workbox $workbox, string $body): string
$assets = $this->serializer->serialize($result, 'json', [
JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
]);
$precacheAndRouteDeclaration = str_contains(
$body,
'precacheAndRoute'
) ? '' : 'const { precacheAndRoute } = workbox.precaching;';

$declaration = <<<PRECACHE_STRATEGY
{$precacheAndRouteDeclaration}
precacheAndRoute({$assets});
workbox.precaching.precacheAndRoute({$assets});
PRECACHE_STRATEGY;

return str_replace($workbox->precachingPlaceholder, trim($declaration), $body);
Expand All @@ -102,21 +125,10 @@ private function processWarmCacheUrls(Workbox $workbox, string $body): string
JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
]);

$cacheFirstStrategyDeclaration = str_contains(
$body,
'CacheFirst'
) ? '' : 'const { CacheFirst } = workbox.strategies;';
$warmStrategyCacheMethod = str_contains(
$body,
'warmStrategyCache'
) ? '' : 'const { warmStrategyCache } = workbox.recipes;';

$declaration = <<<WARM_CACHE_URL_STRATEGY
{$cacheFirstStrategyDeclaration}
{$warmStrategyCacheMethod}
warmStrategyCache({
workbox.recipes.warmStrategyCache({
urls: {$routes},
strategy: new CacheFirst()
strategy: new workbox.strategies.CacheFirst()
});
WARM_CACHE_URL_STRATEGY;

Expand All @@ -133,27 +145,7 @@ private function processOfflineFallback(Workbox $workbox, string $body): string
JsonEncode::OPTIONS => JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
]);

$offlineFallbackMethod = str_contains(
$body,
'offlineFallback'
) ? '' : 'const { offlineFallback } = workbox.recipes;';
$networkOnlyStrategy = str_contains(
$body,
'NetworkOnly'
) ? '' : 'const { NetworkOnly } = workbox.strategies;';
$setDefaultHandlerRouting = str_contains(
$body,
'setDefaultHandler'
) ? '' : 'const { setDefaultHandler } = workbox.routing;' . PHP_EOL . 'setDefaultHandler(new NetworkOnly());';

$declaration = <<<OFFLINE_FALLBACK_STRATEGY
{$offlineFallbackMethod}
{$networkOnlyStrategy}
{$setDefaultHandlerRouting}
offlineFallback({
pageFallback: {$url},
});
OFFLINE_FALLBACK_STRATEGY;
$declaration = sprintf('%sworkbox.recipes.offlineFallback({ pageFallback: %s });', PHP_EOL, $url);

return str_replace($workbox->offlineFallbackPlaceholder, trim($declaration), $body);
}
Expand Down Expand Up @@ -251,7 +243,6 @@ private function processWorkboxImport(Workbox $workbox, string $body): string
);
IMPORT_CDN_STRATEGY;
} else {
$version = $workbox->version;
$publicUrl = '/' . trim($workbox->workboxPublicUrl, '/');
$declaration = <<<IMPORT_CDN_STRATEGY
importScripts('{$publicUrl}/workbox-sw.js');
Expand Down
36 changes: 2 additions & 34 deletions tests/sw.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,6 @@
// *** Workbox Bundle rules ***
//WORKBOX_IMPORT_PLACEHOLDER
const {
pageCache,
imageCache,
googleFontsCache,
} = workbox.recipes;
const {registerRoute} = workbox.routing;
const {CacheFirst} = workbox.strategies;
const {CacheableResponsePlugin} = workbox.cacheableResponse;

pageCache();
imageCache();
googleFontsCache();

const cacheName = 'static-resources';
const matchCallback = ({request}) =>
// CSS
request.destination === 'style' ||
// JavaScript
request.destination === 'script' ||
// Web Workers
request.destination === 'worker';

registerRoute(
matchCallback,
new CacheFirst({
cacheName,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
})
);

//STANDARD_RULES_PLACEHOLDER
//PRECACHING_PLACEHOLDER
//WARM_CACHE_URLS_PLACEHOLDER
//OFFLINE_FALLBACK_PLACEHOLDER
Expand Down

0 comments on commit b983496

Please sign in to comment.