Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions dotcom-rendering/src/client/islands/getPriority.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Priority } from '../../lib/scheduler';
import { isValidSchedulerPriority } from '../../lib/scheduler';

/**
* getPriority takes the given html element and returns its priority attribute
*
* We expect the element to always be a `gu-*` custom element
*
* @param marker : The html element that we want to read the priority attribute from;
* @returns
*/
export const getPriority = (marker: HTMLElement): Priority | undefined => {
const priority = marker.getAttribute('priority');

if (isValidSchedulerPriority(priority)) {
return priority;
}

console.error(
'Unable to find valid priority attribute on gu-island',
marker,
);

return;
};
57 changes: 22 additions & 35 deletions dotcom-rendering/src/client/islands/initHydration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { EmotionCache } from '@emotion/cache';
import { isUndefined } from '@guardian/libs';
import { schedule } from '../../lib/scheduler';
import { doHydration } from './doHydration';
import { getConfig } from './getConfig';
import { getName } from './getName';
import { getPriority } from './getPriority';
import { getProps } from './getProps';
import { onInteraction } from './onInteraction';
import { onNavigation } from './onNavigation';
Expand Down Expand Up @@ -38,51 +41,41 @@ export const initHydration = async (
const name = getName(element);
const props = getProps(element);
const config = getConfig(element);
const priority = getPriority(element);

if (!name) return;
if (isUndefined(priority)) return;

const scheduleHydration = () =>
schedule(
name,
() => doHydration(name, props, element, emotionCache, config),
{ priority },
);

const deferUntil = element.getAttribute('deferuntil');
switch (deferUntil) {
case 'idle': {
whenIdle(() => {
void doHydration(name, props, element, emotionCache, config);
});
whenIdle(() => void scheduleHydration());
return;
}
case 'visible': {
const rootMargin = element.getAttribute('rootmargin') ?? undefined;
whenVisible(
element,
() => {
void doHydration(
name,
props,
element,
emotionCache,
config,
);
},
{ rootMargin },
);
whenVisible(element, () => void scheduleHydration(), {
rootMargin,
});
return;
}
case 'interaction': {
onInteraction(element, (targetElement) => {
void doHydration(
name,
props,
element,
emotionCache,
config,
).then(() => {
targetElement.dispatchEvent(new MouseEvent('click'));
});
onInteraction(element, async (targetElement) => {
await scheduleHydration();
targetElement.dispatchEvent(new MouseEvent('click'));
Comment thread
cemms1 marked this conversation as resolved.
});
return;
}
case 'hash': {
if (window.location.hash.includes(name) || hasLightboxHash(name)) {
void doHydration(name, props, element, emotionCache, config);
return scheduleHydration();
Comment thread
sndrs marked this conversation as resolved.
} else {
// If we didn't find a matching hash on page load, set a
// listener so that we check again each time the reader
Expand All @@ -92,20 +85,14 @@ export const initHydration = async (
window.location.hash.includes(name) ||
hasLightboxHash(name)
) {
void doHydration(
name,
props,
element,
emotionCache,
config,
);
void scheduleHydration();
}
});
}
return;
}
default: {
return doHydration(name, props, element, emotionCache, config);
return scheduleHydration();
}
}
};
4 changes: 2 additions & 2 deletions dotcom-rendering/src/client/islands/onInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
*/
export const onInteraction = (
element: HTMLElement,
callback: (e: HTMLElement) => void,
callback: (e: HTMLElement) => Promise<void> | void,
): void => {
element.addEventListener(
'click',
(e) => {
if (e.target instanceof HTMLElement) {
callback(e.target);
void callback(e.target);
}
},
{ once: true },
Expand Down
6 changes: 5 additions & 1 deletion dotcom-rendering/src/lib/scheduler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { startPerformanceMeasure } from '@guardian/libs';
import type { Guard } from './guard';
import { guard } from './guard';

const START = Date.now();

Expand All @@ -22,9 +24,11 @@ let CONCURRENCY_COUNT = Infinity;
* priorities, and the scheduler will prefer the priority with the lowest index.
**/
const PRIORITIES = ['critical', 'feature', 'enhancement'] as const;
type Priority = (typeof PRIORITIES)[number];
export type Priority = Guard<typeof PRIORITIES>;
export type SchedulePriority = { [K in Priority]: K };

export const isValidSchedulerPriority = guard(PRIORITIES);

/**
* A thing that a consumer want to do. Should be a function that returns a promise.
*/
Expand Down