Open tristanbes opened 5 years ago
Hey @tristanbes!
Sorry for getting back slowly. Thank you for this! I was implementing this feature as a non-expert on this stuff, and was indeed lacking feedback from people that know more than I do. Let me reply a bit out of order:
4) The prefetch strategy is missing and can't be handled globally or per entries
I purposely left this completely unimplemented, because it's a but more complex. As you correctly said:
if you know that a visitor is likely to visit page B after visiting page A, it would be interesting to apply either the prefetch strategy
I haven't given this much thought. I think your idea makes perfect sense... but it also might make sense to do this entirely in the controller - e.g. have some service where you can basically say "Hey! prefetch all the assets from entryB
". I'm honestly not sure which is the more "proper" place. So, indeed, maybe we add it both places.
1) Because it can hurt web performance to push large assets using the link header
Can you tell me more about your understanding of this. Again, my expertise here is low, which is why O created the original PR (PR's push conversation... but in this case, I got no "push back", which is why it was merged as-is"). My initial impression had been that preloading all the assets was basically a way to tell the browser, just a little bit earlier (before parsing and finding them in the HTML) that it should start downloading those assets. However, the:
it will likely prevent the browser from scheduling everything smartly
part makes me pretty sure that I'm missing the point on something.
- Because it's not flexible enough, sometimes you just want to preload the resource and not push it (which require http2) with the nopush attribute
If you were trying to give some recommendations to someone that's not too familiar with all this stuff, when would you recommend "wanting" a push versus a nopush? There are kind of two goals with this feature: (a) to make it technically possible to add all the preload, nopush, etc attributes and (b) to create a framework so that users (who may not be experts on these new features) can make "reasonably good" decisions. Just adding some ability to add nopush
accomplishes the first, but not the second.
- The key is confusing, preload is not true when you have HTTP2 protocol. It will push the asset to the client and not preload it. Only if you're stuck in HTTP1.1 protocol, it will "only" preload it.
Hmm, this is interesting. So for example,
Link: rel=preload; </app/script.js>; as=script;
This same header will behave differently based on if the server supports HTTP2 or not? It will either preload or push, which, are two different things and should probably be used in two different situations? If so, that's a very complex thing to try to get right. It makes me think that nopush
should be the "default" way this behaves:
Link: rel=preload; </app/script.js>; as=script; nopush
(this would "preload" but not push, in all cases, right?) and then have the user specifically opt into push because they know they want it and can support it.
In general, your proposal (2) makes sense to me... I think :). It leaves me with a few other questions:
A) Will users sometimes want different preload, prefetch behavior on CSS vs script tags?
B) What about fonts & images embedded in CSS? Those are currently not preloaded
C) If it is as simple as "here's the behavior I want for all assets for a specific entry point" (this is my question A), should the configuration for this belong in YAML (like your proposal)? In Twig when rendering the assets? Or even in Encore (webpack.config.js
) when setting up your assets (i.e. addEntry()
)?
Thanks for your time!
My turn to apologize, I took some days off :)
If you were trying to give some recommendations to someone that's not too familiar with all this stuff, when would you recommend "wanting" a push versus a nopush?
Instead of inlining elements in your HTML (such as small CSS or JavaScript) separate them into their own files and Push them to the browser instead. This allows you to better leverage browser caching. Push is also great for utilizing think time in a more efficient manner. As a server generates a website’s HTML file no further requests can be made by the browser as it must wait until the HTML file is received before knowing what to request next. However, depending on your server’s think time you can use it to your advantage by pushing necessary resources to the browser along with the HTML file, once generated.
Loading critical CSS that is discovered late Loading above-the-fold images referenced within a CSS file Loading fonts references within a CSS file
Only resources served from your domain can be pushed, while you can preload resources from any domains.
Preloaded resources goes inside a memory cache, that is only for the current page/browser tab Pushed resources goes inside a push cache that is linked to an HTTP/2 connection which is purged when the connection is terminated. Since an HTTP/2 connection can be re-used across multiple tabs (not true for all browsers), the resources from this cache can be used across browser tabs.
This same header will behave differently based on if the server supports HTTP2 or not?
My current understanding of this is yes, it will behave differently. It depends of wether the webserver or CDN supports push or not. If it supports it, it'll push the asset, if not, it'll tell the browser to preload it.
It will either preload or push, which, are two different things and should probably be used in two different situations?
Yes, it'll either preload or push them depending of the capability of the server/CDN.
If you server does not support push, then you would use preload
instead of push. In this case, there is less difference and potential negative impact using this strategy than when you have to choose when to preload and when to push when you server support push.
It makes me think that nopush should be the "default" way this behaves
I'm not sure about this, but I have no points in favor or against it.
A) Will users sometimes want different preload, prefetch behavior on CSS vs script tags ?
I'm not sure I understand the question, can you elaborate please ?
B) What about fonts & images embedded in CSS? Those are currently not preloaded
The current "best practice" of this is to preload webfonts/images that are referenced inside external CSS because they are discovered "late" by the browser;
C) If it is as simple as "here's the behavior I want for all assets for a specific entry point" (this is my question A), should the configuration for this belong in YAML (like your proposal)? In Twig when rendering the assets? Or even in Encore (webpack.config.js) when setting up your assets (i.e. addEntry())?
I think it should be either in a .yaml
configuration, or inside the .addEntry()
method.
I also think we need a way to override this configuration when you call {{ encore_entry_script_tags() }}
with extra parameters.
Note that the prefetch
strategy can't be handled via those methods, it needs to be handled when calling it on the twig template: {{ encore_entry_script_tags('entry.a', { strategy: 'prefetch' }) }}
that will output
<link rel="prefetch" href="https://example.com/dist/runtime.js">
<link rel="prefetch" href="https://example.com/dist/app.0.js">
<link rel="prefetch" href="https://example.com/dist/app.1.js">
Note that today, it's not working, nothing is outputed in the HTML like reported on my issue.
To conclude, those problematics are complex to apply (like any fine-tuning), so a global config or preset to cover most cases, in my point of view, is very difficult to implement.
Hello,
I have multiple concerns reguarding the
preload
feature that has been introduced in a recent PRThis option adds all the resources included with the
{{ encore_* }}
tag in the responselink
header in order to preload the resources.One thing that bugs me is that it's very aggressive approach to tell the application: "Ok let's push ALL the resources from the application"
Why it bugs me ?
1/ Because it can hurt web performance to push large assets using the link header. ⚠️ It would be fair to add this warning when documenting this option.
2/ Because it's not flexible enough, sometimes you just want to preload the resource and not push it (which require http2) with the
nopush
attribute.3/ The key is confusing,
preload
is not true when you have HTTP2 protocol. It will push the asset to the client and not preload it. Only if you're stuck in HTTP1.1 protocol, it will "only" preload it.4/ The
prefetch
strategy is missing and can't be handled globally or per entries. It should be used per "usage" or per "call" if you prefer.Suggestions
1/ 👎 Tweak the global configuration
preload: true
to add a way to not push it.Will translate to:
</build/runtime.fa8f03f5.js>; rel="preload"; as="script"; nopush
in thelink
header2/ 👍 I think a better approach would be defining a strategy by entries:
However this configuration would not solve point number 4/
For example, if you know that a visitor is likely to visit page B after visiting page A, it would be interesting to apply either the
prefetch
strategy, (or theprerender
strategy but that's covered in the WebLink component).On page A you would for example use
If those strategy is used, nothing will be outputted in the DOM. Instead, in the response header, you'll have under the key
link
entry:--
I'll tag @weaverryan because I saw that you needed feedback on this subject (for example here: https://github.com/symfony/webpack-encore-bundle/issues/14)
Thanks.