Skip to content

Commit

Permalink
HasCacheStrategies interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky committed Mar 8, 2024
1 parent e7e320a commit 4b6294e
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 76 deletions.
6 changes: 3 additions & 3 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\ImageProcessor\GDImageProcessor;
use SpomkyLabs\PwaBundle\ImageProcessor\ImagickImageProcessor;
use SpomkyLabs\PwaBundle\Service\CacheStrategy;
use SpomkyLabs\PwaBundle\Service\ManifestBuilder;
use SpomkyLabs\PwaBundle\Service\Rule\ServiceWorkerRule;
use SpomkyLabs\PwaBundle\Service\Rule\WorkboxRule;
use SpomkyLabs\PwaBundle\Service\ServiceWorkerBuilder;
use SpomkyLabs\PwaBundle\Service\ServiceWorkerCompiler;
use SpomkyLabs\PwaBundle\Subscriber\ManifestCompileEventListener;
Expand Down Expand Up @@ -110,8 +110,8 @@
$container->instanceof(ServiceWorkerRule::class)
->tag('spomky_labs_pwa.service_worker_rule')
;
$container->instanceof(WorkboxRule::class)
->tag('spomky_labs_pwa.workbox_rule')
$container->instanceof(CacheStrategy::class)
->tag('spomky_labs_pwa.cache_strategy')
;
$container->load('SpomkyLabs\\PwaBundle\\Service\\Rule\\', '../../Service/Rule/*');
};
53 changes: 53 additions & 0 deletions src/Service/CacheStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\Service;

final readonly class CacheStrategy
{
public const STRATEGY_CACHE_FIRST = 'cacheFirst';

public const STRATEGY_CACHE_ONLY = 'cacheOnly';

public const STRATEGY_NETWORK_FIRST = 'networkFirst';

public const STRATEGY_NETWORK_ONLY = 'networkOnly';

public const STRATEGY_STALE_WHILE_REVALIDATE = 'staleWhileRevalidate';

public const STRATEGIES = [
self::STRATEGY_CACHE_FIRST,
self::STRATEGY_CACHE_ONLY,
self::STRATEGY_NETWORK_FIRST,
self::STRATEGY_NETWORK_ONLY,
self::STRATEGY_STALE_WHILE_REVALIDATE,
];

public function __construct(
public string $name,
public string $strategy,
public string $urlPattern,
public bool $enabled,
public bool $requireWorkbox,
/**
* @var array{maxTimeout?: int, maxAge?: int, maxEntries?: int}
*/
public array $options = []
) {
}

/**
* @param array{maxTimeout?: int, maxAge?: int, maxEntries?: int} $options
*/
public static function create(
string $name,
string $strategy,
string $urlPattern,
bool $enabled,
bool $requireWorkbox,
array $options = []
): self {
return new self($name, $strategy, $urlPattern, $enabled, $requireWorkbox, $options);
}
}
13 changes: 13 additions & 0 deletions src/Service/HasCacheStrategies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\Service;

interface HasCacheStrategies
{
/**
* @return array<CacheStrategy>
*/
public function getCacheStrategies(): array;
}
37 changes: 32 additions & 5 deletions src/Service/Rule/AssetCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace SpomkyLabs\PwaBundle\Service\Rule;

use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\Dto\Workbox;
use SpomkyLabs\PwaBundle\Service\CacheStrategy;
use SpomkyLabs\PwaBundle\Service\HasCacheStrategies;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
Expand All @@ -18,7 +21,7 @@
use const JSON_UNESCAPED_UNICODE;
use const PHP_EOL;

