I found the other answer using eval() here helpful, but ran into a problem as my dynamically loaded content was importing an external script giving CORS warnings in Firefox, for example:
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
I therefore tweaked it a little to inject script tags without using eval() to allow external scripts from other domains as well as embedded scripts. I then modified to load the scripts in the order they are defined, waiting for the load to complete before loading the next - this was due to the fact that an embedded script on my page depended on functionality from the external scripts being loaded.
fetch("/mypage.html").then(response => { return response.text(); }).then(data => { const app = document.getElementById("app"); app.innerHTML = data; // Load scripts in the order they are defined // Note that inserting scripts into an element using innerHTML doesnt work - hence this logic var scripts = app.querySelectorAll("script"); if (scripts !== null && scripts.length > 0) { var loadScript = index => { if (index < scripts.length) { var newScript = document.createElement("script"); if (scripts[index].innerText) { var inlineScript = document.createTextNode(scripts[index].innerText); newScript.appendChild(inlineScript); } else { newScript.src = scripts[index].src; } scripts[index].parentNode.removeChild(scripts[index]); newScript.addEventListener("load", event => loadScript(index + 1)); newScript.addEventListener("error", event => loadScript(index + 1)); app.appendChild(newScript); } } loadScript(0); // Start loading script 0. Function is recursive to load the next script after the current one has finished downloading. } }).catch(err => { console.warn('Something went wrong.', err); });