diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapGenerator.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapGenerator.php index 135bf1a0a28a..80bbaadd1892 100644 --- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapGenerator.php +++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapGenerator.php @@ -217,25 +217,36 @@ private function findAsset(string $path): ?MappedAsset return $this->assetMapper->getAssetFromSourcePath($this->importMapConfigReader->convertPathToFilesystemPath($path)); } + /** + * Finds recursively all the non-lazy modules imported by an asset. + * + * @return array The array of deduplicated import names + */ private function findEagerImports(MappedAsset $asset): array { $dependencies = []; - foreach ($asset->getJavaScriptImports() as $javaScriptImport) { - if ($javaScriptImport->isLazy) { - continue; - } + $queue = [$asset]; - $dependencies[] = $javaScriptImport->importName; + while ($asset = array_shift($queue)) { + foreach ($asset->getJavaScriptImports() as $javaScriptImport) { + if ($javaScriptImport->isLazy) { + continue; + } + if (isset($dependencies[$javaScriptImport->importName])) { + continue; + } + $dependencies[$javaScriptImport->importName] = true; - // Follow its imports! - if (!$nextAsset = $this->assetMapper->getAsset($javaScriptImport->assetLogicalPath)) { - // should not happen at this point, unless something added a bogus JavaScriptImport to this asset - throw new LogicException(sprintf('Cannot find imported JavaScript asset "%s" in asset mapper.', $javaScriptImport->assetLogicalPath)); + // Follow its imports! + if (!$javaScriptAsset = $this->assetMapper->getAsset($javaScriptImport->assetLogicalPath)) { + // should not happen at this point, unless something added a bogus JavaScriptImport to this asset + throw new LogicException(sprintf('Cannot find JavaScript asset "%s" (imported in "%s") in asset mapper.', $javaScriptImport->assetLogicalPath, $asset->logicalPath)); + } + $queue[] = $javaScriptAsset; } - $dependencies = array_merge($dependencies, $this->findEagerImports($nextAsset)); } - return $dependencies; + return array_keys($dependencies); } private function createMissingImportMapAssetException(ImportMapEntry $entry): \InvalidArgumentException diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php index 31c0855d8f02..273e02747a24 100644 --- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapGeneratorTest.php @@ -671,6 +671,25 @@ public function getEagerEntrypointImportsTests(): iterable ['/assets/imports_simple.js', '/assets/simple.js'], [$simpleAsset, $importsSimpleAsset], ]; + + $importsSimpleAsset2 = new MappedAsset( + 'imports_simple2.js', + '/path/to/imports_simple2.js', + publicPathWithoutDigest: '/assets/imports_simple2.js', + javaScriptImports: [new JavaScriptImport('/assets/simple.js', assetLogicalPath: $simpleAsset->logicalPath, assetSourcePath: $simpleAsset->sourcePath, isLazy: false)] + ); + yield 'an entry recursive dependencies are deduplicated' => [ + new MappedAsset( + 'app.js', + publicPath: '/assets/app.js', + javaScriptImports: [ + new JavaScriptImport('/assets/imports_simple.js', assetLogicalPath: $importsSimpleAsset->logicalPath, assetSourcePath: $importsSimpleAsset->sourcePath, isLazy: false), + new JavaScriptImport('/assets/imports_simple2.js', assetLogicalPath: $importsSimpleAsset2->logicalPath, assetSourcePath: $importsSimpleAsset2->sourcePath, isLazy: false), + ] + ), + ['/assets/imports_simple.js', '/assets/imports_simple2.js', '/assets/simple.js'], + [$simpleAsset, $importsSimpleAsset, $importsSimpleAsset2], + ]; } public function testFindEagerEntrypointImportsUsesCacheFile()