Skip to content

Instantly share code, notes, and snippets.

@lidio601
Last active January 18, 2020 19:34
Show Gist options
  • Save lidio601/81974ecf4564dbf257f80a969dcbdd5c to your computer and use it in GitHub Desktop.
Save lidio601/81974ecf4564dbf257f80a969dcbdd5c to your computer and use it in GitHub Desktop.
Load custom script into DOM (with Promise)
/**
* Dinamically load script into DOM
* @see https://gist.github.com/lidio601/81974ecf4564dbf257f80a969dcbdd5c
*
* Example usage:
* {code}
require('./loadScript');
console.log('starting');
loadScripts([
"https://cdn.jsdelivr.net/npm/opus-media-recorder@latest/OpusMediaRecorder.umd.js",
"https://cdn.jsdelivr.net/npm/opus-media-recorder@latest/encoderWorker.umd.js"
], { debug: true })
.then(() => console.log("finished"))
.catch(console.error);
{/code}
*/
/**
* @see https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript
*/
export const loadScript = (
source,
{
beforeEl = false,
afterEl = false,
async = true,
defer = true,
debug = false
} = {}
) => {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
const shouldInjectBefore = !afterEl; // defaults to before
const scripts = document.getElementsByTagName("script");
// check whenever this script is not already included!
const existingOne = Array.prototype.slice
.call(scripts)
.filter(elem => elem.src === source);
if (existingOne.length) {
debug && console.warn("loadScript :: skipped because it's already loaded", {
source
});
return resolve(existingOne);
}
const prior = beforeEl || (scripts.length > 0 ? scripts[0] : null);
const after = afterEl || (scripts.length > 0 ? [scripts.length - 1] : null);
script.async = async;
script.defer = defer;
function onloadHander(_, isAbort) {
if (
isAbort ||
!script.readyState ||
/loaded|complete/.test(script.readyState)
) {
script.onload = null;
script.onreadystatechange = null;
script = undefined;
if (isAbort) {
reject(
new Error(`loadScript :: error while loading script from ${script}`)
);
} else {
resolve(script);
}
}
}
script.onload = onloadHander;
script.onreadystatechange = onloadHander;
script.src = source;
if (shouldInjectBefore && beforeEl) {
prior.parentNode.insertBefore(script, prior);
} else if (!shouldInjectBefore && afterEl) {
// Note: There is no insertAfter() method.
// It can be emulated by combining the insertBefore method with Node.nextSibling.
prior.parentNode.insertBefore(script, after.nextSibling);
} else {
document.head.appendChild(script);
}
});
};
export const loadScripts = async (
sources,
{
beforeEl = false,
afterEl = false,
async = true,
defer = true,
debug = false
} = {}
) => {
// defaults to []
sources = sources || [];
// ensure that is an array
sources = typeof sources.forEach === "function" ? sources : [sources];
// if it's empty
if (sources.length === 0) {
debug && console.log("loadScripts :: ended");
return;
}
// include scripts in order
const firstScript = sources.shift();
debug && console.log("loadScripts :: loading", firstScript);
return (
loadScript(firstScript, { beforeEl, afterEl, async, defer })
// recursion here!
.then(elem => {
debug && console.log("loadScripts :: loaded", firstScript);
return loadScripts(sources, {
// continue injecting the other scripts
// after this one
afterEl: elem,
async,
defer,
debug
});
})
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment