Skip to content

Commit

Permalink
Font cache support (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky authored Feb 6, 2024
1 parent 58f53d7 commit e479f10
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 104 deletions.
20 changes: 0 additions & 20 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -455,26 +455,6 @@ parameters:
count: 1
path: src/Normalizer/ServiceWorkerNormalizer.php

-
message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\ShortcutNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/Normalizer/ShortcutNormalizer.php

-
message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\ShortcutNormalizer\\:\\:normalize\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Normalizer/ShortcutNormalizer.php

-
message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\ShortcutNormalizer\\:\\:normalize\\(\\) should return array\\{description\\?\\: string, icons\\?\\: array, name\\: string, short_name\\?\\: string, url\\: string\\} but returns array\\<mixed\\>\\.$#"
count: 1
path: src/Normalizer/ShortcutNormalizer.php

-
message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\ShortcutNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/Normalizer/ShortcutNormalizer.php

-
message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Normalizer\\\\UrlNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
Expand Down
20 changes: 20 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,31 @@ private function setupServiceWorker(ArrayNodeDefinition $node): void
->info('The regex to match the images.')
->example('/\.(ico|png|jpe?g|gif|svg|webp|bmp)$/')
->end()
->scalarNode('static_regex')
->defaultValue('/\.(css|js|json|xml|txt|woff2|ttf|eot|otf|map|webmanifest)$/')
->info('The regex to match the static files.')
->example('/\.(css|js|json|xml|txt|woff2|ttf|eot|otf|map|webmanifest)$/')
->end()
->integerNode('max_image_cache_entries')
->defaultValue(60)
->info('The maximum number of entries in the image cache.')
->example([50, 100, 200])
->end()
->integerNode('max_image_age')
->defaultValue(60 * 60 * 24 * 365)
->info('The maximum number of seconds before the image cache is invalidated.')
->example([60 * 60 * 24 * 365, 60 * 60 * 24 * 30, 60 * 60 * 24 * 7])
->end()
->integerNode('max_font_cache_entries')
->defaultValue(30)
->info('The maximum number of entries in the font cache.')
->example([30, 50, 100])
->end()
->integerNode('max_font_age')
->defaultValue(60 * 60 * 24 * 365)
->info('The maximum number of seconds before the font cache is invalidated.')
->example([60 * 60 * 24 * 365, 60 * 60 * 24 * 30, 60 * 60 * 24 * 7])
->end()
->integerNode('network_timeout_seconds')
->defaultValue(3)
->info(
Expand Down
9 changes: 9 additions & 0 deletions src/Dto/Workbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ final class Workbox
#[SerializedName('network_timeout_seconds')]
public int $networkTimeoutSeconds = 3;

#[SerializedName('max_font_age')]
public int $maxFontAge = 60 * 60 * 24 * 365;

#[SerializedName('max_font_cache_entries')]
public int $maxFontCacheEntries = 60;

#[SerializedName('max_image_age')]
public int $maxImageAge = 60 * 60 * 24 * 365;

#[SerializedName('max_image_cache_entries')]
public int $maxImageCacheEntries = 60;

Expand Down
1 change: 0 additions & 1 deletion src/Normalizer/AssetNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public function normalize(mixed $object, string $format = null, array $context =
{
assert($object instanceof Asset);
$url = null;
dump($object);
if (! str_starts_with($object->src, '/')) {
$asset = $this->assetMapper->getAsset($object->src);
$url = $asset?->publicPath;
Expand Down
16 changes: 10 additions & 6 deletions src/Normalizer/IconNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\MappedAsset;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use function assert;

final readonly class IconNormalizer implements NormalizerInterface
final class IconNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;

public function __construct(
private AssetMapperInterface $assetMapper,
private readonly AssetMapperInterface $assetMapper,
) {
}

Expand All @@ -24,16 +28,16 @@ public function __construct(
public function normalize(mixed $object, string $format = null, array $context = []): array
{
assert($object instanceof Icon);
$format = null;
$imageFormat = null;
if (! str_starts_with($object->src->src, '/')) {
$asset = $this->assetMapper->getAsset($object->src->src);
$format = $this->getFormat($object, $asset);
$imageFormat = $this->getFormat($object, $asset);
}

$result = [
'src' => $object->src,
'src' => $this->normalizer->normalize($object->src, $format, $context),
'sizes' => $object->getSizeList(),
'type' => $format,
'type' => $imageFormat,
'purpose' => $object->purpose,
];

Expand Down
17 changes: 11 additions & 6 deletions src/Normalizer/ScreenshotNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\MappedAsset;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use function assert;

final readonly class ScreenshotNormalizer implements NormalizerInterface
final class ScreenshotNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;

public function __construct(
private AssetMapperInterface $assetMapper,
private null|ImageProcessor $imageProcessor,
private readonly AssetMapperInterface $assetMapper,
private readonly null|ImageProcessor $imageProcessor,
) {
}

Expand All @@ -28,23 +32,24 @@ public function normalize(mixed $object, string $format = null, array $context =
assert($object instanceof Screenshot);
$url = null;
$asset = null;
$imageFormat = null;
if (! str_starts_with($object->src->src, '/')) {
$asset = $this->assetMapper->getAsset($object->src->src);
$url = $asset?->publicPath;
$format = $this->getFormat($object, $asset);
$imageFormat = $this->getFormat($object, $asset);
}
if ($url === null) {
$url = $object->src->src;
}
['sizes' => $sizes, 'formFactor' => $formFactor] = $this->getSizes($object, $asset);

$result = [
'src' => $url,
'src' => $this->normalizer->normalize($object->src, $format, $context),
'sizes' => $sizes,
'form_factor' => $formFactor,
'label' => $object->label,
'platform' => $object->platform,
'format' => $format,
'format' => $imageFormat,
];

$cleanup = static fn (array $data): array => array_filter(
Expand Down
15 changes: 1 addition & 14 deletions src/Normalizer/ServiceWorkerNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,20 @@
namespace SpomkyLabs\PwaBundle\Normalizer;

use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use function assert;

final readonly class ServiceWorkerNormalizer implements NormalizerInterface
{
public function __construct(
private AssetMapperInterface $assetMapper
) {
}

/**
* @return array{scope?: string, src: string, use_cache?: bool}
*/
public function normalize(mixed $object, string $format = null, array $context = []): array
{
assert($object instanceof ServiceWorker);
$url = null;
if (! str_starts_with($object->dest, '/')) {
$url = $this->assetMapper->getAsset($object->dest)?->publicPath;
}
if ($url === null) {
$url = $object->dest;
}

$result = [
'src' => $url,
'src' => '/' . trim($object->dest, '/'),
'scope' => $object->scope,
'use_cache' => $object->useCache,
];
Expand Down
53 changes: 0 additions & 53 deletions src/Normalizer/ShortcutNormalizer.php

This file was deleted.

24 changes: 20 additions & 4 deletions src/Service/ServiceWorkerCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,19 @@ private function processStandardRules(Workbox $workbox, string $body): string
}

$images = [];
$static = [];
$statics = [];
foreach ($this->assetMapper->allAssets() as $asset) {
if (preg_match($workbox->imageRegex, $asset->sourcePath) === 1) {
$images[] = $asset->publicPath;
} elseif (preg_match($workbox->staticRegex, $asset->sourcePath) === 1) {
$static[] = $asset->publicPath;
$statics[] = $asset->publicPath;
}
}
$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);
$staticUrls = $this->serializer->serialize($statics, 'json', $jsonOptions);
$routes = $this->serializer->serialize($workbox->warmCacheUrls, 'json', $jsonOptions);

$declaration = <<<STANDARD_RULE_STRATEGY
Expand All @@ -94,12 +94,28 @@ private function processStandardRules(Workbox $workbox, string $body): string
workbox.recipes.imageCache({
cacheName: 'images',
maxEntries: {$workbox->maxImageCacheEntries},
maxImageAge: {$workbox->maxImageAge},
warmCache: {$imageUrls}
});
workbox.recipes.staticResourceCache({
cacheName: 'assets',
warmCache: {$staticUrls}
});
workbox.routing.registerRoute(
({request}) => request.destination === 'font',
new workbox.strategies.CacheFirst({
cacheName: 'fonts',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
new workbox.expiration.ExpirationPlugin({
maxAgeSeconds: {$workbox->maxFontAge},
maxEntries: {$workbox->maxFontCacheEntries},
}),
],
})
);
STANDARD_RULE_STRATEGY;

return str_replace($workbox->standardRulesPlaceholder, trim($declaration), $body);
Expand Down Expand Up @@ -138,7 +154,7 @@ private function processOfflineFallback(Workbox $workbox, string $body): string
workbox.recipes.offlineFallback({
pageFallback: {$pageFallback},
imageFallback: {$imageFallback},
pageFallback: {$fontFallback}
fontFallback: {$fontFallback}
});
OFFLINE_FALLBACK_STRATEGY;

Expand Down

0 comments on commit e479f10

Please sign in to comment.