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

[AssetMapper] Automatically preload CSS files if WebLink available #51829

Merged
merged 1 commit into from Oct 11, 2023

Conversation

weaverryan
Copy link
Member

Q A
Branch? 6.4
Bug fix? no
New feature? yes
Deprecations? no
Tickets None
License MIT

Hi!

In AssetMapper 6.4, we now know which CSS files will be rendered on the page. So, I think there is now downside to adding a Link header in the response to load those CSS files, but someone tell me if I'm missing something.

The only possible situation I can think of where this isn't wanted is if you decided to handle your critical CSS manually (i.e. with normal <link rel="stylesheet"> tags in base.html.twig) and load a few less-critical CSS files through the ImportMap system. In that case, we would preload only these "less-critical" CSS, which could take a slight priority over the others. But I think the benefit this would give to most apps outweighs this. We could always add an opt-out later.

Cheers!

@smnandre
Copy link
Contributor

smnandre commented Oct 4, 2023

The only problem would be: Google Pagespeed and other performances tests/tools rate really bad if you preload a CSS you do not use "quickly"

Modern browsers are already pretty good at prioritizing resources, that's why it's important to use preload sparingly and only preload the most critical resources.

https://web.dev/preload-critical-assets/#how-preloading-works

@weaverryan
Copy link
Member Author

The only problem would be: Google Pagespeed and other performances tests/tools rate really bad if you preload a CSS you do not use "quickly"

But if we KNOW that what we are preloading WILL be <link rel="stylesheet"> inside the initial HTML, then we would be good, right?

@smnandre
Copy link
Contributor

smnandre commented Oct 4, 2023

The only problem would be: Google Pagespeed and other performances tests/tools rate really bad if you preload a CSS you do not use "quickly"

But if we KNOW that what we are preloading WILL be <link rel="stylesheet"> inside the initial HTML, then we would be good, right?

I'll really need to try it "in the wild" (ux.symfony.com ? 👼) to be 100% sure... but i'd say "yes" :)

And anyone so obsessed with performances still can call manually the stylesheets so i'm not worried :)

@weaverryan weaverryan added the ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" label Oct 6, 2023
@weaverryan weaverryan force-pushed the asset-mapper-css-preload-weblink branch from edcc1e9 to 6a9d1ff Compare October 6, 2023 17:22
@@ -27,6 +33,7 @@ public function __construct(
private readonly string $charset = 'UTF-8',
private readonly string|false $polyfillUrl = ImportMapManager::POLYFILL_URL,
private readonly array $scriptAttributes = [],
private readonly ?RequestStack $requestStack = null,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Injecting the request stack here feels a bit odd, but it's the best way I can think of to handle this.

@@ -68,6 +75,10 @@ public function render(string|array $entryPoint, array $attributes = []): string
$output .= "\n<link rel=\"stylesheet\" href=\"$url\">";
}

if (class_exists(AddLinkHeaderListener::class) && $request = $this->requestStack?->getCurrentRequest()) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same logic as in AbstractController

@weaverryan
Copy link
Member Author

high-deps for asset mapper failing because 6.4 hasn't been merged up to 7.0, so FWBundle & AssetMapper tests are using not-yet-up-to-date code.

@weaverryan weaverryan force-pushed the asset-mapper-css-preload-weblink branch from 6a9d1ff to f17ce5b Compare October 11, 2023 00:05
@fabpot fabpot force-pushed the asset-mapper-css-preload-weblink branch from 9e80fbb to 2995c16 Compare October 11, 2023 10:50
@fabpot
Copy link
Member

fabpot commented Oct 11, 2023

Thank you @weaverryan.

@fabpot fabpot merged commit f3a09b9 into symfony:6.4 Oct 11, 2023
3 of 9 checks passed
@weaverryan weaverryan deleted the asset-mapper-css-preload-weblink branch October 11, 2023 10:52

private function addWebLinkPreloads(Request $request, array $cssLinks): void
{
$cssPreloadLinks = array_map(fn ($url) => new Link('preload', $url), $cssLinks);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, but shouldn't the nopush attribute be better set here? So that the css files are not sent again and again, even if they are already in client cache.

From https://developer.chrome.com/blog/early-hints/:

with HTTP2/Push it was extremely hard to avoid pushing sub-resources that the browser already had. This "over-pushing" effect resulted in a less efficient usage of the network bandwidth, which significantly hindered the performance benefits.

In current Chrome versions it wouldn't make any difference, because Server Push is already disabled there. But afaik other browsers still support Server Push in current versions.

- $cssPreloadLinks = array_map(fn ($url) => new Link('preload', $url), $cssLinks);
+ $cssPreloadLinks = array_map(fn ($url) => (new Link('preload', $url))->withAttribute('nopush', true), $cssLinks);

@smnandre
Copy link
Contributor

Not sure who implemented "nopush" but it seems not to be considered by most used browsers

https://wpt.fyi/results/preload?label=master&label=experimental&aligned&q=nopush

(compared to https://wpt.fyi/results/preload?label=master&label=experimental&aligned&q=preload` )

@gharlan
Copy link
Contributor

gharlan commented Oct 17, 2023

Not sure who implemented "nopush" but it seems not to be considered by most used browsers

I think the browsers do not need to implement "nopush". It is the server (apache, nginx, ...) that decides based on the nopush attribute whether to push the resource or just send the preload header.

@weaverryan
Copy link
Member Author

See #52143 - thanks for bringing up this possible issue

This was referenced Oct 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AssetMapper Feature ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" Status: Reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants