90 lines
2.5 KiB
JavaScript
90 lines
2.5 KiB
JavaScript
const pageScriptInfoBySrc = new Map();
|
|
|
|
function registerPageScriptElement(src) {
|
|
if (!src) {
|
|
throw new Error('Must provide a non-empty value for the "src" attribute.');
|
|
}
|
|
|
|
let pageScriptInfo = pageScriptInfoBySrc.get(src);
|
|
|
|
if (pageScriptInfo) {
|
|
pageScriptInfo.referenceCount++;
|
|
} else {
|
|
pageScriptInfo = { referenceCount: 1, module: null };
|
|
pageScriptInfoBySrc.set(src, pageScriptInfo);
|
|
initializePageScriptModule(src, pageScriptInfo);
|
|
}
|
|
}
|
|
|
|
function unregisterPageScriptElement(src) {
|
|
if (!src) {
|
|
return;
|
|
}
|
|
|
|
const pageScriptInfo = pageScriptInfoBySrc.get(src);
|
|
if (!pageScriptInfo) {
|
|
return;
|
|
}
|
|
|
|
pageScriptInfo.referenceCount--;
|
|
}
|
|
|
|
async function initializePageScriptModule(src, pageScriptInfo) {
|
|
// If the path is relative, normalize it by by making it an absolute URL
|
|
// with document's the base HREF.
|
|
if (src.startsWith("./")) {
|
|
src = new URL(src.substr(2), document.baseURI).toString();
|
|
}
|
|
|
|
const module = await import(src);
|
|
|
|
if (pageScriptInfo.referenceCount <= 0) {
|
|
// All page-script elements with the same 'src' were
|
|
// unregistered while we were loading the module.
|
|
return;
|
|
}
|
|
|
|
pageScriptInfo.module = module;
|
|
module.onLoad?.();
|
|
module.onUpdate?.();
|
|
}
|
|
|
|
function onEnhancedLoad() {
|
|
// Start by invoking 'onDispose' on any modules that are no longer referenced.
|
|
for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
|
|
if (referenceCount <= 0) {
|
|
module?.onDispose?.();
|
|
pageScriptInfoBySrc.delete(src);
|
|
}
|
|
}
|
|
|
|
// Then invoke 'onUpdate' on the remaining modules.
|
|
for (const { module } of pageScriptInfoBySrc.values()) {
|
|
module?.onUpdate?.();
|
|
}
|
|
}
|
|
|
|
export function afterWebStarted(blazor) {
|
|
customElements.define('page-script', class extends HTMLElement {
|
|
static observedAttributes = ['src'];
|
|
|
|
// We use attributeChangedCallback instead of connectedCallback
|
|
// because a page-script element might get reused between enhanced
|
|
// navigations.
|
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
if (name !== 'src') {
|
|
return;
|
|
}
|
|
|
|
this.src = newValue;
|
|
unregisterPageScriptElement(oldValue);
|
|
registerPageScriptElement(newValue);
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
unregisterPageScriptElement(this.src);
|
|
}
|
|
});
|
|
|
|
blazor.addEventListener('enhancedload', onEnhancedLoad);
|
|
} |