Preload fonts and images (#187)

Part of https://github.com/matrix-org/matrix-public-archive/issues/132
This commit is contained in:
Eric Eastwood 2023-04-26 16:35:00 -05:00 committed by GitHub
parent f0a11139cb
commit e20a67d2ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 8 deletions

View File

@ -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)),
}; };

View File

@ -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;