Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.x] Vite: ability to prevent preload tag generation from attribute resolver callback #45283

Merged
merged 3 commits into from Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 18 additions & 10 deletions src/Illuminate/Foundation/Vite.php
Expand Up @@ -233,7 +233,7 @@ public function useStyleTagAttributes($attributes)
/**
* Use the given callback to resolve attributes for preload tags.
*
* @param (callable(string, string, ?array, ?array): array)|array $attributes
* @param (callable(string, string, ?array, ?array): array|false)|array|false $attributes
* @return $this
*/
public function usePreloadTagAttributes($attributes)
Expand Down Expand Up @@ -351,8 +351,8 @@ public function __invoke($entrypoints, $buildDirectory = null)
*
* @param string $src
* @param string $url
* @param ?array $chunk
* @param ?array $manifest
* @param array|null $chunk
* @param array|null $manifest
* @return string
*/
protected function makeTagForChunk($src, $url, $chunk, $manifest)
Expand Down Expand Up @@ -386,12 +386,16 @@ protected function makeTagForChunk($src, $url, $chunk, $manifest)
* @param string $url
* @param array $chunk
* @param array $manifest
* @return string|null
* @return string
*/
protected function makePreloadTagForChunk($src, $url, $chunk, $manifest)
{
$attributes = $this->resolvePreloadTagAttributes($src, $url, $chunk, $manifest);

if ($attributes === false) {
return '';
}

$this->preloadedAssets[$url] = $this->parseAttributes(
Collection::make($attributes)->forget('href')->all()
);
Expand All @@ -404,8 +408,8 @@ protected function makePreloadTagForChunk($src, $url, $chunk, $manifest)
*
* @param string $src
* @param string $url
* @param ?array $chunk
* @param ?array $manifest
* @param array|null $chunk
* @param array|null $manifest
* @return array
*/
protected function resolveScriptTagAttributes($src, $url, $chunk, $manifest)
Expand All @@ -426,8 +430,8 @@ protected function resolveScriptTagAttributes($src, $url, $chunk, $manifest)
*
* @param string $src
* @param string $url
* @param ?array $chunk
* @param ?array $manifest
* @param array|null $chunk
* @param array|null $manifest
* @return array
*/
protected function resolveStylesheetTagAttributes($src, $url, $chunk, $manifest)
Expand All @@ -450,7 +454,7 @@ protected function resolveStylesheetTagAttributes($src, $url, $chunk, $manifest)
* @param string $url
* @param array $chunk
* @param array $manifest
* @return array
* @return array|false
*/
protected function resolvePreloadTagAttributes($src, $url, $chunk, $manifest)
{
Expand All @@ -472,7 +476,11 @@ protected function resolvePreloadTagAttributes($src, $url, $chunk, $manifest)
: $attributes;

foreach ($this->preloadTagAttributesResolvers as $resolver) {
$attributes = array_merge($attributes, $resolver($src, $url, $chunk, $manifest));
if (false === ($resolvedAttributes = $resolver($src, $url, $chunk, $manifest))) {
return false;
}

$attributes = array_merge($attributes, $resolvedAttributes);
}

return $attributes;
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Support/Facades/Vite.php
Expand Up @@ -14,7 +14,7 @@
* @method static \Illuminate\Foundation\Vite useBuildDirectory(string $path)
* @method static \Illuminate\Foundation\Vite useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
* @method static \Illuminate\Foundation\Vite useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
* @method static \Illuminate\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes)
* @method static \Illuminate\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array|false)|array|false $attributes)
* @method static \Illuminate\Support\HtmlString|void reactRefresh()
* @method static string asset(string $asset, string|null $buildDirectory = null)
* @method static string|null manifestHash(string|null $buildDirectory = null)
Expand Down
151 changes: 151 additions & 0 deletions tests/Foundation/FoundationViteTest.php
Expand Up @@ -865,6 +865,157 @@ public function testItCanSpecifyAttributesForPreloadedAssets()
$this->cleanViteManifest($buildDir);
}

