Skip to content

Commit ab5cddb

Browse files
daniserSergey Danilchenkotaylorotwell
authored
[9.x] Vite: ability to prevent preload tag generation from attribute resolver callback (#45283)
* Vite: ability to prevent preload tag generation from attribute resolver callback * Update Vite.php Co-authored-by: Sergey Danilchenko <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
1 parent 60808a7 commit ab5cddb

File tree

3 files changed

+170
-11
lines changed

3 files changed

+170
-11
lines changed

src/Illuminate/Foundation/Vite.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public function useStyleTagAttributes($attributes)
233233
/**
234234
* Use the given callback to resolve attributes for preload tags.
235235
*
236-
* @param (callable(string, string, ?array, ?array): array)|array $attributes
236+
* @param (callable(string, string, ?array, ?array): array|false)|array|false $attributes
237237
* @return $this
238238
*/
239239
public function usePreloadTagAttributes($attributes)
@@ -351,8 +351,8 @@ public function __invoke($entrypoints, $buildDirectory = null)
351351
*
352352
* @param string $src
353353
* @param string $url
354-
* @param ?array $chunk
355-
* @param ?array $manifest
354+
* @param array|null $chunk
355+
* @param array|null $manifest
356356
* @return string
357357
*/
358358
protected function makeTagForChunk($src, $url, $chunk, $manifest)
@@ -386,12 +386,16 @@ protected function makeTagForChunk($src, $url, $chunk, $manifest)
386386
* @param string $url
387387
* @param array $chunk
388388
* @param array $manifest
389-
* @return string|null
389+
* @return string
390390
*/
391391
protected function makePreloadTagForChunk($src, $url, $chunk, $manifest)
392392
{
393393
$attributes = $this->resolvePreloadTagAttributes($src, $url, $chunk, $manifest);
394394

395+
if ($attributes === false) {
396+
return '';
397+
}
398+
395399
$this->preloadedAssets[$url] = $this->parseAttributes(
396400
Collection::make($attributes)->forget('href')->all()
397401
);
@@ -404,8 +408,8 @@ protected function makePreloadTagForChunk($src, $url, $chunk, $manifest)
404408
*
405409
* @param string $src
406410
* @param string $url
407-
* @param ?array $chunk
408-
* @param ?array $manifest
411+
* @param array|null $chunk
412+
* @param array|null $manifest
409413
* @return array
410414
*/
411415
protected function resolveScriptTagAttributes($src, $url, $chunk, $manifest)
@@ -426,8 +430,8 @@ protected function resolveScriptTagAttributes($src, $url, $chunk, $manifest)
426430
*
427431
* @param string $src
428432
* @param string $url
429-
* @param ?array $chunk
430-
* @param ?array $manifest
433+
* @param array|null $chunk
434+
* @param array|null $manifest
431435
* @return array
432436
*/
433437
protected function resolveStylesheetTagAttributes($src, $url, $chunk, $manifest)
@@ -450,7 +454,7 @@ protected function resolveStylesheetTagAttributes($src, $url, $chunk, $manifest)
450454
* @param string $url
451455
* @param array $chunk
452456
* @param array $manifest
453-
* @return array
457+
* @return array|false
454458
*/
455459
protected function resolvePreloadTagAttributes($src, $url, $chunk, $manifest)
456460
{
@@ -472,7 +476,11 @@ protected function resolvePreloadTagAttributes($src, $url, $chunk, $manifest)
472476
: $attributes;
473477

474478
foreach ($this->preloadTagAttributesResolvers as $resolver) {
475-
$attributes = array_merge($attributes, $resolver($src, $url, $chunk, $manifest));
479+
if (false === ($resolvedAttributes = $resolver($src, $url, $chunk, $manifest))) {
480+
return false;
481+
}
482+
483+
$attributes = array_merge($attributes, $resolvedAttributes);
476484
}
477485

478486
return $attributes;

src/Illuminate/Support/Facades/Vite.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* @method static \Illuminate\Foundation\Vite useBuildDirectory(string $path)
1515
* @method static \Illuminate\Foundation\Vite useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
1616
* @method static \Illuminate\Foundation\Vite useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
17-
* @method static \Illuminate\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
17+
* @method static \Illuminate\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array|false)|array|false $attributes)
1818
* @method static \Illuminate\Support\HtmlString|void reactRefresh()
1919
* @method static string asset(string $asset, string|null $buildDirectory = null)
2020
* @method static string|null manifestHash(string|null $buildDirectory = null)

tests/Foundation/FoundationViteTest.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,157 @@ public function testItCanSpecifyAttributesForPreloadedAssets()
865865
$this->cleanViteManifest($buildDir);
866866
}
867867

