197 lines
6.2 KiB
JavaScript
197 lines
6.2 KiB
JavaScript
/*
|
|
* Script tag fetch
|
|
*
|
|
* When load.metadata.scriptLoad is true, we load via script tag injection.
|
|
*/
|
|
(function() {
|
|
|
|
if (typeof document != 'undefined')
|
|
var head = document.getElementsByTagName('head')[0];
|
|
|
|
var curSystem;
|
|
var curRequire;
|
|
|
|
// if doing worker executing, this is set to the load record being executed
|
|
var workerLoad = null;
|
|
|
|
// interactive mode handling method courtesy RequireJS
|
|
var ieEvents = head && (function() {
|
|
var s = document.createElement('script');
|
|
var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]';
|
|
return s.attachEvent && !(s.attachEvent.toString && s.attachEvent.toString().indexOf('[native code') < 0) && !isOpera;
|
|
})();
|
|
|
|
// IE interactive-only part
|
|
// we store loading scripts array as { script: <script>, load: {...} }
|
|
var interactiveLoadingScripts = [];
|
|
var interactiveScript;
|
|
function getInteractiveScriptLoad() {
|
|
if (interactiveScript && interactiveScript.script.readyState === 'interactive')
|
|
return interactiveScript.load;
|
|
|
|
for (var i = 0; i < interactiveLoadingScripts.length; i++)
|
|
if (interactiveLoadingScripts[i].script.readyState == 'interactive') {
|
|
interactiveScript = interactiveLoadingScripts[i];
|
|
return interactiveScript.load;
|
|
}
|
|
}
|
|
|
|
// System.register, System.registerDynamic, AMD define pipeline
|
|
// this is called by the above methods when they execute
|
|
// we then run the reduceRegister_ collection function either immediately
|
|
// if we are in IE and know the currently executing script (interactive)
|
|
// or later if we need to wait for the synchronous load callback to know the script
|
|
var loadingCnt = 0;
|
|
var registerQueue = [];
|
|
hook('pushRegister_', function(pushRegister) {
|
|
return function(register) {
|
|
// if using eval-execution then skip
|
|
if (pushRegister.call(this, register))
|
|
return false;
|
|
|
|
// if using worker execution, then we're done
|
|
if (workerLoad)
|
|
this.reduceRegister_(workerLoad, register);
|
|
|
|
// detect if we know the currently executing load (IE)
|
|
// if so, immediately call reduceRegister
|
|
else if (ieEvents)
|
|
this.reduceRegister_(getInteractiveScriptLoad(), register);
|
|
|
|
// otherwise, add to our execution queue
|
|
// to call reduceRegister on sync script load event
|
|
else if (loadingCnt)
|
|
registerQueue.push(register);
|
|
|
|
// if we're not currently loading anything though
|
|
// then do the reduction against a null load
|
|
// (out of band named define or named register)
|
|
// note even in non-script environments, this catch is used
|
|
else
|
|
this.reduceRegister_(null, register);
|
|
|
|
return true;
|
|
};
|
|
});
|
|
|
|
function webWorkerImport(loader, load) {
|
|
return new Promise(function(resolve, reject) {
|
|
if (load.metadata.integrity)
|
|
reject(new Error('Subresource integrity checking is not supported in web workers.'));
|
|
|
|
workerLoad = load;
|
|
try {
|
|
importScripts(load.address);
|
|
}
|
|
catch(e) {
|
|
workerLoad = null;
|
|
reject(e);
|
|
}
|
|
workerLoad = null;
|
|
|
|
// if nothing registered, then something went wrong
|
|
if (!load.metadata.entry)
|
|
reject(new Error(load.address + ' did not call System.register or AMD define'));
|
|
|
|
resolve('');
|
|
});
|
|
}
|
|
|
|
// override fetch to use script injection
|
|
hook('fetch', function(fetch) {
|
|
return function(load) {
|
|
var loader = this;
|
|
|
|
if (load.metadata.format == 'json' || !load.metadata.scriptLoad || (!isBrowser && !isWorker))
|
|
return fetch.call(this, load);
|
|
|
|
if (isWorker)
|
|
return webWorkerImport(loader, load);
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
var s = document.createElement('script');
|
|
|
|
s.async = true;
|
|
|
|
if (load.metadata.crossOrigin)
|
|
s.crossOrigin = load.metadata.crossOrigin;
|
|
|
|
if (load.metadata.integrity)
|
|
s.setAttribute('integrity', load.metadata.integrity);
|
|
|
|
if (ieEvents) {
|
|
s.attachEvent('onreadystatechange', complete);
|
|
interactiveLoadingScripts.push({
|
|
script: s,
|
|
load: load
|
|
});
|
|
}
|
|
else {
|
|
s.addEventListener('load', complete, false);
|
|
s.addEventListener('error', error, false);
|
|
}
|
|
|
|
loadingCnt++;
|
|
|
|
curSystem = __global.System;
|
|
curRequire = __global.require;
|
|
|
|
s.src = load.address;
|
|
head.appendChild(s);
|
|
|
|
function complete(evt) {
|
|
if (s.readyState && s.readyState != 'loaded' && s.readyState != 'complete')
|
|
return;
|
|
|
|
loadingCnt--;
|
|
|
|
// complete call is sync on execution finish
|
|
// (in ie already done reductions)
|
|
if (!load.metadata.entry && !registerQueue.length) {
|
|
loader.reduceRegister_(load);
|
|
}
|
|
else if (!ieEvents) {
|
|
for (var i = 0; i < registerQueue.length; i++)
|
|
loader.reduceRegister_(load, registerQueue[i]);
|
|
registerQueue = [];
|
|
}
|
|
|
|
cleanup();
|
|
|
|
// if nothing registered, then something went wrong
|
|
if (!load.metadata.entry && !load.metadata.bundle)
|
|
reject(new Error(load.name + ' did not call System.register or AMD define. If loading a global module configure the global name via the meta exports property for script injection support.'));
|
|
|
|
resolve('');
|
|
}
|
|
|
|
function error(evt) {
|
|
cleanup();
|
|
reject(new Error('Unable to load script ' + load.address));
|
|
}
|
|
|
|
function cleanup() {
|
|
__global.System = curSystem;
|
|
__global.require = curRequire;
|
|
|
|
if (s.detachEvent) {
|
|
s.detachEvent('onreadystatechange', complete);
|
|
for (var i = 0; i < interactiveLoadingScripts.length; i++)
|
|
if (interactiveLoadingScripts[i].script == s) {
|
|
if (interactiveScript && interactiveScript.script == s)
|
|
interactiveScript = null;
|
|
interactiveLoadingScripts.splice(i, 1);
|
|
}
|
|
}
|
|
else {
|
|
s.removeEventListener('load', complete, false);
|
|
s.removeEventListener('error', error, false);
|
|
}
|
|
|
|
head.removeChild(s);
|
|
}
|
|
});
|
|
};
|
|
});
|
|
})();
|