final readonly class AssetCache implements WorkboxRule
final readonly class AssetCache implements ServiceWorkerRule, HasCacheStrategies
{
/**
* @var array<string, mixed>
Expand All @@ -27,14 +30,18 @@

private string $assetPublicPrefix;

private Workbox $workbox;

public function __construct(
ServiceWorker $serviceWorker,
#[Autowire(service: 'asset_mapper.public_assets_path_resolver')]
PublicAssetsPathResolverInterface $publicAssetsPathResolver,
private AssetMapperInterface $assetMapper,
private SerializerInterface $serializer,
#[Autowire('%kernel.debug%')]
bool $debug,
) {
$this->workbox = $serviceWorker->workbox;
$this->assetPublicPrefix = rtrim($publicAssetsPathResolver->resolvePublicPath(''), '/');
$options = [
AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES => true,
Expand All @@ -47,14 +54,17 @@ public function __construct(
$this->jsonOptions = $options;
}

public function process(Workbox $workbox, string $body): string
public function process(string $body): string
{
if ($workbox->assetCache->enabled === false) {
if ($this->workbox->enabled === false) {
return $body;
}
if ($this->workbox->assetCache->enabled === false) {
return $body;
}
$assets = [];
foreach ($this->assetMapper->allAssets() as $asset) {
if (preg_match($workbox->assetCache->regex, $asset->sourcePath) === 1) {
if (preg_match($this->workbox->assetCache->regex, $asset->sourcePath) === 1) {
$assets[] = $asset->publicPath;
}
}
Expand All @@ -63,7 +73,7 @@ public function process(Workbox $workbox, string $body): string

$declaration = <<<ASSET_CACHE_RULE_STRATEGY
const assetCacheStrategy = new workbox.strategies.CacheFirst({
cacheName: '{$workbox->assetCache->cacheName}',
cacheName: '{$this->workbox->assetCache->cacheName}',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({statuses: [0, 200]}),
new workbox.expiration.ExpirationPlugin({
Expand Down Expand Up @@ -91,4 +101,21 @@ public function process(Workbox $workbox, string $body): string

return $body . PHP_EOL . PHP_EOL . trim($declaration);
}

public function getCacheStrategies(): array
{
return [
CacheStrategy::create(
$this->workbox->assetCache->cacheName,
CacheStrategy::STRATEGY_CACHE_FIRST,
sprintf("'({url}) => url.pathname.startsWith('%s')'", $this->assetPublicPrefix),
$this->workbox->enabled && $this->workbox->assetCache->enabled,
true,
[
'maxEntries' => -1,
'maxAge' => 365 * 24 * 60 * 60,
],
),
];
}
}
42 changes: 38 additions & 4 deletions src/Service/Rule/BackgroundSync.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,32 @@

namespace SpomkyLabs\PwaBundle\Service\Rule;

use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\Dto\Workbox;
use SpomkyLabs\PwaBundle\Service\CacheStrategy;
use SpomkyLabs\PwaBundle\Service\HasCacheStrategies;
use const PHP_EOL;

final readonly class BackgroundSync implements WorkboxRule
final readonly class BackgroundSync implements ServiceWorkerRule, HasCacheStrategies
{
public function process(Workbox $workbox, string $body): string
private Workbox $workbox;

public function __construct(ServiceWorker $serviceWorker)
{
$this->workbox = $serviceWorker->workbox;
}

public function process(string $body): string
{
if ($workbox->backgroundSync === []) {
if ($this->workbox->enabled === false) {
return $body;
}
if ($this->workbox->backgroundSync === []) {
return $body;
}

$declaration = '';
foreach ($workbox->backgroundSync as $sync) {
foreach ($this->workbox->backgroundSync as $sync) {
$forceSyncFallback = $sync->forceSyncFallback === true ? 'true' : 'false';
$broadcastChannel = '';
if ($sync->broadcastChannel !== null) {
Expand Down Expand Up @@ -50,4 +63,25 @@ public function process(Workbox $workbox, string $body): string

return $body . PHP_EOL . PHP_EOL . trim($declaration);
}

public function getCacheStrategies(): array
{
$strategies = [];
foreach ($this->workbox->backgroundSync as $sync) {
$strategies[] = CacheStrategy::create(
'backgroundSync',
CacheStrategy::STRATEGY_NETWORK_ONLY,
$sync->regex,
$this->workbox->enabled,
true,
[
'maxTimeout' => 0,
'maxAge' => 0,
'maxEntries' => 0,
]
);
}

return $strategies;
}
}
18 changes: 15 additions & 3 deletions src/Service/Rule/ClearCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@

namespace SpomkyLabs\PwaBundle\Service\Rule;

use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\Dto\Workbox;
use const PHP_EOL;

final readonly class ClearCache implements WorkboxRule
final readonly class ClearCache implements ServiceWorkerRule
{
public function process(Workbox $workbox, string $body): string
private Workbox $workbox;

public function __construct(
ServiceWorker $serviceWorker
) {
$this->workbox = $serviceWorker->workbox;
}

public function process(string $body): string
{
if ($workbox->clearCache === false) {
if ($this->workbox->enabled === false) {
return $body;
}
if ($this->workbox->clearCache === false) {
return $body;
}

Expand Down
41 changes: 34 additions & 7 deletions src/Service/Rule/FontCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace SpomkyLabs\PwaBundle\Service\Rule;

use SpomkyLabs\PwaBundle\Dto\ServiceWorker;
use SpomkyLabs\PwaBundle\Dto\Workbox;
use SpomkyLabs\PwaBundle\Service\CacheStrategy;
use SpomkyLabs\PwaBundle\Service\HasCacheStrategies;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Serializer\Encoder\JsonEncode;
Expand All @@ -16,19 +19,23 @@
use const JSON_UNESCAPED_UNICODE;
use const PHP_EOL;

final readonly class FontCache implements WorkboxRule
final readonly class FontCache implements ServiceWorkerRule, HasCacheStrategies
{
/**
* @var array<string, mixed>
*/
private array $jsonOptions;

private Workbox $workbox;

public function __construct(
ServiceWorker $serviceWorker,
private AssetMapperInterface $assetMapper,
private SerializerInterface $serializer,
#[Autowire('%kernel.debug%')]
bool $debug,
) {
$this->workbox = $serviceWorker->workbox;
$options = [
AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES => true,
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
Expand All @@ -40,29 +47,32 @@ public function __construct(
$this->jsonOptions = $options;
}

public function process(Workbox $workbox, string $body): string
public function process(string $body): string
{
if ($workbox->fontCache->enabled === false) {
if ($this->workbox->enabled === false) {
return $body;
}
if ($this->workbox->fontCache->enabled === false) {
return $body;
}
$fonts = [];
foreach ($this->assetMapper->allAssets() as $asset) {
if (preg_match($workbox->fontCache->regex, $asset->sourcePath) === 1) {
if (preg_match($this->workbox->fontCache->regex, $asset->sourcePath) === 1) {
$fonts[] = $asset->publicPath;
}
}
$fontUrls = $this->serializer->serialize($fonts, 'json', $this->jsonOptions);

$declaration = <<<FONT_CACHE_RULE_STRATEGY
const fontCacheStrategy = new workbox.strategies.CacheFirst({
cacheName: '{$workbox->fontCache->cacheName}',
cacheName: '{$this->workbox->fontCache->cacheName}',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
new workbox.expiration.ExpirationPlugin({
maxAgeSeconds: {$workbox->fontCache->maxAge},
maxEntries: {$workbox->fontCache->maxEntries},
maxAgeSeconds: {$this->workbox->fontCache->maxAge},
maxEntries: {$this->workbox->fontCache->maxEntries},
}),
],
});
Expand All @@ -85,4 +95,21 @@ public function process(Workbox $workbox, string $body): string

return $body . PHP_EOL . PHP_EOL . trim($declaration);
}

public function getCacheStrategies(): array
{
return [
CacheStrategy::create(
$this->workbox->fontCache->cacheName,
CacheStrategy::STRATEGY_CACHE_FIRST,
"'({request}) => request.destination === 'font'",
$this->workbox->enabled && $this->workbox->fontCache->enabled,
true,
[
'maxEntries' => $this->workbox->fontCache->maxEntries,
'maxAge' => $this->workbox->fontCache->maxAge,
],
),
];
}
}
Loading

0 comments on commit 4b6294e

Please sign in to comment.