Preload fonts and images (#187)
Part of https://github.com/matrix-org/matrix-public-archive/issues/132
This commit is contained in:
parent
f0a11139cb
commit
e20a67d2ba
|
@ -30,6 +30,7 @@ function getEntryPoints() {
|
||||||
return _entryPoints;
|
return _entryPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-statements
|
||||||
function recurseManifestEntryName(entryName) {
|
function recurseManifestEntryName(entryName) {
|
||||||
const manifest = getManifest();
|
const manifest = getManifest();
|
||||||
const entry = manifest[entryName];
|
const entry = manifest[entryName];
|
||||||
|
@ -38,6 +39,9 @@ function recurseManifestEntryName(entryName) {
|
||||||
|
|
||||||
// css
|
// css
|
||||||
const styles = [];
|
const styles = [];
|
||||||
|
// assets
|
||||||
|
const fonts = [];
|
||||||
|
const images = [];
|
||||||
// imports
|
// imports
|
||||||
const scripts = [entryFilePath];
|
const scripts = [entryFilePath];
|
||||||
// imports, dynamicImports
|
// imports, dynamicImports
|
||||||
|
@ -50,11 +54,15 @@ function recurseManifestEntryName(entryName) {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
styles: moreStyles,
|
styles: moreStyles,
|
||||||
|
fonts: moreFonts,
|
||||||
|
images: moreImages,
|
||||||
scripts: moreScripts,
|
scripts: moreScripts,
|
||||||
preloadScripts: morePreloadScripts,
|
preloadScripts: morePreloadScripts,
|
||||||
} = recurseManifestEntryName(importName);
|
} = recurseManifestEntryName(importName);
|
||||||
|
|
||||||
styles.push(...moreStyles);
|
styles.push(...moreStyles);
|
||||||
|
fonts.push(...moreFonts);
|
||||||
|
images.push(...moreImages);
|
||||||
scripts.push(...moreScripts);
|
scripts.push(...moreScripts);
|
||||||
preloadScripts.push(...morePreloadScripts);
|
preloadScripts.push(...morePreloadScripts);
|
||||||
}
|
}
|
||||||
|
@ -65,11 +73,15 @@ function recurseManifestEntryName(entryName) {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
styles: moreStyles,
|
styles: moreStyles,
|
||||||
|
fonts: moreFonts,
|
||||||
|
images: moreImages,
|
||||||
scripts: moreScripts,
|
scripts: moreScripts,
|
||||||
preloadScripts: morePreloadScripts,
|
preloadScripts: morePreloadScripts,
|
||||||
} = recurseManifestEntryName(dynamicImportName);
|
} = recurseManifestEntryName(dynamicImportName);
|
||||||
|
|
||||||
styles.push(...moreStyles);
|
styles.push(...moreStyles);
|
||||||
|
fonts.push(...moreFonts);
|
||||||
|
images.push(...moreImages);
|
||||||
scripts.push(...moreScripts);
|
scripts.push(...moreScripts);
|
||||||
preloadScripts.push(...morePreloadScripts);
|
preloadScripts.push(...morePreloadScripts);
|
||||||
}
|
}
|
||||||
|
@ -78,9 +90,36 @@ function recurseManifestEntryName(entryName) {
|
||||||
styles.push(path.join('/', cssName));
|
styles.push(path.join('/', cssName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const assetName of entry.assets || []) {
|
||||||
|
const assetFileExtension = path.extname(assetName);
|
||||||
|
const assetFilePath = path.join('/', assetName);
|
||||||
|
|
||||||
|
if (
|
||||||
|
// We only care about preloading `.woff2` fonts since that is all of the major
|
||||||
|
// browsers support them.
|
||||||
|
['.woff2'].includes(assetFileExtension) &&
|
||||||
|
// We only care about a few variants that we will actually likely use on the page
|
||||||
|
// (this may need to change over time).
|
||||||
|
['-Regular-', '-Bold-', '-SemiBold-'].some((variant) => assetName.includes(variant))
|
||||||
|
) {
|
||||||
|
fonts.push(path.join('/', assetFilePath));
|
||||||
|
} else if (
|
||||||
|
// Preload a specific file we use on the room directory homepage
|
||||||
|
assetName.includes('matrix-lines-hero')
|
||||||
|
// We don't care about preloading *all* images at the moment because there are a
|
||||||
|
// lot that we just don't use even though they are bundled because they are
|
||||||
|
// referened in the CSS.
|
||||||
|
//['.jpg', '.png', '.svg'].includes(assetFileExtension)
|
||||||
|
) {
|
||||||
|
images.push(path.join('/', assetFilePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// css
|
// css
|
||||||
styles,
|
styles,
|
||||||
|
fonts,
|
||||||
|
images,
|
||||||
// imports
|
// imports
|
||||||
scripts,
|
scripts,
|
||||||
// dynamicImports
|
// dynamicImports
|
||||||
|
@ -103,11 +142,14 @@ function getDependenciesForEntryPointName(entryPointName) {
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const { styles, scripts, preloadScripts } = recurseManifestEntryName(entryPointName);
|
const { styles, fonts, images, scripts, preloadScripts } =
|
||||||
|
recurseManifestEntryName(entryPointName);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// De-duplicate assets
|
// De-duplicate assets
|
||||||
styles: Array.from(new Set(styles)),
|
styles: Array.from(new Set(styles)),
|
||||||
|
fonts: Array.from(new Set(fonts)),
|
||||||
|
images: Array.from(new Set(images)),
|
||||||
scripts: Array.from(new Set(scripts)),
|
scripts: Array.from(new Set(scripts)),
|
||||||
preloadScripts: Array.from(new Set(preloadScripts)),
|
preloadScripts: Array.from(new Set(preloadScripts)),
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,13 +16,17 @@ function setHeadersToPreloadAssets(res, pageOptions) {
|
||||||
assert(pageOptions);
|
assert(pageOptions);
|
||||||
assert(pageOptions.entryPoint);
|
assert(pageOptions.entryPoint);
|
||||||
|
|
||||||
const { styles, preloadScripts } = getDependenciesForEntryPointName(pageOptions.entryPoint);
|
const { styles, fonts, images, preloadScripts } = getDependenciesForEntryPointName(
|
||||||
|
pageOptions.entryPoint
|
||||||
|
);
|
||||||
|
|
||||||
|
// Work on assembling the `Link` headers
|
||||||
|
//
|
||||||
// Note: Any docs for the `<link>` element apply to the `Link` header. "The `Link`
|
// Note: Any docs for the `<link>` element apply to the `Link` header. "The `Link`
|
||||||
// header contains parameters [that] are equivalent to attributes of the `<link>`
|
// header contains parameters [that] are equivalent to attributes of the `<link>`
|
||||||
// element."
|
// element."
|
||||||
// (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link#parameters)
|
// (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link#parameters)
|
||||||
|
//
|
||||||
// XXX: Should we add `nopush` to the `Link` headers here? Many servers initiate an
|
// 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
|
// 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
|
// otherwise. Do we want/care about that (or maybe we don't)? (mentioned in
|
||||||
|
@ -32,16 +36,19 @@ function setHeadersToPreloadAssets(res, pageOptions) {
|
||||||
return `<${styleUrl}>; rel=preload; as=style`;
|
return `<${styleUrl}>; rel=preload; as=style`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: We should preload fonts as well.
|
|
||||||
//
|
|
||||||
// We use `crossorigin` because fonts are fetched with anonymous mode "cors" and
|
// We use `crossorigin` because fonts are fetched with anonymous mode "cors" and
|
||||||
// "same-origin" credentials mode (see
|
// "same-origin" credentials mode (see
|
||||||
// https://drafts.csswg.org/css-fonts/#font-fetching-requirements). `crossorigin` is
|
// https://drafts.csswg.org/css-fonts/#font-fetching-requirements). `crossorigin` is
|
||||||
// just short-hand for `crossorigin=anonymous` (see
|
// just short-hand for `crossorigin=anonymous` (see
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin and
|
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin and
|
||||||
// https://html.spec.whatwg.org/multipage/infrastructure.html#cors-settings-attribute).
|
// https://html.spec.whatwg.org/multipage/infrastructure.html#cors-settings-attribute).
|
||||||
//
|
const fontLinks = fonts.map((fontUrl) => {
|
||||||
// `Link: <font_to_load.woff2>; rel=preload; as=font; crossorigin`
|
return `<${fontUrl}>; rel=preload; as=font; crossorigin`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const imageLinks = images.map((imageUrl) => {
|
||||||
|
return `<${imageUrl}>; rel=preload; as=image`;
|
||||||
|
});
|
||||||
|
|
||||||
// We use `rel=modulepreload` instead of `rel=preload` for the JavaScript modules
|
// 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
|
// because it's a nice dedicated thing to handle ESM modules that not only downloads
|
||||||
|
@ -63,7 +70,7 @@ function setHeadersToPreloadAssets(res, pageOptions) {
|
||||||
return `<${scriptUrl}>; rel=modulepreload`;
|
return `<${scriptUrl}>; rel=modulepreload`;
|
||||||
});
|
});
|
||||||
|
|
||||||
res.append('Link', [].concat(styleLinks, scriptLinks).join(', '));
|
res.append('Link', [].concat(styleLinks, fontLinks, imageLinks, scriptLinks).join(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = setHeadersToPreloadAssets;
|
module.exports = setHeadersToPreloadAssets;
|
||||||
|
|
Loading…
Reference in New Issue