tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit ad0ae2c01b2fcd3f159d45e3733ddb53cc551af1
parent 1e90610dee834dc9aa17c036ab8b578f2e47c0a8
Author: Lorenz A <me@lorenzackermann.xyz>
Date:   Thu, 11 Dec 2025 07:07:47 +0000

Bug 2004233 - [devtools] Turn devtools/shared/loader/browser-loader.sys.mjs into an ES class. r=devtools-reviewers,bomsy

Differential Revision: https://phabricator.services.mozilla.com/D275636

Diffstat:
Mdevtools/shared/loader/browser-loader.sys.mjs | 232++++++++++++++++++++++++++++++++++++++-----------------------------------------
1 file changed, 113 insertions(+), 119 deletions(-)

diff --git a/devtools/shared/loader/browser-loader.sys.mjs b/devtools/shared/loader/browser-loader.sys.mjs @@ -69,6 +69,23 @@ const browserBasedDirsRegExp = /^resource\:\/\/devtools\/client\/\S*\/components\//; /** + * @typedef {object} BrowserLoaderOptions + * @property {string} baseURI + * Base path to load modules from. If null or undefined, only + * the shared vendor/components modules are loaded with the browser + * loader. + * @property {Function} commonLibRequire + * Require function that should be used to load common libraries, like React. + * Allows for sharing common modules between tools, instead of loading a new + * instance into each tool. For example, pass "toolbox.browserRequire" here. + * @property {boolean} useOnlyShared + * If true, ignores `baseURI` and only loads the shared + * BROWSER_BASED_DIRS via BrowserLoader. + * @property {Window} window + * The window instance to evaluate modules within + */ + +/** * Create a loader to be used in a browser environment. This evaluates * modules in their own environment, but sets window (the normal * global object) as the sandbox prototype, so when a variable is not @@ -84,15 +101,7 @@ const browserBasedDirsRegExp = * `devtools/client/shared/{vendor/components}`, which is where shared libraries * and React components live that should be evaluated in a browser environment. * - * @param string baseURI - * Base path to load modules from. If null or undefined, only - * the shared vendor/components modules are loaded with the browser - * loader. - * @param Object window - * The window instance to evaluate modules within - * @param Boolean useOnlyShared - * If true, ignores `baseURI` and only loads the shared - * BROWSER_BASED_DIRS via BrowserLoader. + * @param {BrowserLoaderOptions} options * @return Object * An object with two properties: * - loader: the Loader instance @@ -110,129 +119,114 @@ export function BrowserLoader(options) { /** * Private class used to build the Loader instance and require method returned * by BrowserLoader(baseURI, window). - * - * @param string baseURI - * Base path to load modules from. - * @param Function commonLibRequire - * Require function that should be used to load common libraries, like React. - * Allows for sharing common modules between tools, instead of loading a new - * instance into each tool. For example, pass "toolbox.browserRequire" here. - * @param Boolean useOnlyShared - * If true, ignores `baseURI` and only loads the shared - * BROWSER_BASED_DIRS via BrowserLoader. - * @param Object window - * The window instance to evaluate modules within */ -function BrowserLoaderBuilder({ - baseURI, - commonLibRequire, - useOnlyShared, - window, -}) { - assert( - !!baseURI !== !!useOnlyShared, - "Cannot use both `baseURI` and `useOnlyShared`." - ); +class BrowserLoaderBuilder { + /** + * @param {BrowserLoaderOptions} options + */ + constructor({ baseURI, commonLibRequire, useOnlyShared, window }) { + assert( + !!baseURI !== !!useOnlyShared, + "Cannot use both `baseURI` and `useOnlyShared`." + ); - const loaderOptions = devtoolsRequire("@loader/options"); + const loaderOptions = devtoolsRequire("@loader/options"); - const opts = { - sandboxPrototype: window, - sandboxName: "DevTools (UI loader)", - paths: loaderOptions.paths, - // Make sure `define` function exists. This allows defining some modules - // in AMD format while retaining CommonJS compatibility through this hook. - // JSON Viewer needs modules in AMD format, as it currently uses RequireJS - // from a content document and can't access our usual loaders. So, any - // modules shared with the JSON Viewer should include a define wrapper: - // - // // Make this available to both AMD and CJS environments - // define(function(require, exports, module) { - // ... code ... - // }); - // - // Bug 1248830 will work out a better plan here for our content module - // loading needs, especially as we head towards devtools.html. - supportAMDModules: true, - requireHook: (id, require) => { - // If |id| requires special handling, simply defer to devtools - // immediately. - if (loader.isLoaderPluginId(id)) { - return devtoolsRequire(id); - } + const opts = { + sandboxPrototype: window, + sandboxName: "DevTools (UI loader)", + paths: loaderOptions.paths, + // Make sure `define` function exists. This allows defining some modules + // in AMD format while retaining CommonJS compatibility through this hook. + // JSON Viewer needs modules in AMD format, as it currently uses RequireJS + // from a content document and can't access our usual loaders. So, any + // modules shared with the JSON Viewer should include a define wrapper: + // + // // Make this available to both AMD and CJS environments + // define(function(require, exports, module) { + // ... code ... + // }); + // + // Bug 1248830 will work out a better plan here for our content module + // loading needs, especially as we head towards devtools.html. + supportAMDModules: true, + requireHook: (id, require) => { + // If |id| requires special handling, simply defer to devtools + // immediately. + if (loader.isLoaderPluginId(id)) { + return devtoolsRequire(id); + } - let uri = require.resolve(id); + let uri = require.resolve(id); - // The mocks can be set from tests using browser-loader-mocks.js setMockedModule(). - // If there is an entry for a given uri in the `mocks` object, return it instead of - // requiring the module. - if (flags.testing && lazy.getMockedModule(uri)) { - return lazy.getMockedModule(uri); - } + // The mocks can be set from tests using browser-loader-mocks.js setMockedModule(). + // If there is an entry for a given uri in the `mocks` object, return it instead of + // requiring the module. + if (flags.testing && lazy.getMockedModule(uri)) { + return lazy.getMockedModule(uri); + } - // Load all React modules as ES Modules, in the Browser Loader global. - // For this we have to ensure using ChromeUtils.importESModule with `global:"current"`, - // but executed from the Loader global scope. `syncImport` does that. - if (REACT_ESM_MODULES.has(uri)) { - uri = uri.replace(/.js$/, ".mjs"); - const moduleExports = syncImport(uri); - return moduleExports.default || moduleExports; - } - if (uri.endsWith(".mjs")) { - const moduleExports = syncImport(uri); - return moduleExports.default || moduleExports; - } + // Load all React modules as ES Modules, in the Browser Loader global. + // For this we have to ensure using ChromeUtils.importESModule with `global:"current"`, + // but executed from the Loader global scope. `syncImport` does that. + if (REACT_ESM_MODULES.has(uri)) { + uri = uri.replace(/.js$/, ".mjs"); + const moduleExports = syncImport(uri); + return moduleExports.default || moduleExports; + } + if (uri.endsWith(".mjs")) { + const moduleExports = syncImport(uri); + return moduleExports.default || moduleExports; + } - if ( - commonLibRequire && - COMMON_LIBRARY_DIRS.some(dir => uri.startsWith(dir)) - ) { - return commonLibRequire(uri); - } + if ( + commonLibRequire && + COMMON_LIBRARY_DIRS.some(dir => uri.startsWith(dir)) + ) { + return commonLibRequire(uri); + } - // Check if the URI matches one of hardcoded paths or a regexp. - const isBrowserDir = - BROWSER_BASED_DIRS.some(dir => uri.startsWith(dir)) || - uri.match(browserBasedDirsRegExp) != null; + // Check if the URI matches one of hardcoded paths or a regexp. + const isBrowserDir = + BROWSER_BASED_DIRS.some(dir => uri.startsWith(dir)) || + uri.match(browserBasedDirsRegExp) != null; - if ((useOnlyShared || !uri.startsWith(baseURI)) && !isBrowserDir) { - return devtoolsRequire(uri); - } + if ((useOnlyShared || !uri.startsWith(baseURI)) && !isBrowserDir) { + return devtoolsRequire(uri); + } - return require(uri); - }, - globals: { - // Allow modules to use the window's console to ensure logs appear in a - // tab toolbox, if one exists, instead of just the browser console. - console: window.console, - // Allow modules to use the DevToolsLoader lazy loading helpers. - loader: { - lazyGetter: loader.lazyGetter, - lazyServiceGetter: loader.lazyServiceGetter, - lazyRequireGetter: this.lazyRequireGetter.bind(this), + return require(uri); }, - }, - }; + globals: { + // Allow modules to use the window's console to ensure logs appear in a + // tab toolbox, if one exists, instead of just the browser console. + console: window.console, + // Allow modules to use the DevToolsLoader lazy loading helpers. + loader: { + lazyGetter: loader.lazyGetter, + lazyServiceGetter: loader.lazyServiceGetter, + lazyRequireGetter: this.lazyRequireGetter.bind(this), + }, + }, + }; - const mainModule = BaseLoader.Module(baseURI, joinURI(baseURI, "main.js")); - this.loader = BaseLoader.Loader(opts); + const mainModule = BaseLoader.Module(baseURI, joinURI(baseURI, "main.js")); + this.loader = BaseLoader.Loader(opts); - const scope = this.loader.sharedGlobal; - Cu.evalInSandbox( - "function __syncImport(uri) { return ChromeUtils.importESModule(uri, {global: 'current'})}", - scope - ); - const syncImport = scope.__syncImport; + const scope = this.loader.sharedGlobal; + Cu.evalInSandbox( + "function __syncImport(uri) { return ChromeUtils.importESModule(uri, {global: 'current'})}", + scope + ); + const syncImport = scope.__syncImport; - // When running tests, expose the BrowserLoader instance for metrics tests. - if (flags.testing) { - window.getBrowserLoaderForWindow = () => this; + // When running tests, expose the BrowserLoader instance for metrics tests. + if (flags.testing) { + window.getBrowserLoaderForWindow = () => this; + } + this.require = BaseLoader.Require(this.loader, mainModule); + this.lazyRequireGetter = this.lazyRequireGetter.bind(this); } - this.require = BaseLoader.Require(this.loader, mainModule); - this.lazyRequireGetter = this.lazyRequireGetter.bind(this); -} - -BrowserLoaderBuilder.prototype = { /** * Define a getter property on the given object that requires the given * module. This enables delaying importing modules until the module is @@ -270,5 +264,5 @@ BrowserLoaderBuilder.prototype = { : this.require(module || property); }); } - }, -}; + } +}