public function testItCanSuppressPreloadTagGeneration()
{
$buildDir = Str::random();
$this->makeViteManifest([
'resources/js/app.js' => [
'src' => 'resources/js/app.js',
'file' => 'assets/app.versioned.js',
'imports' => [
'import.js',
'import-nopreload.js',
],
'css' => [
'assets/app.versioned.css',
'assets/app-nopreload.versioned.css',
],
],
'resources/js/app-nopreload.js' => [
'src' => 'resources/js/app-nopreload.js',
'file' => 'assets/app-nopreload.versioned.js',
],
'import.js' => [
'file' => 'assets/import.versioned.js',
],
'import-nopreload.js' => [
'file' => 'assets/import-nopreload.versioned.js',
],
'resources/css/app.css' => [
'src' => 'resources/css/app.css',
'file' => 'assets/app.versioned.css',
],
'resources/css/app-nopreload.css' => [
'src' => 'resources/css/app-nopreload.css',
'file' => 'assets/app-nopreload.versioned.css',
],
], $buildDir);
ViteFacade::usePreloadTagAttributes(function ($src, $url, $chunk, $manifest) use ($buildDir) {
$this->assertSame([
'resources/js/app.js' => [
'src' => 'resources/js/app.js',
'file' => 'assets/app.versioned.js',
'imports' => [
'import.js',
'import-nopreload.js',
],
'css' => [
'assets/app.versioned.css',
'assets/app-nopreload.versioned.css',
],
],
'resources/js/app-nopreload.js' => [
'src' => 'resources/js/app-nopreload.js',
'file' => 'assets/app-nopreload.versioned.js',
],
'import.js' => [
'file' => 'assets/import.versioned.js',
],
'import-nopreload.js' => [
'file' => 'assets/import-nopreload.versioned.js',
],
'resources/css/app.css' => [
'src' => 'resources/css/app.css',
'file' => 'assets/app.versioned.css',
],
'resources/css/app-nopreload.css' => [
'src' => 'resources/css/app-nopreload.css',
'file' => 'assets/app-nopreload.versioned.css',
],
], $manifest);

(match ($src) {
'resources/js/app.js' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/app.versioned.js", $url);
$this->assertSame([
'src' => 'resources/js/app.js',
'file' => 'assets/app.versioned.js',
'imports' => [
'import.js',
'import-nopreload.js',
],
'css' => [
'assets/app.versioned.css',
'assets/app-nopreload.versioned.css',
],
], $chunk);
},
'resources/js/app-nopreload.js' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/app-nopreload.versioned.js", $url);
$this->assertSame([
'src' => 'resources/js/app-nopreload.js',
'file' => 'assets/app-nopreload.versioned.js',
], $chunk);
},
'import.js' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/import.versioned.js", $url);
$this->assertSame([
'file' => 'assets/import.versioned.js',
], $chunk);
},
'import-nopreload.js' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/import-nopreload.versioned.js", $url);
$this->assertSame([
'file' => 'assets/import-nopreload.versioned.js',
], $chunk);
},
'resources/css/app.css' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/app.versioned.css", $url);
$this->assertSame([
'src' => 'resources/css/app.css',
'file' => 'assets/app.versioned.css',
], $chunk);
},
'resources/css/app-nopreload.css' => function () use ($url, $chunk, $buildDir) {
$this->assertSame("https://example.com/{$buildDir}/assets/app-nopreload.versioned.css", $url);
$this->assertSame([
'src' => 'resources/css/app-nopreload.css',
'file' => 'assets/app-nopreload.versioned.css',
], $chunk);
},
})();

return Str::contains($src, '-nopreload') ? false : [];
});

$result = app(Vite::class)(['resources/js/app.js', 'resources/js/app-nopreload.js'], $buildDir);

$this->assertSame(
'<link rel="preload" as="style" href="https://example.com/'.$buildDir.'/assets/app.versioned.css" />'
.'<link rel="modulepreload" href="https://example.com/'.$buildDir.'/assets/app.versioned.js" />'
.'<link rel="modulepreload" href="https://example.com/'.$buildDir.'/assets/import.versioned.js" />'
.'<link rel="stylesheet" href="https://example.com/'.$buildDir.'/assets/app.versioned.css" />'
.'<link rel="stylesheet" href="https://example.com/'.$buildDir.'/assets/app-nopreload.versioned.css" />'
.'<script type="module" src="https://example.com/'.$buildDir.'/assets/app.versioned.js"></script>'
.'<script type="module" src="https://example.com/'.$buildDir.'/assets/app-nopreload.versioned.js"></script>',
$result->toHtml());

$this->assertSame([
"https://example.com/$buildDir/assets/app.versioned.css" => [
'rel="preload"',
'as="style"',
],
"https://example.com/$buildDir/assets/app.versioned.js" => [
'rel="modulepreload"',
],
"https://example.com/$buildDir/assets/import.versioned.js" => [
'rel="modulepreload"',
],
], ViteFacade::preloadedAssets());

$this->cleanViteManifest($buildDir);
}

public function testPreloadAssetsGetAssetNonce()
{
$buildDir = Str::random();
Expand Down