Fix preload link headers (#185)
Follow-up to https://github.com/matrix-org/matrix-public-archive/pull/171 and https://github.com/matrix-org/matrix-public-archive/pull/175 where they broke because we went from scripts to modules. Part of https://github.com/matrix-org/matrix-public-archive/issues/132 Before this PR, we were seeing these warning in the Chrome devtools console: ``` A preload for 'foo' is found, but is not used because the request credentials mode does not match. Consider taking a look at crossorigin attribute. ``` This is caused by a credentials mode mismatch between the `<script type="module">` tag and the `Link` header. A `<script type="module">` with no `crossorigin` attribute indicates a credentials mode of `omit` and a naive `Link: </foo-url>; rel=preload; as=script;` has a default credentials mode of `same-origin`, hence the mismatch and warning we're seeing. We could set the credentials mode to match using `Link: </foo-url>; rel=preload; as=script; omit` but there is an even better option! We can use the dedicated `Link: </foo-url>; rel=modulepreload` link type which not only downloads and puts the the file in the cache like a normal preload but the browser also knows it's a JavaScript module now and can parse/compile it so it's ready to go. --- Future consideration: Adding `nopush` to preload link headers. Many servers initiate an HTTP/2 Server Push when they encounter a preload link in HTTP header form otherwise. Do we want/care about that (or maybe we don't)? (mentioned in https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf#6f54) --- References for preload `Link` headers: - https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf#6f54 - https://html.spec.whatwg.org/multipage/links.html#link-type-preload - https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/#headers - https://developer.chrome.com/blog/modulepreload/#ok-so-why-doesnt-link-relpreload-work-for-modules
This commit is contained in:
parent
d3e35a5de1
commit
a3952f1d31
|
@ -18,12 +18,46 @@ function setHeadersToPreloadAssets(res, pageOptions) {
|
||||||
|
|
||||||
const { styles, preloadScripts } = getDependenciesForEntryPointName(pageOptions.entryPoint);
|
const { styles, preloadScripts } = getDependenciesForEntryPointName(pageOptions.entryPoint);
|
||||||
|
|
||||||
|
// XXX: Should we add `nopush` to the `Link` headers here? Many servers initiate an
|
||||||
|
// HTTP/2 Server Push when they encounter a preload link in HTTP header form
|
||||||
|
// otherwise. Do we want/care about that (or maybe we don't)? (mentioned in
|
||||||
|
// https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf#6f54)
|
||||||
|
|
||||||
const styleLinks = styles.map((styleUrl) => {
|
const styleLinks = styles.map((styleUrl) => {
|
||||||
return `<${styleUrl}>; rel=preload; as=style`;
|
return `<${styleUrl}>; rel=preload; as=style`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: We should preload fonts as well.
|
||||||
|
//
|
||||||
|
// We use `cors` because fonts are fetched with "CORS mode 'cors'" (see
|
||||||
|
// https://drafts.csswg.org/css-fonts/#font-fetching-requirements)
|
||||||
|
//
|
||||||
|
// TODO: Should this be `cors` or `crossorigin`?
|
||||||
|
// https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/#headers shows
|
||||||
|
// `crossorigin` but
|
||||||
|
// https://html.spec.whatwg.org/multipage/links.html#link-type-preload (the spec) says
|
||||||
|
// `cors` so I'm not sure.
|
||||||
|
//
|
||||||
|
// `Link: <font_to_load.woff2>; rel=preload; as=font; cors`
|
||||||
|
|
||||||
|
// We use `rel=modulepreload` instead of `rel=preload` for the JavaScript modules
|
||||||
|
// because it's a nice dedicated thing to handle ESM modules that not only downloads
|
||||||
|
// and puts it in the cache like a normal `rel=preload` but the browser also knows
|
||||||
|
// it's a JavaScript module now and can parse/compile it so it's ready to go.
|
||||||
|
//
|
||||||
|
// Also as a note: `<script type="module">` with no `crossorigin` attribute indicates
|
||||||
|
// a credentials mode of `omit` so you will run into CORS issues with a naive `Link:
|
||||||
|
// <thing_to_load.js>; rel=preload; as=script;` because it defaults to `same-origin` and there
|
||||||
|
// is a mismatch (see
|
||||||
|
// https://html.spec.whatwg.org/multipage/links.html#link-type-preload ->
|
||||||
|
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode). We could set the
|
||||||
|
// credentials mode to match using `rel=preload; as=script; omit` but then we lose the
|
||||||
|
// extra parse/compile step that `rel=modulepreload` gives.
|
||||||
|
//
|
||||||
|
// See https://developer.chrome.com/blog/modulepreload/#ok-so-why-doesnt-link-relpreload-work-for-modules
|
||||||
|
// Spec: https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload
|
||||||
const scriptLinks = preloadScripts.map((scriptUrl) => {
|
const scriptLinks = preloadScripts.map((scriptUrl) => {
|
||||||
return `<${scriptUrl}>; rel=preload; as=script`;
|
return `<${scriptUrl}>; rel=modulepreload`;
|
||||||
});
|
});
|
||||||
|
|
||||||
res.append('Link', [].concat(styleLinks, scriptLinks).join(', '));
|
res.append('Link', [].concat(styleLinks, scriptLinks).join(', '));
|
||||||
|
|
Loading…
Reference in New Issue