Add preload link headers for downstream Cloudflare early hints (#171)

Because it takes us at best several seconds to request information from a homeserver and then server-side render the page, the browser has to wait for the response before it can even try loading the necessary assets. With this change that facilitates early hints, the browser can preload all of the assets necessary before we are done generating the response and will be ready to go by the time we're all done on the server.

Fix https://github.com/matrix-org/matrix-public-archive/issues/32

Part of https://github.com/matrix-org/matrix-public-archive/issues/132

See https://developers.cloudflare.com/cache/about/early-hints/ for information on enabling in Cloudflare
This commit is contained in:
Eric Eastwood 2023-04-19 14:20:01 -05:00 committed by GitHub
parent 321c6a4f26
commit 17a39ab8db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 16 deletions

View File

@ -0,0 +1,29 @@
'use strict';
const assert = require('assert');
// Set some preload link headers which we can use with Cloudflare to turn into 103 early
// hints, https://developers.cloudflare.com/cache/about/early-hints/
//
// This will turn into a nice speed-up since the server side render can take some time
// while we fetch all the information from the homeserver and the page can have all of
// the assets loaded and ready to go by that time. This way there is no extra delay
// after the page gets served.
function setHeadersToPreloadAssets(res, pageOptions) {
assert(res);
assert(pageOptions);
const { styles, scripts } = pageOptions;
const styleLinks = styles.map((styleUrl) => {
return `<${styleUrl}>; rel=preload; as=style`;
});
const scriptLinks = scripts.map((scriptUrl) => {
return `<${scriptUrl}>; rel=preload; as=script`;
});
res.append('Link', [].concat(styleLinks, scriptLinks).join(', '));
}
module.exports = setHeadersToPreloadAssets;

View File

@ -8,6 +8,7 @@ const asyncHandler = require('../lib/express-async-handler');
const fetchPublicRooms = require('../lib/matrix-utils/fetch-public-rooms');
const renderHydrogenVmRenderScriptToPageHtml = require('../hydrogen-render/render-hydrogen-vm-render-script-to-page-html');
const setHeadersToPreloadAssets = require('../lib/set-headers-to-preload-assets');
const config = require('../lib/config');
const basePath = config.get('basePath');
@ -65,15 +66,16 @@ router.get(
const roomDirectoryStylesUrl = urlJoin(basePath, '/css/room-directory.css');
const jsBundleUrl = urlJoin(basePath, '/js/entry-client-room-directory.es.js');
const pageOptions = {
title: `Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl, roomDirectoryStylesUrl],
scripts: [jsBundleUrl],
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,
};
const pageHtml = await renderHydrogenVmRenderScriptToPageHtml({
pageOptions: {
title: `Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl, roomDirectoryStylesUrl],
scripts: [jsBundleUrl],
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,
},
pageOptions,
vmRenderScriptFilePath: path.resolve(
__dirname,
'../../shared/room-directory-vm-render-script.js'
@ -102,6 +104,8 @@ router.get(
},
});
setHeadersToPreloadAssets(res, pageOptions);
res.set('Content-Type', 'text/html');
res.send(pageHtml);
})

View File

@ -23,6 +23,7 @@ const timestampToEvent = require('../lib/matrix-utils/timestamp-to-event');
const { removeMe_fetchRoomCreateEventId } = require('../lib/matrix-utils/fetch-room-data');
const getMessagesResponseFromEventId = require('../lib/matrix-utils/get-messages-response-from-event-id');
const renderHydrogenVmRenderScriptToPageHtml = require('../hydrogen-render/render-hydrogen-vm-render-script-to-page-html');
const setHeadersToPreloadAssets = require('../lib/set-headers-to-preload-assets');
const MatrixPublicArchiveURLCreator = require('matrix-public-archive-shared/lib/url-creator');
const {
MS_LOOKUP,
@ -868,15 +869,16 @@ router.get(
const stylesUrl = urlJoin(basePath, '/css/styles.css');
const jsBundleUrl = urlJoin(basePath, '/js/entry-client-hydrogen.es.js');
const pageOptions = {
title: `${roomData.name} - Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl],
scripts: [jsBundleUrl],
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,
};
const pageHtml = await renderHydrogenVmRenderScriptToPageHtml({
pageOptions: {
title: `${roomData.name} - Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl],
scripts: [jsBundleUrl],
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,
},
pageOptions,
vmRenderScriptFilePath: path.resolve(__dirname, '../../shared/hydrogen-vm-render-script.js'),
vmRenderContext: {
toTimestamp,
@ -900,6 +902,8 @@ router.get(
},
});
setHeadersToPreloadAssets(res, pageOptions);
res.set('Content-Type', 'text/html');
res.send(pageHtml);
})