diff --git a/app/error-handler.js b/app/error-handler.js
new file mode 100644
index 00000000..30f77068
--- /dev/null
+++ b/app/error-handler.js
@@ -0,0 +1,61 @@
+// NB: this should *not* be included as a module until we have
+// native support in the browsers, so that our error handler
+// can catch script-loading errors.
+
+
+(function(){
+ "use strict";
+
+ function convertNewlines(msg, parentElem) {
+ const lines = msg.split("\n");
+ lines.forEach(function (line) {
+ parentElem.appendChild(document.createElement("br"));
+ parentElem.appendChild(document.createTextNode(line));
+ });
+ parentElem.removeChild(parentElem.firstChild);
+ return parentElem;
+ }
+
+ // Fallback for all uncought errors
+ function handleError (event, err) {
+ try {
+ const msg = document.getElementById('noVNC_fallback_errormsg');
+
+ // Only show the initial error
+ if (msg.hasChildNodes()) {
+ return false;
+ }
+
+ var div = document.createElement("div");
+ div.classList.add('noVNC_message');
+ convertNewlines(event.message, div);
+ msg.appendChild(div);
+
+ if (event.filename !== undefined && event.lineno !== undefined && event.colno !== undefined) {
+ div = document.createElement("div");
+ div.className = 'noVNC_location';
+ const text = event.filename + ":" + event.lineno + ":" + event.colno;
+ div.appendChild(document.createTextNode(text));
+ msg.appendChild(div);
+ }
+
+ if ((err !== undefined) &&
+ (err.stack !== undefined)) {
+ div = document.createElement("div");
+ div.className = 'noVNC_stack';
+ div.appendChild(document.createTextNode(err.stack));
+ msg.appendChild(div);
+ }
+
+ document.getElementById('noVNC_fallback_error')
+ .classList.add("noVNC_open");
+ } catch (exc) {
+ document.write("noVNC encountered an error.");
+ }
+ // Don't return true since this would prevent the error
+ // from being printed to the browser console.
+ return false;
+ }
+ window.addEventListener('error', function (evt) { handleError(evt, evt.error); });
+ window.addEventListener('unhandledrejection', function (evt) { handleError(evt.reason, evt.reason); });
+})();
diff --git a/app/styles/base.css b/app/styles/base.css
index 4cec1735..30146963 100644
--- a/app/styles/base.css
+++ b/app/styles/base.css
@@ -247,6 +247,11 @@ select:active {
font-weight: normal;
}
+#noVNC_fallback_errormsg .noVNC_message {
+ display: inline-block;
+ text-align: left;
+}
+
#noVNC_fallback_error .noVNC_location {
font-style: italic;
font-size: 0.8em;
diff --git a/app/ui.js b/app/ui.js
index d59204c8..46826221 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -21,46 +21,6 @@ import RFB from "../core/rfb.js";
import Display from "../core/display.js";
import * as WebUtil from "./webutil.js";
-// Fallback for all uncought errors
-window.addEventListener('error', function(event) {
- try {
- var msg, div, text;
-
- msg = document.getElementById('noVNC_fallback_errormsg');
-
- // Only show the initial error
- if (msg.hasChildNodes()) {
- return false;
- }
-
- div = document.createElement("div");
- div.appendChild(document.createTextNode(event.message));
- msg.appendChild(div);
-
- div = document.createElement("div");
- div.className = 'noVNC_location';
- text = event.filename + ":" + event.lineno + ":" + event.colno;
- div.appendChild(document.createTextNode(text));
- msg.appendChild(div);
-
- if ((event.error !== undefined) &&
- (event.error.stack !== undefined)) {
- div = document.createElement("div");
- div.className = 'noVNC_stack';
- div.appendChild(document.createTextNode(event.error.stack));
- msg.appendChild(div);
- }
-
- document.getElementById('noVNC_fallback_error')
- .classList.add("noVNC_open");
- } catch (exc) {
- document.write("noVNC encountered an error.");
- }
- // Don't return true since this would prevent the error
- // from being printed to the browser console.
- return false;
-});
-
const UI = {
connected: false,
@@ -1751,11 +1711,10 @@ if (l10n.language !== "en" && l10n.dictionary === undefined) {
// wait for translations to load before loading the UI
UI.prime();
}, function (err) {
- throw err;
+ throw err;
});
} else {
UI.prime();
}
-
export default UI;
diff --git a/utils/use_require.js b/utils/use_require.js
index bfa14f6f..f0383d09 100755
--- a/utils/use_require.js
+++ b/utils/use_require.js
@@ -21,6 +21,17 @@ var vendor_path = path.resolve(__dirname, '..', 'vendor');
var out_dir_base = path.resolve(__dirname, '..', 'build');
var lib_dir_base = path.resolve(__dirname, '..', 'lib');
+const no_copy_files = new Set([
+ // skip these -- they don't belong in the processed application
+ path.join(vendor_path, 'sinon.js'),
+ path.join(vendor_path, 'browser-es-module-loader'),
+]);
+
+const no_transform_files = new Set([
+ // don't transform this -- we want it imported as-is to properly catch loading errors
+ path.join(app_path, 'error-handler.js'),
+]);
+
// walkDir *recursively* walks directories trees,
// calling the callback for all normal files found.
var walkDir = function (base_path, cb, filter) {
@@ -93,6 +104,8 @@ var make_lib_files = function (import_format, source_maps, with_app_dir) {
const helper = helpers[import_format];
var handleDir = (js_only, in_path_base, filename) => {
+ if (no_copy_files.has(filename)) return;
+
const out_path = path.join(out_path_base, path.relative(in_path_base, filename));
if(path.extname(filename) !== '.js') {
if (!js_only) {
@@ -103,10 +116,17 @@ var make_lib_files = function (import_format, source_maps, with_app_dir) {
}
fse.ensureDir(path.dirname(out_path), () => {
+ if (no_transform_files.has(filename)) {
+ console.log(`Writing ${out_path}`);
+ fse.copy(filename, out_path, (err) => { if (err) throw err; });
+ return;
+ }
+
const opts = babel_opts();
if (helper && helpers.optionsOverride) {
helper.optionsOverride(opts);
}
+
babel.transformFile(filename, babel_opts(), (err, res) => {
console.log(`Writing ${out_path}`);
if (err) throw err;
@@ -124,11 +144,11 @@ var make_lib_files = function (import_format, source_maps, with_app_dir) {
});
};
- walkDir(core_path, handleDir.bind(null, true, in_path || core_path));
- walkDir(vendor_path, handleDir.bind(null, true, in_path || main_path), (filepath, stats) => !((stats.isDirectory() && path.basename(filepath) === 'browser-es-module-loader') || path.basename(filepath) === 'sinon.js'));
+ walkDir(core_path, handleDir.bind(null, true, in_path || core_path), (filename, stats) => !no_copy_files.has(filename));
+ walkDir(vendor_path, handleDir.bind(null, true, in_path || main_path), (filename, stats) => !no_copy_files.has(filename));
if (with_app_dir) {
- walkDir(app_path, handleDir.bind(null, false, in_path || app_path));
+ walkDir(app_path, handleDir.bind(null, false, in_path || app_path), (filename, stats) => !no_copy_files.has(filename));
const out_app_path = path.join(out_path_base, 'app.js');
if (helper && helper.appWriter) {
diff --git a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
index 3d123da6..0d22bab2 100644
--- a/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/dist/browser-es-module-loader.js
@@ -1180,7 +1180,22 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
if (script.type == 'module' && !script.loaded) {
script.loaded = true;
if (script.src) {
- loader.import(script.src);
+ loader.import(script.src).catch(function(err) {
+ // dispatch an error event so that we can display in errors in browsers
+ // that don't yet support unhandledrejection
+ try {
+ var evt = new Event('error');
+ } catch (_eventError) {
+ var evt = document.createEvent('Event');
+ evt.initEvent('error', true, true);
+ }
+ evt.message = err.message;
+ evt.error = err;
+ window.dispatchEvent(evt);
+
+ // throw so it still shows up in the console
+ throw err;
+ });
}
// anonymous modules supported via a custom naming scheme and registry
else {
@@ -1191,7 +1206,22 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
var anonName = resolveIfNotPlain(uri, baseURI);
anonSources[anonName] = script.innerHTML;
- loader.import(anonName);
+ loader.import(anonName).catch(function(err) {
+ // dispatch an error event so that we can display in errors in browsers
+ // that don't yet support unhandledrejection
+ try {
+ var evt = new Event('error');
+ } catch (_eventError) {
+ var evt = document.createEvent('Event');
+ evt.initEvent('error', true, true);
+ }
+ evt.message = err.message;
+ evt.error = err;
+ window.dispatchEvent(evt);
+
+ // throw so it still shows up in the console
+ throw err;
+ });
}
}
}
diff --git a/vendor/browser-es-module-loader/src/browser-es-module-loader.js b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
index 9ba7c36e..a9d72097 100644
--- a/vendor/browser-es-module-loader/src/browser-es-module-loader.js
+++ b/vendor/browser-es-module-loader/src/browser-es-module-loader.js
@@ -20,7 +20,22 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
if (script.type == 'module' && !script.loaded) {
script.loaded = true;
if (script.src) {
- loader.import(script.src);
+ loader.import(script.src).catch(function(err) {
+ // dispatch an error event so that we can display in errors in browsers
+ // that don't yet support unhandledrejection
+ try {
+ var evt = new Event('error');
+ } catch (_eventError) {
+ var evt = document.createEvent('Event');
+ evt.initEvent('error', true, true);
+ }
+ evt.message = err.message;
+ evt.error = err;
+ window.dispatchEvent(evt);
+
+ // throw so it still shows up in the console
+ throw err;
+ });
}
// anonymous modules supported via a custom naming scheme and registry
else {
@@ -31,7 +46,22 @@ if (typeof document != 'undefined' && document.getElementsByTagName) {
var anonName = resolveIfNotPlain(uri, baseURI);
anonSources[anonName] = script.innerHTML;
- loader.import(anonName);
+ loader.import(anonName).catch(function(err) {
+ // dispatch an error event so that we can display in errors in browsers
+ // that don't yet support unhandledrejection
+ try {
+ var evt = new Event('error');
+ } catch (_eventError) {
+ var evt = document.createEvent('Event');
+ evt.initEvent('error', true, true);
+ }
+ evt.message = err.message;
+ evt.error = err;
+ window.dispatchEvent(evt);
+
+ // throw so it still shows up in the console
+ throw err;
+ });
}
}
}
diff --git a/vnc.html b/vnc.html
index b4f43e73..10cc1430 100644
--- a/vnc.html
+++ b/vnc.html
@@ -59,6 +59,9 @@
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'>
-->
+
+
+