summaryrefslogtreecommitdiffstats
path: root/toolkit/components/workerloader/require.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/workerloader/require.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/workerloader/require.js')
-rw-r--r--toolkit/components/workerloader/require.js182
1 files changed, 182 insertions, 0 deletions
diff --git a/toolkit/components/workerloader/require.js b/toolkit/components/workerloader/require.js
new file mode 100644
index 0000000000..246c4a1884
--- /dev/null
+++ b/toolkit/components/workerloader/require.js
@@ -0,0 +1,182 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Implementation of a CommonJS module loader for workers.
+ *
+ * Use:
+ * // in the .js file loaded by the constructor of the worker
+ * importScripts("resource://gre/modules/workers/require.js");
+ * let module = require("resource://gre/modules/worker/myModule.js");
+ *
+ * // in myModule.js
+ * // Load dependencies
+ * let SimpleTest = require("resource://gre/modules/workers/SimpleTest.js");
+ * let Logger = require("resource://gre/modules/workers/Logger.js");
+ *
+ * // Define things that will not be exported
+ * let someValue = // ...
+ *
+ * // Export symbols
+ * exports.foo = // ...
+ * exports.bar = // ...
+ *
+ *
+ * Note #1:
+ * Properties |fileName| and |stack| of errors triggered from a module
+ * contain file names that do not correspond to human-readable module paths.
+ * Human readers should rather use properties |moduleName| and |moduleStack|.
+ *
+ * Note #2:
+ * By opposition to some other module loader implementations, this module
+ * loader does not enforce separation of global objects. Consequently, if
+ * a module modifies a global object (e.g. |String.prototype|), all other
+ * modules in the same worker may be affected.
+ */
+
+/* global require */
+/* exported require */
+
+(function (exports) {
+ "use strict";
+
+ if (exports.require) {
+ // Avoid double-imports
+ return;
+ }
+
+ // Simple implementation of |require|
+ let require = (function () {
+ /**
+ * Mapping from module URI to module exports.
+ *
+ * @keys {string} The absolute URI to a module.
+ * @values {object} The |exports| objects for that module.
+ */
+ let modules = new Map();
+
+ /**
+ * A human-readable version of |stack|.
+ *
+ * @type {string}
+ */
+ Object.defineProperty(Error.prototype, "moduleStack", {
+ get() {
+ return this.stack;
+ },
+ });
+ /**
+ * A human-readable version of |fileName|.
+ *
+ * @type {string}
+ */
+ Object.defineProperty(Error.prototype, "moduleName", {
+ get() {
+ let match = this.stack.match(/\@(.*):.*:/);
+ if (match) {
+ return match[1];
+ }
+ return "(unknown module)";
+ },
+ });
+
+ /**
+ * Import a module
+ *
+ * @param {string} baseURL The URL of the modules from which we load a new module.
+ * This will be null for the first loaded module and so expect an absolute URI in path.
+ * Note that this first parameter is bound before `require` method is passed outside
+ * of this module. So that typical callsites will only path the second `path` parameter.
+ * @param {string} path The path to the module.
+ * @return {*} An object containing the properties exported by the module.
+ */
+ return function require(baseURL, path) {
+ let startTime = performance.now();
+ if (typeof path != "string") {
+ throw new TypeError(
+ "The argument to require() must be a string got " + path
+ );
+ }
+
+ // Resolve relative paths
+ if ((path.startsWith("./") || path.startsWith("../")) && baseURL) {
+ path = new URL(path, baseURL).href;
+ }
+
+ if (!path.includes("://")) {
+ throw new TypeError(
+ "The argument to require() must be a string uri, got " + path
+ );
+ }
+ // Automatically add ".js" if there is no extension
+ let uri;
+ if (path.lastIndexOf(".") <= path.lastIndexOf("/")) {
+ uri = path + ".js";
+ } else {
+ uri = path;
+ }
+
+ // Exports provided by the module
+ let exports = Object.create(null);
+
+ // Identification of the module
+ let module = {
+ id: path,
+ uri,
+ exports,
+ };
+
+ // Make module available immediately
+ // (necessary in case of circular dependencies)
+ if (modules.has(uri)) {
+ return modules.get(uri).exports;
+ }
+ modules.set(uri, module);
+
+ try {
+ // Load source of module, synchronously
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", uri, false);
+ xhr.responseType = "text";
+ xhr.send();
+
+ let source = xhr.responseText;
+ if (source == "") {
+ // There doesn't seem to be a better way to detect that the file couldn't be found
+ throw new Error("Could not find module " + path);
+ }
+ // Use `Function` to leave this scope, use `eval` to start the line
+ // number from 1 that is observed by `source` and the error message
+ // thrown from the module, and also use `arguments` for accessing
+ // `source` and `uri` to avoid polluting the module's environment.
+ let code = new Function(
+ "exports",
+ "require",
+ "module",
+ `eval(arguments[3] + "\\n//# sourceURL=" + arguments[4] + "\\n")`
+ );
+ code(exports, require.bind(null, path), module, source, uri);
+ } catch (ex) {
+ // Module loading has failed, exports should not be made available
+ // after all.
+ modules.delete(uri);
+ throw ex;
+ } finally {
+ ChromeUtils.addProfilerMarker("require", startTime, path);
+ }
+
+ Object.freeze(module.exports);
+ Object.freeze(module);
+ return module.exports;
+ };
+ })();
+
+ Object.freeze(require);
+
+ Object.defineProperty(exports, "require", {
+ value: require.bind(null, null),
+ enumerable: true,
+ configurable: false,
+ });
+})(this);