Skip to content

Commit 7722e10

Browse files
committed
[AssetMapper] Always downloading vendor files
Also adding isVendor to MappedAssets
1 parent 7be1c03 commit 7722e10

38 files changed

+873
-865
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ CHANGELOG
2828
* Add `array $tokenAttributes = []` optional parameter to `KernelBrowser::loginUser()`
2929
* Add support for relative URLs in BrowserKit's redirect assertion.
3030
* Change BrowserKitAssertionsTrait::getClient() to be protected
31+
* Removed the `framework.asset_mapper.provider` config option.
3132

3233
6.3
3334
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class UnusedTagsPass implements CompilerPassInterface
2525
'annotations.cached_reader',
2626
'assets.package',
2727
'asset_mapper.compiler',
28-
'asset_mapper.importmap.resolver',
2928
'auto_alias',
3029
'cache.pool',
3130
'cache.pool.clearer',

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use Symfony\Bundle\FullStack;
1919
use Symfony\Component\Asset\Package;
2020
use Symfony\Component\AssetMapper\AssetMapper;
21-
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
2221
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
2322
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
2423
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
@@ -940,8 +939,7 @@ private function addAssetMapperSection(ArrayNodeDefinition $rootNode, callable $
940939
->defaultValue('%kernel.project_dir%/assets/vendor')
941940
->end()
942941
->scalarNode('provider')
943-
->info('The provider (CDN) to use'.(class_exists(ImportMapManager::class) ? sprintf(' (e.g.: "%s").', implode('", "', ImportMapManager::PROVIDERS)) : '.'))
944-
->defaultValue('jsdelivr.esm')
942+
->setDeprecated('symfony/framework-bundle', '6.4', 'Option "%node%" at "%path%" is deprecated and does nothing. Remove it.')
945943
->end()
946944
->end()
947945
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
use Symfony\Component\AssetMapper\AssetMapper;
3535
use Symfony\Component\AssetMapper\Compiler\AssetCompilerInterface;
3636
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
37-
use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolverInterface;
3837
use Symfony\Component\BrowserKit\AbstractBrowser;
3938
use Symfony\Component\Cache\Adapter\AdapterInterface;
4039
use Symfony\Component\Cache\Adapter\ArrayAdapter;
@@ -1364,28 +1363,24 @@ private function registerAssetMapperConfiguration(array $config, ContainerBuilde
13641363
->setArgument(1, $config['missing_import_mode']);
13651364

13661365
$container
1367-
->getDefinition('asset_mapper.importmap.manager')
1368-
->replaceArgument(3, $config['vendor_dir'])
1366+
->getDefinition('asset_mapper.importmap.remote_package_downloader')
1367+
->replaceArgument(2, $config['vendor_dir'])
13691368
;
1370-
13711369
$container
1372-
->getDefinition('asset_mapper.importmap.config_reader')
1373-
->replaceArgument(0, $config['importmap_path'])
1370+
->getDefinition('asset_mapper.mapped_asset_factory')
1371+
->replaceArgument(2, $config['vendor_dir'])
13741372
;
13751373

13761374
$container
1377-
->getDefinition('asset_mapper.importmap.resolver')
1378-
->replaceArgument(0, $config['provider'])
1375+
->getDefinition('asset_mapper.importmap.config_reader')
1376+
->replaceArgument(0, $config['importmap_path'])
13791377
;
13801378

13811379
$container
13821380
->getDefinition('asset_mapper.importmap.renderer')
13831381
->replaceArgument(3, $config['importmap_polyfill'] ?? ImportMapManager::POLYFILL_URL)
13841382
->replaceArgument(4, $config['importmap_script_attributes'])
13851383
;
1386-
1387-
$container->registerForAutoconfiguration(PackageResolverInterface::class)
1388-
->addTag('asset_mapper.importmap.resolver');
13891384
}
13901385

13911386
/**

src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@
3030
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
3131
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
3232
use Symfony\Component\AssetMapper\ImportMap\ImportMapRenderer;
33+
use Symfony\Component\AssetMapper\ImportMap\RemotePackageDownloader;
3334
use Symfony\Component\AssetMapper\ImportMap\Resolver\JsDelivrEsmResolver;
34-
use Symfony\Component\AssetMapper\ImportMap\Resolver\JspmResolver;
35-
use Symfony\Component\AssetMapper\ImportMap\Resolver\PackageResolver;
3635
use Symfony\Component\AssetMapper\MapperAwareAssetPackage;
3736
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolver;
3837
use Symfony\Component\HttpKernel\Event\RequestEvent;
@@ -51,6 +50,7 @@
5150
->args([
5251
service('asset_mapper.public_assets_path_resolver'),
5352
service('asset_mapper_compiler'),
53+
abstract_arg('vendor directory'),
5454
])
5555

5656
->set('asset_mapper.cached_mapped_asset_factory', CachedMappedAssetFactory::class)
@@ -148,41 +148,20 @@
148148
service('asset_mapper'),
149149
service('asset_mapper.public_assets_path_resolver'),
150150
service('asset_mapper.importmap.config_reader'),
151-
abstract_arg('vendor directory'),
151+
service('asset_mapper.importmap.remote_package_downloader'),
152152
service('asset_mapper.importmap.resolver'),
153-
service('http_client'),
154153
])
155154
->alias(ImportMapManager::class, 'asset_mapper.importmap.manager')
156155

157-
->set('asset_mapper.importmap.resolver', PackageResolver::class)
156+
->set('asset_mapper.importmap.remote_package_downloader', RemotePackageDownloader::class)
158157
->args([
159-
abstract_arg('provider'),
160-
tagged_locator('asset_mapper.importmap.resolver'),
158+
service('asset_mapper.importmap.config_reader'),
159+
service('asset_mapper.importmap.resolver'),
160+
abstract_arg('vendor directory'),
161161
])
162162

163-
->set('asset_mapper.importmap.resolver.jsdelivr_esm', JsDelivrEsmResolver::class)
163+
->set('asset_mapper.importmap.resolver', JsDelivrEsmResolver::class)
164164
->args([service('http_client')])
165-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSDELIVR_ESM])
166-
167-
->set('asset_mapper.importmap.resolver.jspm', JspmResolver::class)
168-
->args([service('http_client'), ImportMapManager::PROVIDER_JSPM])
169-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSPM])
170-
171-
->set('asset_mapper.importmap.resolver.jspm_system', JspmResolver::class)
172-
->args([service('http_client'), ImportMapManager::PROVIDER_JSPM_SYSTEM])
173-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSPM_SYSTEM])
174-
175-
->set('asset_mapper.importmap.resolver.skypack', JspmResolver::class)
176-
->args([service('http_client'), ImportMapManager::PROVIDER_SKYPACK])
177-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_SKYPACK])
178-
179-
->set('asset_mapper.importmap.resolver.jsdelivr', JspmResolver::class)
180-
->args([service('http_client'), ImportMapManager::PROVIDER_JSDELIVR])
181-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_JSDELIVR])
182-
183-
->set('asset_mapper.importmap.resolver.unpkg', JspmResolver::class)
184-
->args([service('http_client'), ImportMapManager::PROVIDER_UNPKG])
185-
->tag('asset_mapper.importmap.resolver', ['resolver' => ImportMapManager::PROVIDER_UNPKG])
186165

187166
->set('asset_mapper.importmap.renderer', ImportMapRenderer::class)
188167
->args([
@@ -210,7 +189,10 @@
210189
->tag('console.command')
211190

212191
->set('asset_mapper.importmap.command.install', ImportMapInstallCommand::class)
213-
->args([service('asset_mapper.importmap.manager')])
192+
->args([
193+
service('asset_mapper.importmap.remote_package_downloader'),
194+
param('kernel.project_dir'),
195+
])
214196
->tag('console.command')
215197
;
216198
};

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ public function testAssetMapperCanBeEnabled()
134134
'importmap_path' => '%kernel.project_dir%/importmap.php',
135135
'importmap_polyfill' => null,
136136
'vendor_dir' => '%kernel.project_dir%/assets/vendor',
137-
'provider' => 'jsdelivr.esm',
138137
'importmap_script_attributes' => [],
139138
];
140139

@@ -671,7 +670,6 @@ protected static function getBundleDefaultConfig()
671670
'importmap_path' => '%kernel.project_dir%/importmap.php',
672671
'importmap_polyfill' => null,
673672
'vendor_dir' => '%kernel.project_dir%/assets/vendor',
674-
'provider' => 'jsdelivr.esm',
675673
'importmap_script_attributes' => [],
676674
],
677675
'cache' => [

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/asset_mapper.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
importmap-path="%kernel.project_dir%/importmap.php"
1818
importmap-polyfill="https://cdn.example.com/polyfill.js"
1919
vendor-dir="%kernel.project_dir%/assets/vendor"
20-
provider="jspm"
2120
>
2221
<framework:path>assets/</framework:path>
2322
<framework:path namespace="my_namespace">assets2/</framework:path>

src/Symfony/Component/AssetMapper/AssetMapperRepository.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ public function all(): array
111111
continue;
112112
}
113113

114+
// avoid potentially exposing PHP files
115+
if (str_ends_with($file->getPathname(), '.php')) {
116+
continue;
117+
}
118+
114119
/** @var RecursiveDirectoryIterator $innerIterator */
115120
$innerIterator = $iterator->getInnerIterator();
116121
$logicalPath = ($namespace ? rtrim($namespace, '/').'/' : '').$innerIterator->getSubPathName();

src/Symfony/Component/AssetMapper/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Mark the component as non experimental
88
* Add CSS support to the importmap
99
* Add "entrypoints" concept to the importmap
10+
* Always download packages locally instead of using a CDN
1011
* Allow relative path strings in the importmap
1112
* Add `PreAssetsCompileEvent` event when running `asset-map:compile`
1213
* Add support for importmap paths to use the Asset component (for subdirectories)

src/Symfony/Component/AssetMapper/Command/ImportMapInstallCommand.php

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
namespace Symfony\Component\AssetMapper\Command;
1313

14-
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
14+
use Symfony\Component\AssetMapper\ImportMap\RemotePackageDownloader;
1515
use Symfony\Component\Console\Attribute\AsCommand;
1616
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Helper\ProgressBar;
1718
use Symfony\Component\Console\Input\InputInterface;
1819
use Symfony\Component\Console\Output\OutputInterface;
1920
use Symfony\Component\Console\Style\SymfonyStyle;
21+
use Symfony\Contracts\HttpClient\ResponseInterface;
2022

2123
/**
2224
* Downloads all assets that should be downloaded.
@@ -27,7 +29,8 @@
2729
final class ImportMapInstallCommand extends Command
2830
{
2931
public function __construct(
30-
private readonly ImportMapManager $importMapManager,
32+
private readonly RemotePackageDownloader $packageDownloader,
33+
private readonly string $projectDir,
3134
) {
3235
parent::__construct();
3336
}
@@ -36,8 +39,36 @@ protected function execute(InputInterface $input, OutputInterface $output): int
3639
{
3740
$io = new SymfonyStyle($input, $output);
3841

39-
$downloadedPackages = $this->importMapManager->downloadMissingPackages();
40-
$io->success(sprintf('Downloaded %d assets.', \count($downloadedPackages)));
42+
$finishedCount = 0;
43+
$progressBar = new ProgressBar($output);
44+
$progressBar->setFormat('<info>%current%/%max%</info> %bar% %url%');
45+
$downloadedPackages = $this->packageDownloader->downloadPackages(function (string $package, string $event, ResponseInterface $response, int $totalPackages) use (&$finishedCount, $progressBar) {
46+
$progressBar->setMessage($response->getInfo('url'), 'url');
47+
if (0 === $progressBar->getMaxSteps()) {
48+
$progressBar->setMaxSteps($totalPackages);
49+
$progressBar->start();
50+
}
51+
52+
if ('finished' === $event) {
53+
++$finishedCount;
54+
$progressBar->advance();
55+
}
56+
});
57+
$progressBar->finish();
58+
$progressBar->clear();
59+
60+
if (0 === \count($downloadedPackages)) {
61+
$io->success('No assets to install.');
62+
63+
return Command::SUCCESS;
64+
}
65+
66+
$io->success(sprintf(
67+
'Downloaded %d asset%s into %s.',
68+
\count($downloadedPackages),
69+
1 == \count($downloadedPackages) ? '' : 's',
70+
str_replace($this->projectDir.'/', '', $this->packageDownloader->getVendorDir()),
71+
));
4172

4273
return Command::SUCCESS;
4374
}

src/Symfony/Component/AssetMapper/Command/ImportMapRequireCommand.php

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\AssetMapper\Command;
1313

14-
use Symfony\Bundle\FrameworkBundle\Console\Application;
1514
use Symfony\Component\AssetMapper\AssetMapperInterface;
1615
use Symfony\Component\AssetMapper\ImportMap\ImportMapEntry;
1716
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
@@ -113,9 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
113112
$packages[] = new PackageRequireOptions(
114113
$parts['package'],
115114
$parts['version'] ?? null,
116-
$input->getOption('download'),
117115
$parts['alias'] ?? $parts['package'],
118-
isset($parts['registry']) && $parts['registry'] ? $parts['registry'] : null,
119116
$path,
120117
);
121118
}
@@ -125,19 +122,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
125122
$newPackage = $newPackages[0];
126123
$message = sprintf('Package "%s" added to importmap.php', $newPackage->importName);
127124

128-
if ($newPackage->isDownloaded && null !== $downloadedAsset = $this->assetMapper->getAsset($newPackage->path)) {
129-
$application = $this->getApplication();
130-
if ($application instanceof Application) {
131-
$projectDir = $application->getKernel()->getProjectDir();
132-
$downloadedPath = $downloadedAsset->sourcePath;
133-
if (str_starts_with($downloadedPath, $projectDir)) {
134-
$downloadedPath = substr($downloadedPath, \strlen($projectDir) + 1);
135-
}
136-
137-
$message .= sprintf(' and downloaded locally to "%s"', $downloadedPath);
138-
}
139-
}
140-
141125
$message .= '.';
142126
} else {
143127
$names = array_map(fn (ImportMapEntry $package) => $package->importName, $newPackages);

src/Symfony/Component/AssetMapper/Compiler/JavaScriptImportPathCompiler.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ private function findAssetForBareImport(string $importedModule, AssetMapperInter
146146
}
147147

148148
// remote entries have no MappedAsset
149-
if ($importMapEntry->isRemote()) {
149+
if ($importMapEntry->isRemotePackage()) {
150150
return null;
151151
}
152152

@@ -158,7 +158,10 @@ private function findAssetForRelativeImport(string $importedModule, MappedAsset
158158
try {
159159
$resolvedPath = $this->resolvePath(\dirname($asset->logicalPath), $importedModule);
160160
} catch (RuntimeException $e) {
161-
$this->handleMissingImport(sprintf('Error processing import in "%s": ', $asset->sourcePath).$e->getMessage(), $e);
161+
// avoid warning about vendor imports - these are often comments
162+
if (!$asset->isVendor) {
163+
$this->handleMissingImport(sprintf('Error processing import in "%s": ', $asset->sourcePath).$e->getMessage(), $e);
164+
}
162165

163166
return null;
164167
}
@@ -179,7 +182,10 @@ private function findAssetForRelativeImport(string $importedModule, MappedAsset
179182
// avoid circular error if there is self-referencing import comments
180183
}
181184

182-
$this->handleMissingImport($message);
185+
// avoid warning about vendor imports - these are often comments
186+
if (!$asset->isVendor) {
187+
$this->handleMissingImport($message);
188+
}
183189

184190
return null;
185191
}

src/Symfony/Component/AssetMapper/Factory/MappedAssetFactory.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ class MappedAssetFactory implements MappedAssetFactoryInterface
2929
private array $fileContentsCache = [];
3030

3131
public function __construct(
32-
private PublicAssetsPathResolverInterface $assetsPathResolver,
33-
private AssetMapperCompiler $compiler,
32+
private readonly PublicAssetsPathResolverInterface $assetsPathResolver,
33+
private readonly AssetMapperCompiler $compiler,
34+
private readonly string $vendorDir,
3435
) {
3536
}
3637

@@ -43,7 +44,8 @@ public function createMappedAsset(string $logicalPath, string $sourcePath): ?Map
4344
if (!isset($this->assetsCache[$logicalPath])) {
4445
$this->assetsBeingCreated[] = $logicalPath;
4546

46-
$asset = new MappedAsset($logicalPath, $sourcePath, $this->assetsPathResolver->resolvePublicPath($logicalPath));
47+
$isVendor = $this->isVendor($sourcePath);
48+
$asset = new MappedAsset($logicalPath, $sourcePath, $this->assetsPathResolver->resolvePublicPath($logicalPath), isVendor: $isVendor);
4749

4850
[$digest, $isPredigested] = $this->getDigest($asset);
4951

@@ -55,6 +57,7 @@ public function createMappedAsset(string $logicalPath, string $sourcePath): ?Map
5557
$this->calculateContent($asset),
5658
$digest,
5759
$isPredigested,
60+
$isVendor,
5861
$asset->getDependencies(),
5962
$asset->getFileDependencies(),
6063
$asset->getJavaScriptImports(),
@@ -116,4 +119,12 @@ private function getPublicPath(MappedAsset $asset): ?string
116119

117120
return $this->assetsPathResolver->resolvePublicPath($digestedPath);
118121
}
122+
123+
private function isVendor(string $sourcePath): bool
124+
{
125+
$sourcePath = realpath($sourcePath);
126+
$vendorDir = realpath($this->vendorDir);
127+
128+
return $sourcePath && str_starts_with($sourcePath, $vendorDir);
129+
}
119130
}

0 commit comments

Comments
 (0)