Skip to content

Commit

Permalink
Adds a command for the SW creation (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky authored Jan 10, 2024
1 parent 056856d commit ff38672
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 55 deletions.
83 changes: 83 additions & 0 deletions src/Command/GenerateServiceWorkerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?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\HttpKernel\Config\FileLocator;
use function count;
use function dirname;

#[AsCommand(name: 'pwa:sw', description: 'Generate a basic Service Worker')]
final class GenerateServiceWorkerCommand extends Command
{
public function __construct(

Check failure on line 22 in src/Command/GenerateServiceWorkerCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Method SpomkyLabs\PwaBundle\Command\GenerateServiceWorkerCommand::__construct() has parameter $config with no value type specified in iterable type array.
#[Autowire('%spomky_labs_pwa.config%')]
private readonly array $config,
private readonly Filesystem $filesystem,
private readonly FileLocator $fileLocator,
) {
parent::__construct();
}

protected function configure(): void
{
$this->addOption('force', 'f', InputOption::VALUE_NONE, 'Force the generation of the service worker');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->title('PWA Service Worker Generator');

if (! isset($this->config['serviceworker'])) {
$io->info('Service worker section is missing.');
return self::SUCCESS;
}

$force = $input->getOption('force');

$dest = $this->config['serviceworker']['filepath'];
$scope = $this->config['serviceworker']['scope'];
$src = $this->config['serviceworker']['src'];

if (! $this->filesystem->exists(dirname((string) $dest))) {
$this->filesystem->mkdir(dirname((string) $dest));
}
if ($this->filesystem->exists($dest) && ! $force) {

Check failure on line 55 in src/Command/GenerateServiceWorkerCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Only booleans are allowed in a negated boolean, mixed given.
$io->info('Service worker already exists. Skipping.');
return self::SUCCESS;
}

$resourcePath = $this->fileLocator->locate('@SpomkyLabsPwaBundle/Resources/workbox.js', null, false);
if (count($resourcePath) !== 1) {

Check failure on line 61 in src/Command/GenerateServiceWorkerCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Parameter #1 $value of function count expects array|Countable, array|string given.
$io->error('Unable to find the Workbox resource.');
return Command::FAILURE;
}
$resourcePath = $resourcePath[0];
$this->filesystem->copy($resourcePath, $dest);
$io->info('Service worker generated.');
$io->comment('You can now configure your web server to serve the service worker file.');
$io->section('# assets/app.js (or any other entrypoint)');
$jsTemplate = <<<JS
if (navigator.serviceWorker) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("{$src}", {scope: '{$scope}'});
})
}
JS;

$io->writeln($jsTemplate);
$io->section('# End of file');

return self::SUCCESS;
}
}
54 changes: 1 addition & 53 deletions src/Command/SectionProcessor/ServiceWorkerSectionProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,16 @@

namespace SpomkyLabs\PwaBundle\Command\SectionProcessor;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Config\FileLocator;
use function count;
use function dirname;

final readonly class ServiceWorkerSectionProcessor implements SectionProcessor
{
public function __construct(
private Filesystem $filesystem,
private FileLocator $fileLocator,
) {
}

public function process(SymfonyStyle $io, array $config, array $manifest): array|int
{
if (! isset($manifest['serviceworker'])) {
$io->error('Service worker generation is disabled. Skipping.');
return $manifest;
}
$generate = $manifest['serviceworker']['generate'];
unset($manifest['serviceworker']['generate']);

if ($generate !== true) {
$io->info('Service worker generation is disabled. Skipping.');
return $manifest;
}

$dest = $manifest['serviceworker']['filepath'];
$scope = $manifest['serviceworker']['scope'];
$src = $manifest['serviceworker']['src'];
unset($manifest['serviceworker']['filepath']);

if (! $this->filesystem->exists(dirname((string) $dest))) {
$this->filesystem->mkdir(dirname((string) $dest));
}
if ($this->filesystem->exists($dest)) {
$io->info('Service worker already exists. Skipping.');
return $manifest;
}

$resourcePath = $this->fileLocator->locate('@SpomkyLabsPwaBundle/Resources/workbox.js', null, false);
if (count($resourcePath) !== 1) {
$io->error('Unable to find the Workbox resource.');
return Command::FAILURE;
}
$resourcePath = $resourcePath[0];
$this->filesystem->copy($resourcePath, $dest);
$io->info('Service worker generated.');
$io->comment('You can now configure your web server to serve the service worker file.');
$io->section('# assets/app.js (or any other entrypoint)');
$jsTemplate = <<<JS
if (navigator.serviceWorker) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("{$src}", {scope: '{$scope}'});
})
}
JS;

$io->writeln($jsTemplate);
$io->section('# End of file');
unset($manifest['serviceworker']['generate'],$manifest['serviceworker']['filepath']);

return $manifest;
}
Expand Down
2 changes: 2 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use SpomkyLabs\PwaBundle\Command\GenerateManifestCommand;
use SpomkyLabs\PwaBundle\Command\GenerateServiceWorkerCommand;
use SpomkyLabs\PwaBundle\Command\SectionProcessor\ActionsSectionProcessor;
use SpomkyLabs\PwaBundle\Command\SectionProcessor\ApplicationIconsSectionProcessor;
use SpomkyLabs\PwaBundle\Command\SectionProcessor\ApplicationScreenshotsSectionProcessor;
Expand Down Expand Up @@ -35,6 +36,7 @@
->tag('pwa.section-processor');

$container->set(GenerateManifestCommand::class);
$container->set(GenerateServiceWorkerCommand::class);

if (extension_loaded('imagick')) {
$container
Expand Down
21 changes: 19 additions & 2 deletions tests/Functional/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected function tearDown(): void
}

#[Test]
public static function theCommandCanGenerateTheManifestAndIcons(): void
public static function theCommandCanGenerateTheManifestAndAssets(): void
{
// Given
$command = self::$application->find('pwa:build');
Expand All @@ -51,6 +51,24 @@ public static function theCommandCanGenerateTheManifestAndIcons(): void
}
}

#[Test]
public static function theCommandCanGenerateTheServiceWorker(): void
{
// Given
$command = self::$application->find('pwa:sw');
$commandTester = new CommandTester($command);

// When
$commandTester->execute([]);

// Then
$commandTester->assertCommandIsSuccessful();

static::assertStringContainsString('PWA Service Worker Generator', $commandTester->getDisplay());
static::assertDirectoryExists(sprintf('%s/samples/sw', self::$kernel->getCacheDir()));
static::assertFileExists(sprintf('%s/samples/sw/my-sw.js', self::$kernel->getCacheDir()));
}

private static function cleanupFolder(): void
{
$filesystem = self::getContainer()->get(Filesystem::class);
Expand All @@ -62,7 +80,6 @@ private static function cleanupFolder(): void
*/
private static function expectedFiles(): iterable
{
yield 'sw' => sprintf('%s/samples/sw/my-sw.js', self::$kernel->getCacheDir());
yield 'manifest' => sprintf('%s/samples/manifest/my-pwa.json', self::$kernel->getCacheDir());
yield 'icon 48' => sprintf('%s/samples/icons/icon--48x48-1dc988f5.json', self::$kernel->getCacheDir());
yield 'icon 72' => sprintf('%s/samples/icons/icon--72x72-5446402b.json', self::$kernel->getCacheDir());
Expand Down

0 comments on commit ff38672

Please sign in to comment.