Increase perceived performance by scrolling to the right spot before Hydrogen loads (#128)
This commit is contained in:
parent
3671da0405
commit
fa4720af04
|
@ -16,9 +16,7 @@ const vm = require('vm');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { readFile } = require('fs').promises;
|
const { readFile } = require('fs').promises;
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
const { parseHTML } = require('linkedom');
|
const { parseHTML } = require('linkedom');
|
||||||
const safeJson = require('../lib/safe-json');
|
|
||||||
|
|
||||||
// Setup the DOM context with any necessary shims/polyfills and ensure the VM
|
// Setup the DOM context with any necessary shims/polyfills and ensure the VM
|
||||||
// context global has everything that a normal document does so Hydrogen can
|
// context global has everything that a normal document does so Hydrogen can
|
||||||
|
@ -67,24 +65,36 @@ async function _renderHydrogenToStringUnsafe(renderOptions) {
|
||||||
assert(renderOptions.vmRenderScriptFilePath);
|
assert(renderOptions.vmRenderScriptFilePath);
|
||||||
assert(renderOptions.vmRenderContext);
|
assert(renderOptions.vmRenderContext);
|
||||||
assert(renderOptions.pageOptions);
|
assert(renderOptions.pageOptions);
|
||||||
|
assert(renderOptions.pageOptions.locationHref);
|
||||||
assert(renderOptions.pageOptions.cspNonce);
|
assert(renderOptions.pageOptions.cspNonce);
|
||||||
|
|
||||||
const { dom, vmContext } = createDomAndSetupVmContext();
|
const { dom, vmContext } = createDomAndSetupVmContext();
|
||||||
|
|
||||||
|
// A small `window.location` stub
|
||||||
|
if (!dom.window.location) {
|
||||||
|
const locationUrl = new URL(renderOptions.pageOptions.locationHref);
|
||||||
|
dom.window.location = {};
|
||||||
|
[
|
||||||
|
'hash',
|
||||||
|
'host',
|
||||||
|
'hostname',
|
||||||
|
'href',
|
||||||
|
'origin',
|
||||||
|
'password',
|
||||||
|
'pathname',
|
||||||
|
'port',
|
||||||
|
'protocol',
|
||||||
|
'search',
|
||||||
|
'username',
|
||||||
|
].forEach((key) => {
|
||||||
|
dom.window.location[key] = locationUrl[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Define this for the SSR context
|
// Define this for the SSR context
|
||||||
dom.window.matrixPublicArchiveContext = {
|
dom.window.matrixPublicArchiveContext = {
|
||||||
...renderOptions.vmRenderContext,
|
...renderOptions.vmRenderContext,
|
||||||
};
|
};
|
||||||
// Serialize it for when we run this again client-side
|
|
||||||
const serializedContext = JSON.stringify(dom.window.matrixPublicArchiveContext);
|
|
||||||
dom.document.body.insertAdjacentHTML(
|
|
||||||
'beforeend',
|
|
||||||
`
|
|
||||||
<script type="text/javascript" nonce="${renderOptions.pageOptions.cspNonce}">
|
|
||||||
window.matrixPublicArchiveContext = ${safeJson(serializedContext)}
|
|
||||||
</script>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
const vmRenderScriptFilePath = renderOptions.vmRenderScriptFilePath;
|
const vmRenderScriptFilePath = renderOptions.vmRenderScriptFilePath;
|
||||||
const hydrogenRenderScriptCode = await readFile(vmRenderScriptFilePath, 'utf8');
|
const hydrogenRenderScriptCode = await readFile(vmRenderScriptFilePath, 'utf8');
|
||||||
|
|
|
@ -26,6 +26,12 @@ async function renderHydrogenVmRenderScriptToPageHtml(
|
||||||
pageOptions,
|
pageOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Serialize the state for when we run the Hydrogen render again client-side to
|
||||||
|
// re-hydrate the DOM
|
||||||
|
const serializedMatrixPublicArchiveContext = JSON.stringify({
|
||||||
|
...vmRenderContext,
|
||||||
|
});
|
||||||
|
|
||||||
const serializableSpans = getSerializableSpans();
|
const serializableSpans = getSerializableSpans();
|
||||||
const serializedSpans = JSON.stringify(serializableSpans);
|
const serializedSpans = JSON.stringify(serializableSpans);
|
||||||
|
|
||||||
|
@ -51,6 +57,34 @@ async function renderHydrogenVmRenderScriptToPageHtml(
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
${hydrogenHtmlOutput}
|
${hydrogenHtmlOutput}
|
||||||
|
|
||||||
|
${
|
||||||
|
/**
|
||||||
|
* This inline snippet is used in to scroll the Hydrogen timeline to the
|
||||||
|
* right place immediately when the page loads instead of waiting for
|
||||||
|
* Hydrogen to load, hydrate and finally scroll.
|
||||||
|
*/ ''
|
||||||
|
}
|
||||||
|
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
|
||||||
|
const qs = new URLSearchParams(window?.location?.search);
|
||||||
|
const atEventId = qs.get('at');
|
||||||
|
if (atEventId) {
|
||||||
|
const el = document.querySelector(\`[data-event-id="\${atEventId}"]\`);
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
el && el.scrollIntoView({ block: 'center' });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const el = document.querySelector('.js-bottom-scroll-anchor');
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
el && el.scrollIntoView({ block: 'end' });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
|
||||||
|
window.matrixPublicArchiveContext = ${safeJson(serializedMatrixPublicArchiveContext)}
|
||||||
|
</script>
|
||||||
|
|
||||||
${pageOptions.scripts
|
${pageOptions.scripts
|
||||||
.map(
|
.map(
|
||||||
(scriptUrl) =>
|
(scriptUrl) =>
|
||||||
|
|
|
@ -93,6 +93,7 @@ router.get(
|
||||||
title: `Matrix Public Archive`,
|
title: `Matrix Public Archive`,
|
||||||
styles: [hydrogenStylesUrl, stylesUrl, roomDirectoryStylesUrl],
|
styles: [hydrogenStylesUrl, stylesUrl, roomDirectoryStylesUrl],
|
||||||
scripts: [jsBundleUrl],
|
scripts: [jsBundleUrl],
|
||||||
|
locationHref: urlJoin(basePath, req.originalUrl),
|
||||||
shouldIndex,
|
shouldIndex,
|
||||||
cspNonce: res.locals.cspNonce,
|
cspNonce: res.locals.cspNonce,
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,6 +420,7 @@ router.get(
|
||||||
title: `${roomData.name} - Matrix Public Archive`,
|
title: `${roomData.name} - Matrix Public Archive`,
|
||||||
styles: [hydrogenStylesUrl, stylesUrl],
|
styles: [hydrogenStylesUrl, stylesUrl],
|
||||||
scripts: [jsBundleUrl],
|
scripts: [jsBundleUrl],
|
||||||
|
locationHref: urlJoin(basePath, req.originalUrl),
|
||||||
shouldIndex,
|
shouldIndex,
|
||||||
cspNonce: res.locals.cspNonce,
|
cspNonce: res.locals.cspNonce,
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,12 @@ class JumpToNextActivitySummaryTileView extends TemplateView {
|
||||||
|
|
||||||
return t.div(
|
return t.div(
|
||||||
{
|
{
|
||||||
className: 'JumpToNextActivitySummaryTileView',
|
className: {
|
||||||
|
JumpToNextActivitySummaryTileView: true,
|
||||||
|
// Used by page loaded JavaScript to quickly jump the scroll viewport down
|
||||||
|
// while we wait for the rest of the JavaScript to load.
|
||||||
|
'js-bottom-scroll-anchor': true,
|
||||||
|
},
|
||||||
'data-event-id': vm.eventId,
|
'data-event-id': vm.eventId,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue