react-render-props-script-loader
Version:
an easier to use dynamic script loader
79 lines • 2.16 kB
JavaScript
/* eslint-env browser */
let nonce;
function getNonce() {
if (nonce === undefined) {
const node = document.querySelector('meta[property="csp-nonce"], meta[name="csp-nonce"]');
nonce = node ? node.getAttribute('content') ?? null : null;
}
return nonce ?? null;
}
const loadScript = async ({
scriptsRegistry,
onLoad,
onError,
children,
// eslint-disable-next-line no-unused-vars
act,
...props
}) => {
const {
src
} = props;
if (scriptsRegistry) {
scriptsRegistry.results[src] = {
error: undefined
};
scriptsRegistry.scripts.push(props);
return;
}
if (typeof document === 'undefined') {
throw new Error('you must pass a scriptsRegistry if calling on the server side');
}
if (typeof document.querySelector === 'function') {
if (document.querySelector(`script[src="${src}"]`)) {
results[src] = {
error: undefined
};
return;
}
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.nonce = getNonce();
Object.keys(props).forEach(key => script.setAttribute(key, props[key]));
script.onload = resolve;
script.onerror = reject;
if (document.body) document.body.appendChild(script);
});
};
const results = {};
const promises = {};
export default (props => {
const {
scriptsRegistry
} = props;
const _promises = scriptsRegistry ? scriptsRegistry.promises : promises;
const _results = scriptsRegistry ? scriptsRegistry.results : results;
return _promises[props.src] || (_promises[props.src] = loadScript(props).then(() => _results[props.src] = {
error: null
}, (error = new Error(`failed to load ${props.src}`)) => {
_results[props.src] = {
error
};
throw error;
}));
});
export function getState({
src,
scriptsRegistry
}) {
const result = scriptsRegistry ? scriptsRegistry.results[src] : results[src];
const promise = scriptsRegistry ? scriptsRegistry.promises[src] : promises[src];
return {
loading: result == null,
loaded: result ? !result.error : false,
error: result && result.error,
promise
};
}