8000 feature #38495 [Asset] [DX] Option to make asset manifests strict on … · symfony/symfony@7e28580 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7e28580

Browse files
committed
feature #38495 [Asset] [DX] Option to make asset manifests strict on missing item (GromNaN)
This PR was merged into the 5.4 branch. Discussion ---------- [Asset] [DX] Option to make asset manifests strict on missing item | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | symfony/symfony-docs#14414 In all the projects I use a JSON manifest, when an asset is not listed in manifest.json, the asset file is not generated. The current behavior is permissive as it returns the unmodified path of the asset. Which ends with a 404 when the browser tries to load the asset. With the option `strict_mode: true`, an exception is thrown when we try to use an asset that is not listed in `manifest.json`. Thereby we don't have to check that asset urls are actually working in tests (manual or automated). **Usage:** The option `strict_mode` is optional for backward compatibility. Using the `%kernel.debug%` value is safe to flush bugs on dev or test mode but keep the application working on production. ```yaml # config/packages/assets.yaml framework: assets: packages: app: # Uses a JSON manifest (can be a local path or an url remote file) json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' # Throws an exception when an expected entry is missing in the manifest strict_mode: '%kernel.debug%' ``` Todo: - [x] Documentation symfony/symfony-docs#14414 - [x] Demo symfony/demo#1168 - [x] ~Update recipe ?~ Commits ------- 4cdb921 Option to make asset manifests strict on missing item
2 parents aebe81b + 4cdb921 commit 7e28580

File tree

14 files changed

+186
-18
lines changed

14 files changed

+186
-18
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,10 @@ private function addAssetsSection(ArrayNodeDefinition $rootNode, callable $enabl
696696
->{$enableIfStandalone('symfony/asset', Package::class)}()
697697
->fixXmlConfig('base_url')
698698
->children()
699+
->booleanNode('strict_mode')
700+
->info('Throw an exception if an entry is missing from the manifest.json')
701+
->defaultFalse()
702+
->end()
699703
->scalarNode('version_strategy')->defaultNull()->end()
700704
->scalarNode('version')->defaultNull()->end()
701705
->scalarNode('version_format')->defaultValue('%%s?%%s')->end()
@@ -733,6 +737,10 @@ private function addAssetsSection(ArrayNodeDefinition $rootNode, callable $enabl
733737
->prototype('array')
734738
->fixXmlConfig('base_url')
735739
->children()
740+
->booleanNode('strict_mode')
741+
->info('Throw an exception if an entry is missing from the manifest.json')
742+
->defaultFalse()
743+
->end()
736744
->scalarNode('version_strategy')->defaultNull()->end()
737745
->scalarNode('version')
738746
->beforeNormalization()

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
11411141
if ($config['version_strategy']) {
11421142
$defaultVersion = new Reference($config['version_strategy']);
11431143
} else {
1144-
$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], $config['json_manifest_path'], '_default');
1144+
$defaultVersion = $this->createVersion($container, $config['version'], $config['version_format'], $config['json_manifest_path'], '_default', $config['strict_mode']);
11451145
}
11461146

11471147
$defaultPackage = $this->createPackageDefinition($config['base_path'], $config['base_urls'], $defaultVersion);
@@ -1157,7 +1157,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
11571157
// let format fallback to main version_format
11581158
$format = $package['version_format'] ?: $config['version_format'];
11591159
$version = $package['version'] ?? null;
1160-
$version = $this->createVersion($container, $version, $format, $package['json_manifest_path'], $name);
1160+
$version = $this->createVersion($container, $version, $format, $package['json_manifest_path'], $name, $package['strict_mode']);
11611161
}
11621162

11631163
$packageDefinition = $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version)
@@ -1186,7 +1186,7 @@ private function createPackageDefinition(?string $basePath, array $baseUrls, Ref
11861186
return $package;
11871187
}
11881188

