Merge branch 'loadscript-race-condition' into 'main'

fix $loadScript/$loadStylesheet race condition

See merge request PronounsPage/PronounsPage!493
This commit is contained in:
Andrea Vos 2024-07-08 20:18:04 +00:00
commit 09066acb46

View File

@ -80,13 +80,38 @@ const plugin: Plugin = ({ app, store }, inject) => {
store.commit('showTranslationMode');
}
const awaitLoadedClass = (node: Element): Promise<void> => {
return new Promise((resolve) => {
if (node.classList.contains('loaded')) {
resolve();
} else {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const target = mutation.target as Element;
if (target.classList.contains('loaded')) {
observer.disconnect();
resolve();
}
});
});
observer.observe(node, { attributes: true, attributeFilter: ['class'] });
}
});
};
inject('loadScript', (name: string, src: string, nonce: string | undefined = undefined): Promise<void> => {
if (!process.client || document.querySelectorAll(`script.${name}-script`).length > 0) {
if (!process.client) {
return new Promise((resolve) => {
resolve();
});
}
const existingScriptNode = document.querySelector(`script.${name}-script`);
if (existingScriptNode) {
return awaitLoadedClass(existingScriptNode);
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.setAttribute('src', src);
@ -100,6 +125,7 @@ const plugin: Plugin = ({ app, store }, inject) => {
resolve();
});
script.addEventListener('error', (event) => {
script.classList.add('loaded'); // not really loaded, but let's stop other calls from waiting forever, see !493
reject(new LoadScriptError(name, src, typeof event === 'string' ? event : event.type));
});
document.body.appendChild(script);
@ -107,20 +133,29 @@ const plugin: Plugin = ({ app, store }, inject) => {
});
inject('loadStylesheet', (name: string, src: string): Promise<void> => {
if (!process.client || document.querySelectorAll(`link.${name}-stylesheet`).length > 0) {
if (!process.client) {
return new Promise((resolve) => {
resolve();
});
}
const existingLinkNode = document.querySelector(`link.${name}-stylesheet`);
if (existingLinkNode) {
return awaitLoadedClass(existingLinkNode);
}
return new Promise((resolve, reject) => {
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', src);
link.classList.add(`${name}-stylesheet`);
link.crossOrigin = 'true';
link.addEventListener('load', () => resolve());
link.addEventListener('load', () => {
link.classList.add('loaded');
resolve();
});
link.addEventListener('error', (event) => {
link.classList.add('loaded'); // not really loaded, but let's stop other calls from waiting forever, see !493
reject(new LoadScriptError(name, src, typeof event === 'string' ? event : event.type));
});
document.body.appendChild(link);