diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php index b73d70fcfcd11..6a376c58e072d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php @@ -19,6 +19,7 @@ use Symfony\Component\AssetMapper\Command\AssetMapperCompileCommand; use Symfony\Component\AssetMapper\Command\DebugAssetMapperCommand; use Symfony\Component\AssetMapper\Command\ImportMapExportCommand; +use Symfony\Component\AssetMapper\Command\ImportMapInstallCommand; use Symfony\Component\AssetMapper\Command\ImportMapRemoveCommand; use Symfony\Component\AssetMapper\Command\ImportMapRequireCommand; use Symfony\Component\AssetMapper\Command\ImportMapUpdateCommand; @@ -202,5 +203,9 @@ ->set('asset_mapper.importmap.command.export', ImportMapExportCommand::class) ->args([service('asset_mapper.importmap.manager')]) ->tag('console.command') + + ->set('asset_mapper.importmap.command.install', ImportMapInstallCommand::class) + ->args([service('asset_mapper.importmap.manager')]) + ->tag('console.command') ; }; diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index a4525d9724a4d..d5518c297fab5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -37,7 +37,7 @@ "doctrine/persistence": "^1.3|^2|^3", "seld/jsonlint": "^1.10", "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/asset-mapper": "^6.3|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", "symfony/browser-kit": "^5.4|^6.0|^7.0", "symfony/console": "^5.4.9|^6.0.9|^7.0", "symfony/clock": "^6.2|^7.0", @@ -79,6 +79,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/asset": "<5.4", + "symfony/asset-mapper": "<6.4", "symfony/clock": "<6.3", "symfony/console": "<5.4", "symfony/dotenv": "<5.4", diff --git a/src/Symfony/Component/AssetMapper/CHANGELOG.md b/src/Symfony/Component/AssetMapper/CHANGELOG.md index 140d728dbfa51..77f32884bdc02 100644 --- a/src/Symfony/Component/AssetMapper/CHANGELOG.md +++ b/src/Symfony/Component/AssetMapper/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Mark the component as non experimental + * Add a `importmap:install` command to download all missing downloaded packages 6.3 --- diff --git a/src/Symfony/Component/AssetMapper/Command/ImportMapInstallCommand.php b/src/Symfony/Component/AssetMapper/Command/ImportMapInstallCommand.php new file mode 100644 index 0000000000000..6924deddc55ca --- /dev/null +++ b/src/Symfony/Component/AssetMapper/Command/ImportMapInstallCommand.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\AssetMapper\Command; + +use Symfony\Component\AssetMapper\ImportMap\ImportMapManager; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * Downloads all assets that should be downloaded. + * + * @author Jonathan Scheiber + */ +#[AsCommand(name: 'importmap:install', description: 'Downloads all assets that should be downloaded.')] +final class ImportMapInstallCommand extends Command +{ + public function __construct( + private readonly ImportMapManager $importMapManager, + ) { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $downloadedPackages = $this->importMapManager->downloadMissingPackages(); + $io->success(sprintf('Downloaded %d assets.', \count($downloadedPackages))); + + return Command::SUCCESS; + } +} diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php index 699dcdae2cade..3b8559f715315 100644 --- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php +++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php @@ -13,6 +13,7 @@ use Symfony\Component\AssetMapper\AssetDependency; use Symfony\Component\AssetMapper\AssetMapperInterface; +use Symfony\Component\AssetMapper\Exception\RuntimeException; use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolverInterface; use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolverInterface; use Symfony\Component\VarExporter\VarExporter; @@ -108,6 +109,36 @@ public function update(): array return $this->updateImportMapConfig(true, [], []); } + /** + * Downloads all missing downloaded packages. + * + * @return ImportMapEntry[] The downloaded packages + */ + public function downloadMissingPackages(): array + { + $entries = $this->loadImportMapEntries(); + $packagesToDownload = []; + + foreach ($entries as $entry) { + if (!$entry->isDownloaded || $this->assetMapper->getAsset($entry->path)) { + continue; + } + + $parts = self::parsePackageName($entry->url); + + $packagesToDownload[] = new PackageRequireOptions( + $parts['package'], + $parts['version'] ?? throw new RuntimeException(sprintf('Cannot get a version for the "%s" package.', $parts['package'])), + true, + $entry->preload, + $parts['alias'] ?? $parts['package'], + isset($parts['registry']) && $parts['registry'] ? $parts['registry'] : null, + ); + } + + return $this->require($packagesToDownload); + } + /** * @internal */ diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php index c947d334909e4..86f3a96d4e1dc 100644 --- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php @@ -373,6 +373,43 @@ public function testUpdate() $this->assertSame('contents of cowsay.js', $actualContents); } + public function testDownloadMissingPackages() + { + $rootDir = __DIR__.'/../fixtures/download'; + $manager = $this->createImportMapManager(['assets' => ''], $rootDir); + + $this->packageResolver->expects($this->once()) + ->method('resolvePackages') + ->willReturn([ + self::resolvedPackage('@hotwired/stimulus', 'https://cdn.jsdelivr.net/npm/stimulus@3.2.1/+esm', true, content: 'contents of stimulus.js'), + ]) + ; + + $downloadedPackages = $manager->downloadMissingPackages(); + $actualImportMap = require $rootDir.'/importmap.php'; + $expectedImportMap = [ + '@hotwired/stimulus' => [ + 'downloaded_to' => 'vendor/@hotwired/stimulus.js', + 'url' => 'https://cdn.jsdelivr.net/npm/stimulus@3.2.1/+esm', + ], + 'lodash' => [ + 'downloaded_to' => 'vendor/lodash.js', + 'url' => 'https://ga.jspm.io/npm:lodash@4.17.21/lodash.js', + ], + ]; + $this->assertEquals($expectedImportMap, $actualImportMap); + + $expectedDownloadedFiles = [ + 'assets/vendor/@hotwired/stimulus.js' => 'contents of stimulus.js', + ]; + foreach ($expectedDownloadedFiles as $file => $expectedContents) { + $this->assertFileExists($rootDir.'/'.$file); + $actualContents = file_get_contents($rootDir.'/'.$file); + $this->assertSame($expectedContents, $actualContents); + unlink($rootDir.'/'.$file); + } + } + /** * @dataProvider getPackageNameTests */ diff --git a/src/Symfony/Component/AssetMapper/Tests/fixtures/download/assets/vendor/lodash.js b/src/Symfony/Component/AssetMapper/Tests/fixtures/download/assets/vendor/lodash.js new file mode 100644 index 0000000000000..ac1d7f73afb58 --- /dev/null +++ b/src/Symfony/Component/AssetMapper/Tests/fixtures/download/assets/vendor/lodash.js @@ -0,0 +1 @@ +console.log('fake downloaded lodash.js'); diff --git a/src/Symfony/Component/AssetMapper/Tests/fixtures/download/importmap.php b/src/Symfony/Component/AssetMapper/Tests/fixtures/download/importmap.php new file mode 100644 index 0000000000000..30bb5a9469f59 --- /dev/null +++ b/src/Symfony/Component/AssetMapper/Tests/fixtures/download/importmap.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '@hotwired/stimulus' => [ + 'downloaded_to' => 'vendor/@hotwired/stimulus.js', + 'url' => 'https://cdn.jsdelivr.net/npm/stimulus@3.2.1/+esm', + ], + 'lodash' => [ + 'downloaded_to' => 'vendor/lodash.js', + 'url' => 'https://ga.jspm.io/npm:lodash@4.17.21/lodash.js', + ], +]; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy