From cf1e595ba2c21698cfef458422080425c5b95f43 Mon Sep 17 00:00:00 2001 From: garronej Date: Wed, 19 Apr 2023 03:20:22 +0200 Subject: [PATCH] Clean up dynamically inserted assets when template is unmounted #274 --- src/lib/usePrepareTemplate.ts | 45 ++++++++++++++++++++++------------- src/login/pages/LoginOtp.tsx | 15 ++++++++---- src/tools/headInsert.ts | 7 ++++-- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/lib/usePrepareTemplate.ts b/src/lib/usePrepareTemplate.ts index 6a44b41e..ee49a93c 100644 --- a/src/lib/usePrepareTemplate.ts +++ b/src/lib/usePrepareTemplate.ts @@ -15,7 +15,7 @@ export function usePrepareTemplate(params: { htmlClassName: string | undefined; bodyClassName: string | undefined; }) { - const { doFetchDefaultThemeResources, stylesCommon, styles, url, scripts, htmlClassName, bodyClassName } = params; + const { doFetchDefaultThemeResources, stylesCommon = [], styles = [], url, scripts = [], htmlClassName, bodyClassName } = params; const [isReady, setReady] = useReducer(() => true, !doFetchDefaultThemeResources); @@ -26,36 +26,49 @@ export function usePrepareTemplate(params: { let isUnmounted = false; - Promise.all( + const removeArray: (() => void)[] = []; + + (async () => { + const prLoadedArray: Promise[] = []; + [ - ...(stylesCommon ?? []).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)), - ...(styles ?? []).map(relativePath => pathJoin(url.resourcesPath, relativePath)) + ...stylesCommon.map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)), + ...styles.map(relativePath => pathJoin(url.resourcesPath, relativePath)) ] .reverse() - .map(href => - headInsert({ + .forEach(href => { + const { prLoaded, remove } = headInsert({ "type": "css", - href, - "position": "prepend" - }) - ) - ).then(() => { + "position": "prepend", + href + }); + + removeArray.push(remove); + + prLoadedArray.push(prLoaded); + }); + + await Promise.all(prLoadedArray); + if (isUnmounted) { return; } setReady(); - }); + })(); - (scripts ?? []).forEach(relativePath => - headInsert({ + scripts.forEach(relativePath => { + const { remove } = headInsert({ "type": "javascript", "src": pathJoin(url.resourcesPath, relativePath) - }) - ); + }); + + removeArray.push(remove); + }); return () => { isUnmounted = true; + removeArray.forEach(remove => remove()); }; }, []); diff --git a/src/login/pages/LoginOtp.tsx b/src/login/pages/LoginOtp.tsx index 3007c128..c6126fab 100644 --- a/src/login/pages/LoginOtp.tsx +++ b/src/login/pages/LoginOtp.tsx @@ -22,17 +22,24 @@ export default function LoginOtp(props: PageProps { let isCleanedUp = false; - headInsert({ + const { prLoaded, remove } = headInsert({ "type": "javascript", "src": pathJoin(kcContext.url.resourcesCommonPath, "node_modules/jquery/dist/jquery.min.js") - }).then(() => { - if (isCleanedUp) return; + }); + + (async () => { + await prLoaded; + + if (isCleanedUp) { + return; + } evaluateInlineScript(); - }); + })(); return () => { isCleanedUp = true; + remove(); }; }, []); diff --git a/src/tools/headInsert.ts b/src/tools/headInsert.ts index fd6efea2..0a123772 100644 --- a/src/tools/headInsert.ts +++ b/src/tools/headInsert.ts @@ -12,7 +12,7 @@ export function headInsert( type: "javascript"; src: string; } -) { +): { remove: () => void; prLoaded: Promise } { const htmlElement = document.createElement( (() => { switch (params.type) { @@ -66,5 +66,8 @@ export function headInsert( })() ](htmlElement); - return dLoaded.pr; + return { + "prLoaded": dLoaded.pr, + "remove": () => htmlElement.remove() + }; }