868+
public function testItCanSuppressPreloadTagGeneration()
869+
{
870+
$buildDir = Str::random();
871+
$this->makeViteManifest([
872+
'resources/js/app.js' => [
873+
'src' => 'resources/js/app.js',
874+
'file' => 'assets/app.versioned.js',
875+
'imports' => [
876+
'import.js',
877+
'import-nopreload.js',
878+
],
879+
'css' => [
880+
'assets/app.versioned.css',
881+
'assets/app-nopreload.versioned.css',
882+
],
883+
],
884+
'resources/js/app-nopreload.js' => [
885+
'src' => 'resources/js/app-nopreload.js',
886+
'file' => 'assets/app-nopreload.versioned.js',
887+
],
888+
'import.js' => [
889+
'file' => 'assets/import.versioned.js',
890+
],
891+
'import-nopreload.js' => [
892+
'file' => 'assets/import-nopreload.versioned.js',
893+
],
894+
'resources/css/app.css' => [
895+
'src' => 'resources/css/app.css',
896+
'file' => 'assets/app.versioned.css',
897+
],
898+
'resources/css/app-nopreload.css' => [
899+
'src' => 'resources/css/app-nopreload.css',
900+
'file' => 'assets/app-nopreload.versioned.css',
901+
],
902+
], $buildDir);
903+
ViteFacade::usePreloadTagAttributes(function ($src, $url, $chunk, $manifest) use ($buildDir) {
904+
$this->assertSame([
905+
'resources/js/app.js' => [
906+
'src' => 'resources/js/app.js',
907+
'file' => 'assets/app.versioned.js',
908+
'imports' => [
909+
'import.js',
910+
'import-nopreload.js',
911+
],
912+
'css' => [
913+
'assets/app.versioned.css',
914+
'assets/app-nopreload.versioned.css',
915+
],
916+
],
917+
'resources/js/app-nopreload.js' => [
918+
'src' => 'resources/js/app-nopreload.js',
919+
'file' => 'assets/app-nopreload.versioned.js',
920+
],
921+
'import.js' => [
922+
'file' => 'assets/import.versioned.js',
923+
],
924+
'import-nopreload.js' => [
925+
'file' => 'assets/import-nopreload.versioned.js',
926+
],
927+
'resources/css/app.css' => [
928+
'src' => 'resources/css/app.css',
929+
'file' => 'assets/app.versioned.css',
930+
],
931+
'resources/css/app-nopreload.css' => [
932+
'src' => 'resources/css/app-nopreload.css',
933+
'file' => 'assets/app-nopreload.versioned.css',
934+
],
935+
], $manifest);
936+
937+
(match ($src) {
938+
'resources/js/app.js' => function () use ($url, $chunk, $buildDir) {
939+
$this->assertSame("https://example.com/{$buildDir}/assets/app.versioned.js", $url);
940+
$this->assertSame([
941+
'src' => 'resources/js/app.js',
942+
'file' => 'assets/app.versioned.js',
943+
'imports' => [
944+
'import.js',
945+
'import-nopreload.js',
946+
],
947+
'css' => [
948+
'assets/app.versioned.css',
949+
'assets/app-nopreload.versioned.css',
950+
],
951+
], $chunk);
952+
},
953+
'resources/js/app-nopreload.js' => function () use ($url, $chunk, $buildDir) {
954+
$this->assertSame("https://example.com/{$buildDir}/assets/app-nopreload.versioned.js", $url);
955+
$this->assertSame([
956+
'src' => 'resources/js/app-nopreload.js',
957+
'file' => 'assets/app-nopreload.versioned.js',
958+
], $chunk);
959+
},
960+
'import.js' => function () use ($url, $chunk, $buildDir) {
961+
$this->assertSame("https://example.com/{$buildDir}/assets/import.versioned.js", $url);
962+
$this->assertSame([
963+
'file' => 'assets/import.versioned.js',
964+
], $chunk);
965+
},
966+
'import-nopreload.js' => function () use ($url, $chunk, $buildDir) {
967+
$this->assertSame("https://example.com/{$buildDir}/assets/import-nopreload.versioned.js", $url);
968+
$this->assertSame([
969+
'file' => 'assets/import-nopreload.versioned.js',
970+
], $chunk);
971+
},
972+
'resources/css/app.css' => function () use ($url, $chunk, $buildDir) {
973+
$this->assertSame("https://example.com/{$buildDir}/assets/app.versioned.css", $url);
974+
$this->assertSame([
975+
'src' => 'resources/css/app.css',
976+
'file' => 'assets/app.versioned.css',
977+
], $chunk);
978+
},
979+
'resources/css/app-nopreload.css' => function () use ($url, $chunk, $buildDir) {
980+
$this->assertSame("https://example.com/{$buildDir}/assets/app-nopreload.versioned.css", $url);
981+
$this->assertSame([
982+
'src' => 'resources/css/app-nopreload.css',
983+
'file' => 'assets/app-nopreload.versioned.css',
984+
], $chunk);
985+
},
986+
})();
987+
988+
return Str::contains($src, '-nopreload') ? false : [];
989+
});
990+
991+
$result = app(Vite::class)(['resources/js/app.js', 'resources/js/app-nopreload.js'], $buildDir);
992+
993+
$this->assertSame(
994+
'<link rel="preload" as="style" href="https://example.com/'.$buildDir.'/assets/app.versioned.css" />'
995+
.'<link rel="modulepreload" href="https://example.com/'.$buildDir.'/assets/app.versioned.js" />'
996+
.'<link rel="modulepreload" href="https://example.com/'.$buildDir.'/assets/import.versioned.js" />'
997+
.'<link rel="stylesheet" href="https://example.com/'.$buildDir.'/assets/app.versioned.css" />'
998+
.'<link rel="stylesheet" href="https://example.com/'.$buildDir.'/assets/app-nopreload.versioned.css" />'
999+
.'<script type="module" src="https://example.com/'.$buildDir.'/assets/app.versioned.js"></script>'
1000+
.'<script type="module" src="https://example.com/'.$buildDir.'/assets/app-nopreload.versioned.js"></script>',
1001+
$result->toHtml());
1002+
1003+
$this->assertSame([
1004+
"https://example.com/$buildDir/assets/app.versioned.css" => [
1005+
'rel="preload"',
1006+
'as="style"',
1007+
],
1008+
"https://example.com/$buildDir/assets/app.versioned.js" => [
1009+
'rel="modulepreload"',
1010+
],
1011+
"https://example.com/$buildDir/assets/import.versioned.js" => [
1012+
'rel="modulepreload"',
1013+
],
1014+
], ViteFacade::preloadedAssets());
1015+
1016+
$this->cleanViteManifest($buildDir);
1017+
}
1018+
8681019
public function testPreloadAssetsGetAssetNonce()
8691020
{
8701021
$buildDir = Str::random();

0 commit comments

Comments
 (0)