diff --git a/src/Command/GenerateServiceWorkerCommand.php b/src/Command/GenerateServiceWorkerCommand.php new file mode 100644 index 0000000..e0dfa61 --- /dev/null +++ b/src/Command/GenerateServiceWorkerCommand.php @@ -0,0 +1,83 @@ +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) { + $io->info('Service worker already exists. Skipping.'); + return self::SUCCESS; + } + + $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 = << { + navigator.serviceWorker.register("{$src}", {scope: '{$scope}'}); + }) + } + JS; + + $io->writeln($jsTemplate); + $io->section('# End of file'); + + return self::SUCCESS; + } +} diff --git a/src/Command/SectionProcessor/ServiceWorkerSectionProcessor.php b/src/Command/SectionProcessor/ServiceWorkerSectionProcessor.php index 1d111a6..a3002db 100644 --- a/src/Command/SectionProcessor/ServiceWorkerSectionProcessor.php +++ b/src/Command/SectionProcessor/ServiceWorkerSectionProcessor.php @@ -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 = << { - navigator.serviceWorker.register("{$src}", {scope: '{$scope}'}); - }) - } - JS; - - $io->writeln($jsTemplate); - $io->section('# End of file'); + unset($manifest['serviceworker']['generate'],$manifest['serviceworker']['filepath']); return $manifest; } diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index c678bf5..25ea090 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -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; @@ -35,6 +36,7 @@ ->tag('pwa.section-processor'); $container->set(GenerateManifestCommand::class); + $container->set(GenerateServiceWorkerCommand::class); if (extension_loaded('imagick')) { $container diff --git a/tests/Functional/CommandTest.php b/tests/Functional/CommandTest.php index 3296389..fe6a890 100644 --- a/tests/Functional/CommandTest.php +++ b/tests/Functional/CommandTest.php @@ -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'); @@ -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); @@ -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());