first draft novnc
This commit is contained in:
1 parent
6b3c8cc71b
commit
7916d7f257
108 files changed
+79262
-2
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,15 @@
|
||||
Custom Browser ES Module Loader
|
||||
===============================
|
||||
|
||||
This is a module loader using babel and the ES Module Loader polyfill.
|
||||
It's based heavily on
|
||||
https://github.com/ModuleLoader/browser-es-module-loader, but uses
|
||||
WebWorkers to compile the modules in the background.
|
||||
|
||||
To generate, run `rollup -c` in this directory, and then run `browserify
|
||||
src/babel-worker.js > dist/babel-worker.js`.
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
MIT
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"browser-es-module-loader.js","sources":["../../../node_modules/es-module-loader/core/common.js","../../../node_modules/es-module-loader/core/loader-polyfill.js","../../../node_modules/es-module-loader/core/resolve.js","../../../node_modules/es-module-loader/core/register-loader.js","../src/browser-es-module-loader.js"],"sourcesContent":["/*\n * Environment\n */\nexport var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';\nexport var isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\nexport var isWindows = typeof process !== 'undefined' && typeof process.platform === 'string' && process.platform.match(/^win/);\n\nvar envGlobal = typeof self !== 'undefined' ? self : global;\nexport { envGlobal as global }\n\n/*\n * Simple Symbol() shim\n */\nvar hasSymbol = typeof Symbol !== 'undefined';\nexport function createSymbol (name) {\n return hasSymbol ? Symbol() : '@@' + name;\n}\n\nexport function pathToFileUrl (filePath) {\n return 'file://' + (isWindows ? '/' : '') + (isWindows ? filePath.replace(/\\\\/g, '/') : filePath);\n}\n\nexport function fileUrlToPath (fileUrl) {\n if (fileUrl.substr(0, 7) !== 'file://')\n throw new RangeError(fileUrl + ' is not a valid file url');\n if (isWindows)\n return fileUrl.substr(8).replace(/\\\\/g, '/');\n else\n return fileUrl.substr(7);\n}\n\n/*\n * Environment baseURI\n */\nexport var baseURI;\n\n// environent baseURI detection\nif (typeof document != 'undefined' && document.getElementsByTagName) {\n baseURI = document.baseURI;\n\n if (!baseURI) {\n var bases = document.getElementsByTagName('base');\n baseURI = bases[0] && bases[0].href || window.location.href;\n }\n}\nelse if (typeof location != 'undefined') {\n baseURI = location.href;\n}\n\n// sanitize out the hash and querystring\nif (baseURI) {\n baseURI = baseURI.split('#')[0].split('?')[0];\n var slashIndex = baseURI.lastIndexOf('/');\n if (slashIndex !== -1)\n baseURI = baseURI.substr(0, slashIndex + 1);\n}\nelse if (typeof process !== 'undefined' && process.cwd) {\n baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd();\n if (isWindows)\n baseURI = baseURI.replace(/\\\\/g, '/');\n}\nelse {\n throw new TypeError('No environment baseURI');\n}\n\n// ensure baseURI has trailing \"/\"\nif (baseURI[baseURI.length - 1] !== '/')\n baseURI += '/';\n\n/*\n * LoaderError with chaining for loader stacks\n */\nvar errArgs = new Error(0, '_').fileName == '_';\nfunction LoaderError__Check_error_message_for_loader_stack (childErr, newMessage) {\n // Convert file:/// URLs to paths in Node\n if (!isBrowser)\n newMessage = newMessage.replace(isWindows ? /file:\\/\\/\\//g : /file:\\/\\//g, '');\n\n var message = (childErr.message || childErr) + '\\n ' + newMessage;\n\n var err;\n if (errArgs && childErr.fileName)\n err = new Error(message, childErr.fileName, childErr.lineNumber);\n else\n err = new Error(message);\n\n\n var stack = childErr.originalErr ? childErr.originalErr.stack : childErr.stack;\n\n if (isNode)\n // node doesn't show the message otherwise\n err.stack = message + '\\n ' + stack;\n else\n err.stack = stack;\n\n err.originalErr = childErr.originalErr || childErr;\n\n return err;\n}\nexport { LoaderError__Check_error_message_for_loader_stack as addToError }\n","import { addToError, createSymbol } from './common.js';\n\nexport { Loader, ModuleNamespace, REGISTRY }\n\nvar resolvedPromise = Promise.resolve();\n\n/*\n * Simple Array values shim\n */\nfunction arrayValues (arr) {\n if (arr.values)\n return arr.values();\n\n if (typeof Symbol === 'undefined' || !Symbol.iterator)\n throw new Error('Symbol.iterator not supported in this browser');\n\n var iterable = {};\n iterable[Symbol.iterator] = function () {\n var keys = Object.keys(arr);\n var keyIndex = 0;\n return {\n next: function () {\n if (keyIndex < keys.length)\n return {\n value: arr[keys[keyIndex++]],\n done: false\n };\n else\n return {\n value: undefined,\n done: true\n };\n }\n };\n };\n return iterable;\n}\n\n/*\n * 3. Reflect.Loader\n *\n * We skip the entire native internal pipeline, just providing the bare API\n */\n// 3.1.1\nfunction Loader () {\n this.registry = new Registry();\n}\n// 3.3.1\nLoader.prototype.constructor = Loader;\n\nfunction ensureInstantiated (module) {\n if (!(module instanceof ModuleNamespace))\n throw new TypeError('Module instantiation did not return a valid namespace object.');\n return module;\n}\n\n// 3.3.2\nLoader.prototype.import = function (key, parent) {\n if (typeof key !== 'string')\n throw new TypeError('Loader import method must be passed a module key string');\n // custom resolveInstantiate combined hook for better perf\n var loader = this;\n return resolvedPromise\n .then(function () {\n return loader[RESOLVE_INSTANTIATLine truncated
|
||||
@@ -0,0 +1,16 @@
|
||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
||||
|
||||
export default {
|
||||
entry: 'src/browser-es-module-loader.js',
|
||||
dest: 'dist/browser-es-module-loader.js',
|
||||
format: 'umd',
|
||||
moduleName: 'BrowserESModuleLoader',
|
||||
sourceMap: true,
|
||||
|
||||
plugins: [
|
||||
nodeResolve(),
|
||||
],
|
||||
|
||||
// skip rollup warnings (specifically the eval warning)
|
||||
onwarn: function() {}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*import { transform as babelTransform } from 'babel-core';
|
||||
import babelTransformDynamicImport from 'babel-plugin-syntax-dynamic-import';
|
||||
import babelTransformES2015ModulesSystemJS from 'babel-plugin-transform-es2015-modules-systemjs';*/
|
||||
|
||||
// sadly, due to how rollup works, we can't use es6 imports here
|
||||
var babelTransform = require('babel-core').transform;
|
||||
var babelTransformDynamicImport = require('babel-plugin-syntax-dynamic-import');
|
||||
var babelTransformES2015ModulesSystemJS = require('babel-plugin-transform-es2015-modules-systemjs');
|
||||
|
||||
self.onmessage = function (evt) {
|
||||
// transform source with Babel
|
||||
var output = babelTransform(evt.data.source, {
|
||||
compact: false,
|
||||
filename: evt.data.key + '!transpiled',
|
||||
sourceFileName: evt.data.key,
|
||||
moduleIds: false,
|
||||
sourceMaps: 'inline',
|
||||
babelrc: false,
|
||||
plugins: [babelTransformDynamicImport, babelTransformES2015ModulesSystemJS],
|
||||
});
|
||||
|
||||
self.postMessage({key: evt.data.key, code: output.code, source: evt.data.source});
|
||||
};
|
||||
@@ -0,0 +1,273 @@
|
||||
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 === 'complete')
|
||||
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) {
|
||||
// We should be the last loaded script
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
current = scripts[scripts.length - 1];
|
||||
}
|
||||
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;
|
||||
Reference in new issue
Block a user