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/chart.js@2.8.0"></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);
});