diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index c6b343c96d8..947fa138fec 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -62,6 +62,11 @@ class MyLiveComponent { * Options `authReferrerPolicy`, `mapIds`, `channel`, `solutionChannel` have been added * Options `ìd`, `nonce`, `retries`, `url` have been removed +## StimulusBundle + +* The Twig function `ux_controller_link_tags()` has been removed, which requires Symfony AssetMapper >=6.4, + run `composer require symfony/asset-mapper:>=6.4` if you don't have it installed yet. + ## Swup * The package has been removed, see the [previous README](https://raw.githubusercontent.com/symfony/ux/refs/heads/2.x/src/Turbo/README.md) diff --git a/src/StimulusBundle/CHANGELOG.md b/src/StimulusBundle/CHANGELOG.md index 9b66e398bc0..778856eda5e 100644 --- a/src/StimulusBundle/CHANGELOG.md +++ b/src/StimulusBundle/CHANGELOG.md @@ -4,6 +4,7 @@ - Minimum required Symfony version is now 6.4 - Minimum required PHP version is now 8.2 +- Remove Twig function `ux_controller_link_tags()`, which requires Symfony AssetMapper >=6.4 ## 2.30 diff --git a/src/StimulusBundle/composer.json b/src/StimulusBundle/composer.json index 3043f6a8c84..b0c7378966d 100644 --- a/src/StimulusBundle/composer.json +++ b/src/StimulusBundle/composer.json @@ -21,6 +21,9 @@ "twig/twig": "^2.15.3|^3.8", "symfony/deprecation-contracts": "^2.0|^3.0" }, + "conflict": { + "symfony/asset-mapper": "<6.4" + }, "require-dev": { "symfony/asset-mapper": "^6.4|^7.0|^8.0", "symfony/framework-bundle": "^6.4|^7.0|^8.0", diff --git a/src/StimulusBundle/config/services.php b/src/StimulusBundle/config/services.php index 239ce739441..36434998560 100644 --- a/src/StimulusBundle/config/services.php +++ b/src/StimulusBundle/config/services.php @@ -15,8 +15,6 @@ use Symfony\UX\StimulusBundle\AssetMapper\StimulusLoaderJavaScriptCompiler; use Symfony\UX\StimulusBundle\Helper\StimulusHelper; use Symfony\UX\StimulusBundle\Twig\StimulusTwigExtension; -use Symfony\UX\StimulusBundle\Twig\UxControllersTwigExtension; -use Symfony\UX\StimulusBundle\Twig\UxControllersTwigRuntime; use Symfony\UX\StimulusBundle\Ux\UxPackageReader; use Twig\Environment; @@ -45,17 +43,6 @@ ]) // symfony/asset-mapper services - ->set('stimulus.ux_controllers_twig_extension', UxControllersTwigExtension::class) - ->tag('twig.extension') - - ->set('stimulus.ux_controllers_twig_runtime', UxControllersTwigRuntime::class) - ->args([ - service('stimulus.asset_mapper.controllers_map_generator'), - service('asset_mapper'), - service('stimulus.asset_mapper.ux_package_reader'), - param('kernel.project_dir'), - ]) - ->tag('twig.runtime') ->set('stimulus.asset_mapper.controllers_map_generator', ControllersMapGenerator::class) ->args([ diff --git a/src/StimulusBundle/doc/index.rst b/src/StimulusBundle/doc/index.rst index 871eef39397..e5c938d4fb8 100644 --- a/src/StimulusBundle/doc/index.rst +++ b/src/StimulusBundle/doc/index.rst @@ -416,10 +416,6 @@ will import all your custom controllers as well as those from ``controllers.json It will also dynamically enable "debug" mode in Stimulus when your application is running in debug mode. -.. tip:: - - For AssetMapper 6.3 only, you also need a ``{{ ux_controller_link_tags() }}`` - in ``base.html.twig``. This is not needed in AssetMapper 6.4+. With WebpackEncoreBundle ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/StimulusBundle/src/DependencyInjection/Compiler/RemoveAssetMapperServicesCompiler.php b/src/StimulusBundle/src/DependencyInjection/Compiler/RemoveAssetMapperServicesCompiler.php index e805465dee8..98cc4fb101d 100644 --- a/src/StimulusBundle/src/DependencyInjection/Compiler/RemoveAssetMapperServicesCompiler.php +++ b/src/StimulusBundle/src/DependencyInjection/Compiler/RemoveAssetMapperServicesCompiler.php @@ -24,7 +24,6 @@ class RemoveAssetMapperServicesCompiler implements CompilerPassInterface public function process(ContainerBuilder $container): void { if (!$container->hasDefinition('asset_mapper')) { - $container->removeDefinition('stimulus.ux_controllers_twig_runtime'); $container->removeDefinition('stimulus.asset_mapper.controllers_map_generator'); $container->removeDefinition('stimulus.asset_mapper.loader_javascript_compiler'); } diff --git a/src/StimulusBundle/src/Twig/UxControllersTwigExtension.php b/src/StimulusBundle/src/Twig/UxControllersTwigExtension.php deleted file mode 100644 index 02e409b4061..00000000000 --- a/src/StimulusBundle/src/Twig/UxControllersTwigExtension.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\StimulusBundle\Twig; - -use Twig\Extension\AbstractExtension; -use Twig\TwigFunction; - -/** - * @internal - * - * @author Ryan Weaver - */ -final class UxControllersTwigExtension extends AbstractExtension -{ - public function getFunctions(): array - { - return [ - new TwigFunction('ux_controller_link_tags', [UxControllersTwigRuntime::class, 'renderLinkTags'], ['is_safe' => ['html']]), - ]; - } -} diff --git a/src/StimulusBundle/src/Twig/UxControllersTwigRuntime.php b/src/StimulusBundle/src/Twig/UxControllersTwigRuntime.php deleted file mode 100644 index aacb0914faf..00000000000 --- a/src/StimulusBundle/src/Twig/UxControllersTwigRuntime.php +++ /dev/null @@ -1,171 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\StimulusBundle\Twig; - -use Symfony\Component\AssetMapper\AssetMapperInterface; -use Symfony\Component\AssetMapper\ImportMap\ImportMapGenerator; -use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator; -use Symfony\UX\StimulusBundle\Ux\UxPackageReader; -use Twig\Extension\RuntimeExtensionInterface; - -/** - * Returns the link tags for all autoimported CSS files in controllers.json. - * - * @internal - * - * @author Ryan Weaver - */ -final class UxControllersTwigRuntime implements RuntimeExtensionInterface -{ - private array $importMap; - - public function __construct( - private ControllersMapGenerator $controllersMapGenerator, - private AssetMapperInterface $assetMapper, - private UxPackageReader $uxPackageReader, - private string $projectDir, - ) { - } - - /** - * Returns the CSS tags for all "autoimport" entries in controllers.json. - */ - public function renderLinkTags(): string - { - if (class_exists(ImportMapGenerator::class)) { - trigger_deprecation('symfony/ux-stimulus-bundle', '2.13.0', 'Calling ux_controller_link_tags() is deprecated and does nothing with symfony/asset-mapper 6.4. The link tags are rendered automatically via the importmap() function.'); - - return ''; - } - - $controllersFile = $this->controllersMapGenerator->getControllersJsonPath(); - if (!is_file($controllersFile)) { - return ''; - } - - $data = json_decode(file_get_contents($controllersFile), true, 512, \JSON_THROW_ON_ERROR); - $packages = $data['controllers'] ?? []; - - $links = []; - foreach ($packages as $uxPackageName => $controllers) { - foreach ($controllers as $controllerData) { - if (!$controllerData['enabled'] ?? false) { - continue; - } - - foreach ($controllerData['autoimport'] ?? [] as $autoImport => $enabled) { - if ($enabled) { - $links[] = \sprintf('', $this->getLinkHref($autoImport, $uxPackageName)); - } - } - } - } - - return implode("\n", $links); - } - - // duplicated & adapted in ControllersMapGenerator - private function getLinkHref(string $autoImport, string $uxPackageName): string - { - // see if this is a mapped asset path - $asset = $this->assetMapper->getAsset($autoImport); - if ($asset) { - return $asset->publicPath; - } - - $slashPosition = strpos($autoImport, '/'); - if (false === $slashPosition) { - throw new \LogicException(\sprintf('The autoimport "%s" is not valid.', $autoImport)); - } - - // if the first character is @, then the package name is @symfony/ux-cropperjs - $parts = explode('/', $autoImport); - if (str_starts_with($autoImport, '@')) { - $package = implode('/', \array_slice($parts, 0, 2)); - $file = implode('/', \array_slice($parts, 2)); - } else { - $package = $parts[0]; - $file = implode('/', \array_slice($parts, 1)); - } - - if ($package === $uxPackageName) { - // this is a file local to the ux package - $uxPackageMetadata = $this->uxPackageReader->readPackageMetadata($uxPackageName); - $filePath = $uxPackageMetadata->packageDirectory.'/'.$file; - if (!is_file($filePath)) { - throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and the file "%s" does not exist in the package path "%s". And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $file, $uxPackageMetadata->packageDirectory)); - } - - $asset = $this->assetMapper->getAssetFromSourcePath($filePath); - if (!$asset) { - throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This file was found, but the path is not in the asset mapper. And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport)); - } - - return $asset->publicPath; - } - - $importMap = $this->readImportMap(); - if (!isset($importMap[$package])) { - throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and no "%s" entry was found in importmap.php. And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $package)); - } - - $importMapEntry = $importMap[$package]; - if (!isset($importMapEntry['url'])) { - throw new \LogicException(\sprintf('An "autoimport" in "%s" refers to "%s". This path could not be found in the asset mapper and no "url" key was found in importmap.php for the package "%s". And so, the file cannot be loaded.', $this->shortControllersPath(), $autoImport, $package)); - } - - $version = $this->parseVersionFromUrl($importMapEntry['url']); - - return $this->getJsDelivrUrl($package, $version, $file); - } - - private function readImportMap(): array - { - if (!isset($this->importMap)) { - // this should be dynamic, but for now, we'll hardcode it - $path = $this->projectDir.'/importmap.php'; - $this->importMap = is_file($path) ? (static fn () => include $path)() : []; - } - - return $this->importMap; - } - - private function parseVersionFromUrl(string $url): ?string - { - $versionPattern = '/(?<=@)\d+(?:\.\d+)+/'; - if (!preg_match($versionPattern, $url, $matches)) { - return null; - } - - return $matches[0]; - } - - private function getJsDelivrUrl(string $package, ?string $version, string $file): string - { - $version ??= 'latest'; - $package = str_replace('@', '', $package); - - return \sprintf('https://cdn.jsdelivr.net/npm/%s@%s/%s', $package, $version, $file); - } - - private function shortControllersPath(): string - { - $path = $this->controllersMapGenerator->getControllersJsonPath(); - $path = realpath($path); - $projectDir = realpath($this->projectDir); - if (!str_starts_with($path, $projectDir)) { - return $path; - } - - return str_replace($projectDir, '', $path); - } -} diff --git a/src/StimulusBundle/tests/AssetMapper/AutoImportLocatorTest.php b/src/StimulusBundle/tests/AssetMapper/AutoImportLocatorTest.php index 78a3cc43a4f..6926f91f099 100644 --- a/src/StimulusBundle/tests/AssetMapper/AutoImportLocatorTest.php +++ b/src/StimulusBundle/tests/AssetMapper/AutoImportLocatorTest.php @@ -22,13 +22,6 @@ class AutoImportLocatorTest extends TestCase { - protected function setUp(): void - { - if (!class_exists(ImportMapConfigReader::class)) { - $this->markTestSkipped('Test requires AssetMapper >= 6.4.'); - } - } - public function testLocateAutoImportCanHandleAssetMapperPath() { $assetMapper = $this->createMock(AssetMapperInterface::class); diff --git a/src/StimulusBundle/tests/AssetMapper/ControllersMapGeneratorTest.php b/src/StimulusBundle/tests/AssetMapper/ControllersMapGeneratorTest.php index 15004969447..0b75ddd3f8f 100644 --- a/src/StimulusBundle/tests/AssetMapper/ControllersMapGeneratorTest.php +++ b/src/StimulusBundle/tests/AssetMapper/ControllersMapGeneratorTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\AssetMapper\AssetMapperInterface; -use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader; use Symfony\Component\AssetMapper\MappedAsset; use Symfony\UX\StimulusBundle\AssetMapper\AutoImportLocator; use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator; @@ -54,17 +53,11 @@ public function testGetControllersMap() $packageReader = new UxPackageReader(__DIR__.'/../fixtures'); $autoImportLocator = $this->createMock(AutoImportLocator::class); - if (class_exists(ImportMapConfigReader::class)) { - $autoImportLocator->expects($this->any()) - ->method('locateAutoImport') - ->willReturnCallback(function ($path) { - return new MappedControllerAutoImport('/path/to'.$path, false); - }); - } else { - // @legacy for AssetMapper 6.3 - $autoImportLocator->expects($this->never()) - ->method('locateAutoImport'); - } + $autoImportLocator->expects($this->any()) + ->method('locateAutoImport') + ->willReturnCallback(function ($path) { + return new MappedControllerAutoImport('/path/to'.$path, false); + }); $generator = new ControllersMapGenerator( $mapper, @@ -106,11 +99,7 @@ public function testGetControllersMap() $this->assertSame('fake-vendor/ux-package1/package-controller-second.js', $controllerSecond->asset->logicalPath); // lazy from user's controller.json $this->assertTrue($controllerSecond->isLazy); - // @legacy: assert can be without the conditional for AssetMapper 6.4+ - if (class_exists(ImportMapConfigReader::class)) { - // 4 auto imports from package.json - $this->assertCount(4, $controllerSecond->autoImports); - } + $this->assertCount(4, $controllerSecond->autoImports); $helloControllerFromPackage = $map['fake-vendor--ux-package2--hello-controller']; $this->assertSame('fake-vendor/ux-package2/package-hello-controller.js', $helloControllerFromPackage->asset->logicalPath); diff --git a/src/StimulusBundle/tests/AssetMapper/StimulusControllerLoaderFunctionalTest.php b/src/StimulusBundle/tests/AssetMapper/StimulusControllerLoaderFunctionalTest.php index 346fca2fa32..b1f110e0294 100644 --- a/src/StimulusBundle/tests/AssetMapper/StimulusControllerLoaderFunctionalTest.php +++ b/src/StimulusBundle/tests/AssetMapper/StimulusControllerLoaderFunctionalTest.php @@ -13,7 +13,6 @@ use Composer\InstalledVersions; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader; use Symfony\Component\Filesystem\Filesystem; use Symfony\UX\StimulusBundle\Tests\fixtures\StimulusTestKernel; use Zenstruck\Browser\Test\HasBrowser; @@ -33,123 +32,79 @@ public function testFullApplicationLoad() $crawler = $this->browser() ->get('/') - ->crawler() - ; + ->crawler(); $importMapJson = $crawler->filter('script[type="importmap"]')->html(); $importMap = json_decode($importMapJson, true); $importMapKeys = array_keys($importMap['imports']); - if (class_exists(ImportMapConfigReader::class)) { - // filter out items ending in .css - $importMapJsKeys = array_filter($importMapKeys, function ($key) { - return '.css' !== substr($key, -4); - }); - $importMapCssKeys = array_filter($importMapKeys, function ($key) { - return '.css' === substr($key, -4); - }); - sort($importMapJsKeys); - $this->assertSame([ - // 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap) - '/assets/@symfony/stimulus-bundle/controllers.js', - // 7x from "controllers" (hello is overridden) - '/assets/controllers/bye_controller.js', - '/assets/controllers/hello-with-dashes-controller.js', - '/assets/controllers/hello_with_underscores-controller.js', - '/assets/controllers/subdir/deeper-controller.js', - '/assets/controllers/subdir/deeper-with-dashes-controller.js', - '/assets/controllers/subdir/deeper_with_underscores-controller.js', - '/assets/controllers/typescript-controller.ts', - // 2x from UX packages, which are enabled in controllers.json - '/assets/fake-vendor/ux-package1/package-controller-second.js', - '/assets/fake-vendor/ux-package2/package-hello-controller.js', - // 4x from more-controllers - '/assets/more-controllers/excluded-controller.js', - '/assets/more-controllers/hello-controller.js', - '/assets/more-controllers/minified-controller.js', - '/assets/more-controllers/other-controller.js', - // 5x from importmap.php - '@hotwired/stimulus', - '@scoped/needed-vendor', - '@symfony/stimulus-bundle', - 'app', - 'needed-vendor', - ], array_values($importMapJsKeys)); + // filter out items ending in .css + $importMapJsKeys = array_filter($importMapKeys, function ($key) { + return '.css' !== substr($key, -4); + }); + $importMapCssKeys = array_filter($importMapKeys, function ($key) { + return '.css' === substr($key, -4); + }); + sort($importMapJsKeys); + $this->assertSame([ + // 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap) + '/assets/@symfony/stimulus-bundle/controllers.js', + // 7x from "controllers" (hello is overridden) + '/assets/controllers/bye_controller.js', + '/assets/controllers/hello-with-dashes-controller.js', + '/assets/controllers/hello_with_underscores-controller.js', + '/assets/controllers/subdir/deeper-controller.js', + '/assets/controllers/subdir/deeper-with-dashes-controller.js', + '/assets/controllers/subdir/deeper_with_underscores-controller.js', + '/assets/controllers/typescript-controller.ts', + // 2x from UX packages, which are enabled in controllers.json + '/assets/fake-vendor/ux-package1/package-controller-second.js', + '/assets/fake-vendor/ux-package2/package-hello-controller.js', + // 4x from more-controllers + '/assets/more-controllers/excluded-controller.js', + '/assets/more-controllers/hello-controller.js', + '/assets/more-controllers/minified-controller.js', + '/assets/more-controllers/other-controller.js', + // 5x from importmap.php + '@hotwired/stimulus', + '@scoped/needed-vendor', + '@symfony/stimulus-bundle', + 'app', + 'needed-vendor', + ], array_values($importMapJsKeys)); - // the autoimport CSS - $this->assertSame([ - '/assets/in/asset/mapper/controller_second1.css', - // enabled => false - // '/assets/in/asset/mapper/controller_second2.css', - '/assets/fake-vendor/ux-package1/styles.css', + // the autoimport CSS + $this->assertSame([ + '/assets/in/asset/mapper/controller_second1.css', + // enabled => false + // '/assets/in/asset/mapper/controller_second2.css', + '/assets/fake-vendor/ux-package1/styles.css', - // 2x from importmap.php: so they should, of course, be here. - // But our compiler should not add "path-based" entries - // '/assets/vendor/needed-vendor/file.css', - // '/assets/vendor/@scoped/needed-vendor/the/file2.css', - 'needed-vendor/file.css', - '@scoped/needed-vendor/the/file2.css', - ], array_values($importMapCssKeys)); + // 2x from importmap.php: so they should, of course, be here. + // But our compiler should not add "path-based" entries + // '/assets/vendor/needed-vendor/file.css', + // '/assets/vendor/@scoped/needed-vendor/the/file2.css', + 'needed-vendor/file.css', + '@scoped/needed-vendor/the/file2.css', + ], array_values($importMapCssKeys)); - // "app" is the entry. So, all non-lazy controllers should be preloaded: - $preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(function ($link) { - return $link->attr('href'); - }); - $this->assertCount(12, $preLoadHrefs); - sort($preLoadHrefs); - $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]); - $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]); - $this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[3]); - $this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[4]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[5]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[6]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[7]); - $this->assertStringStartsWith('/assets/controllers/typescript-controller-', $preLoadHrefs[8]); - $this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[9]); - $this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[10]); - $this->assertStringStartsWith('/assets/vendor/@hotwired/stimulus/stimulus.index', $preLoadHrefs[11]); - } else { - // legacy - $this->assertSame([ - // 1x import from loader.js (which is aliased to @symfony/stimulus-bundle via importmap) - '/assets/@symfony/stimulus-bundle/controllers.js', - // 6x from "controllers" (hello is overridden) - '/assets/controllers/bye_controller.js', - '/assets/controllers/hello-with-dashes-controller.js', - '/assets/controllers/hello_with_underscores-controller.js', - '/assets/controllers/subdir/deeper-controller.js', - '/assets/controllers/subdir/deeper-with-dashes-controller.js', - '/assets/controllers/subdir/deeper_with_underscores-controller.js', - // 2x from UX packages, which are enabled in controllers.json - '/assets/fake-vendor/ux-package1/package-controller-second.js', - '/assets/fake-vendor/ux-package2/package-hello-controller.js', - // 2x from more-controllers - '/assets/more-controllers/hello-controller.js', - '/assets/more-controllers/other-controller.js', - // 5x from importmap.php - '@hotwired/stimulus', - '@scoped/needed-vendor', - '@symfony/stimulus-bundle', - 'app', - 'needed-vendor', - ], $importMapKeys); - - // "app" & loader.js are pre-loaded. So, all non-lazy controllers should be preloaded: - $preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(function ($link) { - return $link->attr('href'); - }); - $this->assertCount(10, $preLoadHrefs); - sort($preLoadHrefs); - $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]); - $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]); - $this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[2]); - $this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[3]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[4]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[5]); - $this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[6]); - $this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[7]); - $this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[8]); - } + // "app" is the entry. So, all non-lazy controllers should be preloaded: + $preLoadHrefs = $crawler->filter('link[rel="modulepreload"]')->each(function ($link) { + return $link->attr('href'); + }); + $this->assertCount(12, $preLoadHrefs); + sort($preLoadHrefs); + $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/controllers-', $preLoadHrefs[0]); + $this->assertStringStartsWith('/assets/@symfony/stimulus-bundle/loader-', $preLoadHrefs[1]); + $this->assertStringStartsWith('/assets/controllers/hello-with-dashes-controller-', $preLoadHrefs[3]); + $this->assertStringStartsWith('/assets/controllers/hello_with_underscores-controller-', $preLoadHrefs[4]); + $this->assertStringStartsWith('/assets/controllers/subdir/deeper-controller-', $preLoadHrefs[5]); + $this->assertStringStartsWith('/assets/controllers/subdir/deeper-with-dashes-controller-', $preLoadHrefs[6]); + $this->assertStringStartsWith('/assets/controllers/subdir/deeper_with_underscores-controller-', $preLoadHrefs[7]); + $this->assertStringStartsWith('/assets/controllers/typescript-controller-', $preLoadHrefs[8]); + $this->assertStringStartsWith('/assets/fake-vendor/ux-package2/package-hello-controller-', $preLoadHrefs[9]); + $this->assertStringStartsWith('/assets/more-controllers/hello-controller-', $preLoadHrefs[10]); + $this->assertStringStartsWith('/assets/vendor/@hotwired/stimulus/stimulus.index', $preLoadHrefs[11]); } protected static function getKernelClass(): string diff --git a/src/StimulusBundle/tests/Twig/UxControllersTwigRuntimeTest.php b/src/StimulusBundle/tests/Twig/UxControllersTwigRuntimeTest.php deleted file mode 100644 index fd507ae05b8..00000000000 --- a/src/StimulusBundle/tests/Twig/UxControllersTwigRuntimeTest.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\StimulusBundle\Tests\Twig; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\AssetMapper\AssetMapperInterface; -use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader; -use Symfony\Component\AssetMapper\MappedAsset; -use Symfony\UX\StimulusBundle\AssetMapper\ControllersMapGenerator; -use Symfony\UX\StimulusBundle\Twig\UxControllersTwigRuntime; -use Symfony\UX\StimulusBundle\Ux\UxPackageReader; - -class UxControllersTwigRuntimeTest extends TestCase -{ - /** - * @group legacy - */ - public function testRenderLinkTags() - { - if (class_exists(ImportMapConfigReader::class)) { - $this->markTestSkipped('Skip test for AssetMapper 6.4+'); - } - - $controllersMapGenerator = $this->createMock(ControllersMapGenerator::class); - $controllersMapGenerator->expects($this->any()) - ->method('getControllersJsonPath') - ->willReturn(__DIR__.'/../fixtures/assets/controllers.json') - ; - - $assetMapper = $this->createMock(AssetMapperInterface::class); - $assetMapper->expects($this->any()) - ->method('getAsset') - ->willReturnCallback(function ($path) { - if (str_starts_with($path, 'in/asset/mapper')) { - return new MappedAsset(basename($path), publicPath: '/assets/mapper/'.basename($path)); - } - - if (str_starts_with($path, '@fake-vendor/ux-package1')) { - return new MappedAsset('fake-vendor/ux-package1/'.basename($path), publicPath: '/assets/@fake-vendor/ux-package1/'.basename($path)); - } - - return null; - }); - - $runtime = new UxControllersTwigRuntime( - $controllersMapGenerator, - $assetMapper, - new UxPackageReader(__DIR__.'/../fixtures'), - __DIR__.'/../fixtures/legacy' - ); - - $this->assertStringNotContainsString( - 'controller_first.css', - $runtime->renderLinkTags() - ); - $this->assertStringContainsString( - 'href="/assets/mapper/controller_second1.css"', - $runtime->renderLinkTags() - ); - $this->assertStringNotContainsString( - 'controller_second2.css', - $runtime->renderLinkTags() - ); - $this->assertStringContainsString( - 'href="/assets/@fake-vendor/ux-package1/styles.css"', - $runtime->renderLinkTags() - ); - $this->assertStringContainsString( - 'href="https://cdn.jsdelivr.net/npm/needed-vendor@3.2.0/file.css"', - $runtime->renderLinkTags() - ); - $this->assertStringContainsString( - 'href="https://cdn.jsdelivr.net/npm/scoped/needed-vendor@1.2.3/the/file2.css"', - $runtime->renderLinkTags() - ); - - // loop through a controllers.json file with several autoimports - // cases for the assets: - // 1) asset path is in the pipeline - // 2) path starts with the "package name" (try with scoped and non-scoped) - // then look right inside the package - // 3) look inside importmap.php for a "url" package and map to jsdelivr - } -} diff --git a/src/StimulusBundle/tests/fixtures/StimulusTestKernel.php b/src/StimulusBundle/tests/fixtures/StimulusTestKernel.php index ff8337f2ae6..16bf388bf72 100644 --- a/src/StimulusBundle/tests/fixtures/StimulusTestKernel.php +++ b/src/StimulusBundle/tests/fixtures/StimulusTestKernel.php @@ -15,7 +15,6 @@ use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Bundle\TwigBundle\TwigBundle; -use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpFoundation\Response; @@ -60,7 +59,7 @@ protected function configureContainer(ContainerConfigurator $container): void __DIR__.'/vendor/fake-vendor/ux-package2/Resources/assets/dist' => 'fake-vendor/ux-package2', ], // @legacy - 'importmap_path' => '%kernel.project_dir%/'.(class_exists(ImportMapConfigReader::class) ? 'importmap.php' : 'legacy/importmap.php'), + 'importmap_path' => '%kernel.project_dir%/importmap.php', ], 'test' => true, ...(self::VERSION_ID >= 60200 ? [ diff --git a/src/StimulusBundle/tests/fixtures/legacy/importmap.php b/src/StimulusBundle/tests/fixtures/legacy/importmap.php deleted file mode 100644 index 998ee44649c..00000000000 --- a/src/StimulusBundle/tests/fixtures/legacy/importmap.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -// @legacy for AssetMapper 6.3 support -return [ - 'app' => [ - 'path' => 'app.js', - 'entrypoint' => true, - ], - '@hotwired/stimulus' => [ - 'url' => 'https://ga.jspm.io/npm:@hotwired/stimulus@3.2.1/dist/stimulus.js', - ], - '@symfony/stimulus-bundle' => [ - 'path' => '@symfony/stimulus-bundle/loader.js', - ], - 'needed-vendor' => [ - 'url' => 'https://cdn.jsdelivr.net/npm/needed-vendor@3.2.0/dist/needed-vendor+esm', - ], - '@scoped/needed-vendor' => [ - 'url' => 'https://cdn.jsdelivr.net/npm/@scoped/needed-vendor@1.2.3', - ], -];