1189-
private function createVersion(ContainerBuilder $container, ?string $version, ?string $format, ?string $jsonManifestPath, string $name): Reference
1189+
private function createVersion(ContainerBuilder $container, ?string $version, ?string $format, ?string $jsonManifestPath, string $name, bool $strictMode): Reference
11901190
{
11911191
// Configuration prevents $version and $jsonManifestPath from being set
11921192
if (null !== $version) {
@@ -1203,6 +1203,7 @@ private function createVersion(ContainerBuilder $container, ?string $version, ?s
12031203
if (null !== $jsonManifestPath) {
12041204
$def = new ChildDefinition('assets.json_manifest_version_strategy');
12051205
$def->replaceArgument(0, $jsonManifestPath);
1206+
$def->replaceArgument(2, $strictMode);
12061207
$container->setDefinition('assets._version_'.$name, $def);
12071208

12081209
return new Reference('assets._version_'.$name);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
->args([
8181
abstract_arg('manifest path'),
8282
service('http_client')->nullOnInvalid(),
83+
false,
8384
])
8485

8586
->set('assets.remote_json_manifest_version_strategy', RemoteJsonManifestVersionStrategy::class)

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
<xsd:attribute name="version" type="xsd:string" />
156156
<xsd:attribute name="version-format" type="xsd:string" />
157157
<xsd:attribute name="json-manifest-path" type="xsd:string" />
158+
<xsd:attribute name="strict-mode" type="xsd:boolean" />
158159
</xsd:complexType>
159160

160161
<xsd:complexType name="package">
@@ -168,6 +169,7 @@
168169
<xsd:attribute name="version" type="xsd:string" />
169170
<xsd:attribute name="version-format" type="xsd:string" />
170171
<xsd:attribute name="json-manifest-path" type="xsd:string" />
172+
<xsd:attribute name="strict-mode" type="xsd:boolean" />
171173
</xsd:complexType>
172174

173175
<xsd:complexType name="translator">

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function testAssetsCanBeEnabled()
8686
'base_urls' => [],
8787
'packages' => [],
8888
'json_manifest_path' => null,
89+
'strict_mode' => false,
8990
];
9091

9192
$this->assertEquals($defaultConfig, $config['assets']);
@@ -489,6 +490,7 @@ protected static function getBundleDefaultConfig()
489490
'base_urls' => [],
490491
'packages' => [],
491492
'json_manifest_path' => null,
493+
'strict_mode' => false,
492494
],
493495
'cache' => [
494496
'pools' => [],

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/assets.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
'env_manifest' => [
3737
'json_manifest_path' => '%env(env_manifest)%',
3838
],
39+
'strict_manifest_strategy' => [
40+
'json_manifest_path' => '/path/to/manifest.json',
41+
'strict_mode' => true,
42+
],
3943
],
4044
],
4145
]);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<framework:package name="remote_manifest" json-manifest-path="https://cdn.example.com/manifest.json" />
2626
<framework:package name="var_manifest" json-manifest-path="%var_json_manifest_path%" />
2727
<framework:package name="env_manifest" json-manifest-path="%env(env_manifest)%" />
28+
<framework:package name="strict_manifest_strategy" json-manifest-path="/path/to/manifest.json" strict-mode="true" />
2829
</framework:assets>
2930
</framework:config>
3031

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/assets.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ framework:
2525
json_manifest_path: '%var_json_manifest_path%'
2626
env_manifest:
2727
json_manifest_path: '%env(env_manifest)%'
28+
strict_manifest_strategy:
29+
json_manifest_path: '/path/to/manifest.json'
30+
strict_mode: true
2831

2932
parameters:
3033
var_json_manifest_path: 'https://cdn.example.com/manifest.json'

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ public function testAssets()
632632

633633
// packages
634634
$packageTags = $container->findTaggedServiceIds('assets.package');
635-
$this->assertCount(9, $packageTags);
635+
$this->assertCount(10, $packageTags);
636636

637637
$packages = [];
638638
foreach ($packageTags as $serviceId => $tagAttributes) {
@@ -658,6 +658,7 @@ public function testAssets()
658658
$versionStrategy = $container->getDefinition((string) $package->getArgument(1));
659659
$this->assertEquals('assets.json_manifest_version_strategy', $versionStrategy->getParent());
660660
$this->assertEquals('/path/to/manifest.json', $versionStrategy->getArgument(0));
661+
$this->assertFalse($versionStrategy->getArgument(2));
661662

662663
$package = $container->getDefinition($packages['remote_manifest']);
663664
$versionStrategy = $container->getDefinition($package->getArgument(1));
@@ -668,11 +669,19 @@ public function testAssets()
668669
$versionStrategy = $container->getDefinition($package->getArgument(1));
669670
$this->assertSame('assets.json_manifest_version_strategy', $versionStrategy->getParent());
670671
$this->assertSame('https://cdn.example.com/manifest.json', $versionStrategy->getArgument(0));
672+
$this->assertFalse($versionStrategy->getArgument(2));
671673

672674
$package = $container->getDefinition($packages['env_manifest']);
673675
$versionStrategy = $container->getDefinition($package->getArgument(1));
674676
$this->assertSame('assets.json_manifest_version_strategy', $versionStrategy->getParent());
675677
$this->assertStringMatchesFormat('env_%s', $versionStrategy->getArgument(0));
678+
$this->assertFalse($versionStrategy->getArgument(2));
679+
680+
$package = $container->getDefinition((string) $packages['strict_manifest_strategy']);
681+
$versionStrategy = $container->getDefinition((string) $package->getArgument(1));
682+
$this->assertEquals('assets.json_manifest_version_strategy', $versionStrategy->getParent());
683+
$this->assertEquals('/path/to/manifest.json', $versionStrategy->getArgument(0));
684+
$this->assertTrue($versionStrategy->getArgument(2));
676685
}
677686

678687
public function testAssetsDefaultVersionStrategyAsService()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Asset\Exception;
13+
14+
/**
15+
* Represents an asset not found in a manifest.
16+
*/
17+
class AssetNotFoundException extends RuntimeException
18+
{
19+
private $alternatives;
20+
21+
/**
22+
* @param string $message Exception message to throw
23+
* @param array $alternatives List of similar defined names
24+
* @param int $code Exception code
25+
* @param \Throwable $previous Previous exception used for the exception chaining
26+
*/
27+
public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
28+
{
29+
parent::__construct($message, $code, $previous);
30+
31+
$this->alternatives = $alternatives;
32+
}
33+
34+
/**
35+
* @return array A list of similar defined names
36+
*/
37+
public function getAlternatives(): array
38+
{
39+
return $this->alternatives;
40+
}
41+
}

0 commit comments

Comments
 (0)
0