UNPKG

meshcentral

Version:

Web based remote computer management server

281 lines (252 loc) • 8.6 kB
import RegisterLoader from 'es-module-loader/core/register-loader.js'; import { InternalModuleNamespace as ModuleNamespace } from 'es-module-loader/core/loader-polyfill.js'; import { baseURI, global, isBrowser } from 'es-module-loader/core/common.js'; import { resolveIfNotPlain } from 'es-module-loader/core/resolve.js'; var loader; // <script type="module"> support var anonSources = {}; if (typeof document != 'undefined' && document.getElementsByTagName) { var handleError = function(err) { // dispatch an error event so that we can display in errors in browsers // that don't yet support unhandledrejection if (window.onunhandledrejection === undefined) { try { var evt = new Event('error'); } catch (_eventError) { var evt = document.createEvent('Event'); evt.initEvent('error', true, true); } evt.message = err.message; if (err.fileName) { evt.filename = err.fileName; evt.lineno = err.lineNumber; evt.colno = err.columnNumber; } else if (err.sourceURL) { evt.filename = err.sourceURL; evt.lineno = err.line; evt.colno = err.column; } evt.error = err; window.dispatchEvent(evt); } // throw so it still shows up in the console throw err; } var ready = function() { document.removeEventListener('DOMContentLoaded', ready, false ); var anonCnt = 0; var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { var script = scripts[i]; if (script.type == 'module' && !script.loaded) { script.loaded = true; if (script.src) { loader.import(script.src).catch(handleError); } // anonymous modules supported via a custom naming scheme and registry else { var uri = './<anon' + ++anonCnt + '>.js'; if (script.id !== ""){ uri = "./" + script.id; } var anonName = resolveIfNotPlain(uri, baseURI); anonSources[anonName] = script.innerHTML; loader.import(anonName).catch(handleError); } } } } // simple DOM ready if (document.readyState !== 'loading') setTimeout(ready); else document.addEventListener('DOMContentLoaded', ready, false); } function BrowserESModuleLoader(baseKey) { if (baseKey) this.baseKey = resolveIfNotPlain(baseKey, baseURI) || resolveIfNotPlain('./' + baseKey, baseURI); RegisterLoader.call(this); var loader = this; // ensure System.register is available global.System = global.System || {}; if (typeof global.System.register == 'function') var prevRegister = global.System.register; global.System.register = function() { loader.register.apply(loader, arguments); if (prevRegister) prevRegister.apply(this, arguments); }; } BrowserESModuleLoader.prototype = Object.create(RegisterLoader.prototype); // normalize is never given a relative name like "./x", that part is already handled BrowserESModuleLoader.prototype[RegisterLoader.resolve] = function(key, parent) { var resolved = RegisterLoader.prototype[RegisterLoader.resolve].call(this, key, parent || this.baseKey) || key; if (!resolved) throw new RangeError('ES module loader does not resolve plain module names, resolving "' + key + '" to ' + parent); return resolved; }; function xhrFetch(url, resolve, reject) { var xhr = new XMLHttpRequest(); var load = function(source) { resolve(xhr.responseText); } var error = function() { reject(new Error('XHR error' + (xhr.status ? ' (' + xhr.status + (xhr.statusText ? ' ' + xhr.statusText : '') + ')' : '') + ' loading ' + url)); } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { // in Chrome on file:/// URLs, status is 0 if (xhr.status == 0) { if (xhr.responseText) { load(); } else { // when responseText is empty, wait for load or error event // to inform if it is a 404 or empty file xhr.addEventListener('error', error); xhr.addEventListener('load', load); } } else if (xhr.status === 200) { load(); } else { error(); } } }; xhr.open("GET", url, true); xhr.send(null); } var WorkerPool = function (script, size) { var current = document.currentScript; // IE doesn't support currentScript if (!current) { // Find an entry with out basename var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { if (scripts[i].src.indexOf("browser-es-module-loader.js") !== -1) { current = scripts[i]; break; } } if (!current) throw Error("Could not find own <script> element"); } script = current.src.substr(0, current.src.lastIndexOf("/")) + "/" + script; this._workers = new Array(size); this._ind = 0; this._size = size; this._jobs = 0; this.onmessage = undefined; this._stopTimeout = undefined; for (var i = 0; i < size; i++) { var wrkr = new Worker(script); wrkr._count = 0; wrkr._ind = i; wrkr.onmessage = this._onmessage.bind(this, wrkr); wrkr.onerror = this._onerror.bind(this); this._workers[i] = wrkr; } this._checkJobs(); }; WorkerPool.prototype = { postMessage: function (msg) { if (this._stopTimeout !== undefined) { clearTimeout(this._stopTimeout); this._stopTimeout = undefined; } var wrkr = this._workers[this._ind % this._size]; wrkr._count++; this._jobs++; wrkr.postMessage(msg); this._ind++; }, _onmessage: function (wrkr, evt) { wrkr._count--; this._jobs--; this.onmessage(evt, wrkr); this._checkJobs(); }, _onerror: function(err) { try { var evt = new Event('error'); } catch (_eventError) { var evt = document.createEvent('Event'); evt.initEvent('error', true, true); } evt.message = err.message; evt.filename = err.filename; evt.lineno = err.lineno; evt.colno = err.colno; evt.error = err.error; window.dispatchEvent(evt); }, _checkJobs: function () { if (this._jobs === 0 && this._stopTimeout === undefined) { // wait for 2s of inactivity before stopping (that should be enough for local loading) this._stopTimeout = setTimeout(this._stop.bind(this), 2000); } }, _stop: function () { this._workers.forEach(function(wrkr) { wrkr.terminate(); }); } }; var promiseMap = new Map(); var babelWorker = new WorkerPool('babel-worker.js', 3); babelWorker.onmessage = function (evt) { var promFuncs = promiseMap.get(evt.data.key); promFuncs.resolve(evt.data); promiseMap.delete(evt.data.key); }; // instantiate just needs to run System.register // so we fetch the source, convert into the Babel System module format, then evaluate it BrowserESModuleLoader.prototype[RegisterLoader.instantiate] = function(key, processAnonRegister) { var loader = this; // load as ES with Babel converting into System.register return new Promise(function(resolve, reject) { // anonymous module if (anonSources[key]) { resolve(anonSources[key]) anonSources[key] = undefined; } // otherwise we fetch else { xhrFetch(key, resolve, reject); } }) .then(function(source) { // check our cache first var cacheEntry = localStorage.getItem(key); if (cacheEntry) { cacheEntry = JSON.parse(cacheEntry); // TODO: store a hash instead if (cacheEntry.source === source) { return Promise.resolve({key: key, code: cacheEntry.code, source: cacheEntry.source}); } } return new Promise(function (resolve, reject) { promiseMap.set(key, {resolve: resolve, reject: reject}); babelWorker.postMessage({key: key, source: source}); }); }).then(function (data) { // evaluate without require, exports and module variables // we leave module in for now to allow module.require access try { var cacheEntry = JSON.stringify({source: data.source, code: data.code}); localStorage.setItem(key, cacheEntry); } catch (e) { if (window.console) { window.console.warn('Unable to cache transpiled version of ' + key + ': ' + e); } } (0, eval)(data.code + '\n//# sourceURL=' + data.key + '!transpiled'); processAnonRegister(); }); }; // create a default loader instance in the browser if (isBrowser) loader = new BrowserESModuleLoader(); export default BrowserESModuleLoader;