Skip to content

Commit d453d19

Browse files
committed
Adds header for preloading Tailwind assets
1 parent 08f2f66 commit d453d19

File tree

7 files changed

+138
-4
lines changed

7 files changed

+138
-4
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Tonysm\TailwindCss\Http\Middleware;
4+
5+
use Tonysm\TailwindCss\Manifest;
6+
7+
class AddLinkHeaderForPreloadedAssets
8+
{
9+
public function __construct(private Manifest $manifest)
10+
{
11+
}
12+
13+
public function handle($request, $next)
14+
{
15+
return tap($next($request), function ($response) {
16+
if (count($assets = $this->manifest->assetsForPreloading()) > 0) {
17+
$response->header('Link', trim(implode(', ', array_filter([
18+
$response->headers->get('Link', null),
19+
...collect($assets)
20+
->map(fn ($attributes, $asset) => implode('; ', [
21+
"<$asset>",
22+
...collect(array_merge(['rel' => 'preload', 'as' => 'style'], $attributes))
23+
->map(fn ($value, $key) => "{$key}={$value}")
24+
->all(),
25+
]))
26+
->all(),
27+
]))));
28+
}
29+
});
30+
}
31+
}

src/Manifest.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
class Manifest
1010
{
11+
protected array $preloading = [];
12+
13+
public function assetsForPreloading(): array
14+
{
15+
return $this->preloading;
16+
}
17+
1118
public static function filename(): string
1219
{
1320
return basename(self::path());
@@ -18,7 +25,7 @@ public static function path(): string
1825
return config('tailwindcss.build.manifest_file_path');
1926
}
2027

21-
public function __invoke(string $path)
28+
public function __invoke(string $path, $preload = true)
2229
{
2330
static $manifests = [];
2431

@@ -50,6 +57,12 @@ public function __invoke(string $path)
5057
}
5158
}
5259

53-
return new HtmlString(asset($manifest[$path]));
60+
$asset = asset($manifest[$path]);
61+
62+
if ($preload) {
63+
$this->preloading[$asset] = is_array($preload) ? $preload : [];
64+
}
65+
66+
return new HtmlString($asset);
5467
}
5568
}

src/TailwindCssServiceProvider.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ public function configurePackage(Package $package): void
2424
Commands\WatchCommand::class,
2525
]);
2626
}
27+
28+
public function packageRegistered()
29+
{
30+
$this->app->scoped(Manifest::class);
31+
}
2732
}

src/helpers.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
* Get the path to a versioned TailwindCSS file.
99
*
1010
* @param string $path
11+
* @param bool|array $preload
1112
* @return \Illuminate\Support\HtmlString|string
1213
*/
13-
function tailwindcss(string $path): HtmlString|string
14+
function tailwindcss(string $path, $preload = true): HtmlString|string
1415
{
15-
return app(Manifest::class)($path);
16+
return app(Manifest::class)($path, $preload);
1617
}
1718
}

tests/PreloadingHeaderTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
namespace Tonysm\TailwindCss\Tests;
4+
5+
use Illuminate\Http\Request;
6+
use Tonysm\TailwindCss\Http\Middleware\AddLinkHeaderForPreloadedAssets;
7+
8+
class PreloadingHeaderTest extends TestCase
9+
{
10+
/** @test */
11+
public function no_link_header_when_not_preloading()
12+
{
13+
config()->set('tailwindcss.build.manifest_file_path', __DIR__.'/stubs/test-manifest.json');
14+
15+
$tailwindcss = tailwindcss('css/app.css', preload: false);
16+
17+
$response = resolve(AddLinkHeaderForPreloadedAssets::class)->handle(
18+
Request::create('/'),
19+
fn () => response('hello world'),
20+
);
21+
22+
$this->assertEquals('http://localhost/css/app-123.css', (string) $tailwindcss);
23+
$this->assertEquals('hello world', $response->content());
24+
$this->assertNull($response->headers->get('Link', null));
25+
}
26+
27+
/** @test */
28+
public function adds_link_header_when_preloading()
29+
{
30+
config()->set('tailwindcss.build.manifest_file_path', __DIR__.'/stubs/test-manifest.json');
31+
32+
$tailwindcss = tailwindcss('css/app.css', preload: true);
33+
34+
$response = resolve(AddLinkHeaderForPreloadedAssets::class)->handle(
35+
Request::create('/'),
36+
fn () => response('hello world'),
37+
);
38+
39+
$this->assertEquals($asset = 'http://localhost/css/app-123.css', (string) $tailwindcss);
40+
$this->assertEquals('hello world', $response->content());
41+
$this->assertEquals("<{$asset}>; rel=preload; as=style", $response->headers->get('Link', null));
42+
}
43+
44+
/** @test */
45+
public function keeps_existing_preloading_link_header()
46+
{
47+
config()->set('tailwindcss.build.manifest_file_path', __DIR__.'/stubs/test-manifest.json');
48+
49+
$tailwindcss = tailwindcss('css/app.css', preload: true);
50+
51+
$response = resolve(AddLinkHeaderForPreloadedAssets::class)->handle(
52+
Request::create('/'),
53+
fn () => response('hello world')->withHeaders([
54+
'Link' => '</js/app.js>; rel=modulepreload'
55+
]),
56+
);
57+
58+
$this->assertEquals($asset = 'http://localhost/css/app-123.css', (string) $tailwindcss);
59+
$this->assertEquals('hello world', $response->content());
60+
$this->assertEquals("</js/app.js>; rel=modulepreload, <{$asset}>; rel=preload; as=style", $response->headers->get('Link', null));
61+
}
62+
63+
/** @test */
64+
public function adds_link_header_when_preloading_custom_attributes()
65+
{
66+
config()->set('tailwindcss.build.manifest_file_path', __DIR__.'/stubs/test-manifest.json');
67+
68+
$tailwindcss = tailwindcss('css/app.css', ['crossorigin' => 'anonymous']);
69+
70+
$response = resolve(AddLinkHeaderForPreloadedAssets::class)->handle(
71+
Request::create('/'),
72+
fn () => response('hello world'),
73+
);
74+
75+
$this->assertEquals($asset = 'http://localhost/css/app-123.css', (string) $tailwindcss);
76+
$this->assertEquals('hello world', $response->content());
77+
$this->assertEquals("<{$asset}>; rel=preload; as=style; crossorigin=anonymous", $response->headers->get('Link', null));
78+
}
79+
}

tests/TestCase.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ protected function getPackageProviders($app)
3333
public function getEnvironmentSetUp($app)
3434
{
3535
config()->set('database.default', 'testing');
36+
config()->set('app.url', 'http://localhost');
37+
config()->set('app.asset_url', 'http://localhost');
3638
}
3739
}

tests/stubs/test-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"/css/app.css": "/css/app-123.css"
3+
}

0 commit comments

Comments
 (0)