diff --git a/devtools/client/accessibility/panel.js b/devtools/client/accessibility/panel.js index 1e57f2b69a0a..aa4ffdd63732 100644 --- a/devtools/client/accessibility/panel.js +++ b/devtools/client/accessibility/panel.js @@ -50,9 +50,10 @@ const EVENTS = { * render Accessibility Tree of the current debugger target and the sidebar that * displays current relevant accessible details. */ -function AccessibilityPanel(iframeWindow, toolbox) { +function AccessibilityPanel(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this._toolbox = toolbox; + this._commands = commands; this.onTabNavigated = this.onTabNavigated.bind(this); this.onTargetUpdated = this.onTargetUpdated.bind(this); diff --git a/devtools/client/application/panel.js b/devtools/client/application/panel.js index 2165d69f8ed6..a74f01ee253c 100644 --- a/devtools/client/application/panel.js +++ b/devtools/client/application/panel.js @@ -16,10 +16,13 @@ class ApplicationPanel { * The frame/window dedicated to this panel. * @param {Toolbox} toolbox * The toolbox instance responsible for this panel. + * @param {Object} commands + * The commands object with all interfaces defined from devtools/shared/commands/ */ - constructor(panelWin, toolbox) { + constructor(panelWin, toolbox, commands) { this.panelWin = panelWin; this.toolbox = toolbox; + this.commands = commands; } async open() { diff --git a/devtools/client/debugger/panel.js b/devtools/client/debugger/panel.js index 24da5a1aef3a..f30f9ea5fb5a 100644 --- a/devtools/client/debugger/panel.js +++ b/devtools/client/debugger/panel.js @@ -37,10 +37,11 @@ async function getNodeFront(gripOrFront, toolbox) { } class DebuggerPanel { - constructor(iframeWindow, toolbox) { + constructor(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this.panelWin.L10N = L10N; this.toolbox = toolbox; + this.commands = commands; } async open() { diff --git a/devtools/client/definitions.js b/devtools/client/definitions.js index 7074f10f1770..bbd71c229eed 100644 --- a/devtools/client/definitions.js +++ b/devtools/client/definitions.js @@ -125,8 +125,8 @@ Tools.options = { return true; }, - build: function(iframeWindow, toolbox) { - return new OptionsPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new OptionsPanel(iframeWindow, toolbox, commands); }, }; @@ -162,8 +162,8 @@ Tools.inspector = { return target.hasActor("inspector"); }, - build: function(iframeWindow, toolbox) { - return new InspectorPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new InspectorPanel(iframeWindow, toolbox, commands); }, }; Tools.webConsole = { @@ -197,8 +197,8 @@ Tools.webConsole = { isTargetSupported: function() { return true; }, - build: function(iframeWindow, toolbox) { - return new WebConsolePanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new WebConsolePanel(iframeWindow, toolbox, commands); }, }; @@ -221,8 +221,8 @@ Tools.jsdebugger = { isTargetSupported: function() { return true; }, - build: function(iframeWindow, toolbox) { - return new DebuggerPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new DebuggerPanel(iframeWindow, toolbox, commands); }, }; @@ -246,8 +246,8 @@ Tools.styleEditor = { return target.hasActor("styleSheets"); }, - build: function(iframeWindow, toolbox) { - return new StyleEditorPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new StyleEditorPanel(iframeWindow, toolbox, commands); }, }; @@ -274,8 +274,8 @@ function switchPerformancePanel() { ) { Tools.performance.url = "chrome://devtools/content/performance-new/index.xhtml"; - Tools.performance.build = function(frame, target) { - return new NewPerformancePanel(frame, target); + Tools.performance.build = function(frame, toolbox, commands) { + return new NewPerformancePanel(frame, toolbox, commands); }; Tools.performance.isTargetSupported = function(target) { // Only use the new performance panel on local tab toolboxes, as they are guaranteed @@ -287,8 +287,8 @@ function switchPerformancePanel() { }; } else { Tools.performance.url = "chrome://devtools/content/performance/index.xhtml"; - Tools.performance.build = function(frame, target) { - return new PerformancePanel(frame, target); + Tools.performance.build = function(frame, toolbox, commands) { + return new PerformancePanel(frame, toolbox, commands); }; Tools.performance.isTargetSupported = function(target) { return target.hasActor("performance"); @@ -327,8 +327,8 @@ Tools.memory = { return !target.isAddon && !target.isWorkerTarget; }, - build: function(frame, target) { - return new MemoryPanel(frame, target); + build: function(frame, toolbox, commands) { + return new MemoryPanel(frame, toolbox, commands); }, }; @@ -354,8 +354,8 @@ Tools.netMonitor = { return target.getTrait("networkMonitor") && !target.isWorkerTarget; }, - build: function(iframeWindow, toolbox) { - return new NetMonitorPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new NetMonitorPanel(iframeWindow, toolbox, commands); }, }; @@ -381,8 +381,8 @@ Tools.storage = { return target.hasActor("storage"); }, - build: function(iframeWindow, toolbox) { - return new StoragePanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new StoragePanel(iframeWindow, toolbox, commands); }, }; @@ -408,8 +408,8 @@ Tools.dom = { return true; }, - build: function(iframeWindow, toolbox) { - return new DomPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new DomPanel(iframeWindow, toolbox, commands); }, }; @@ -435,8 +435,8 @@ Tools.accessibility = { return target.hasActor("accessibility"); }, - build(iframeWindow, toolbox) { - return new AccessibilityPanel(iframeWindow, toolbox); + build(iframeWindow, toolbox, commands) { + return new AccessibilityPanel(iframeWindow, toolbox, commands); }, }; @@ -455,8 +455,8 @@ Tools.application = { return target.hasActor("manifest"); }, - build: function(iframeWindow, toolbox) { - return new ApplicationPanel(iframeWindow, toolbox); + build: function(iframeWindow, toolbox, commands) { + return new ApplicationPanel(iframeWindow, toolbox, commands); }, }; diff --git a/devtools/client/dom/panel.js b/devtools/client/dom/panel.js index a6110748a5a8..f0059343f9d4 100644 --- a/devtools/client/dom/panel.js +++ b/devtools/client/dom/panel.js @@ -17,9 +17,10 @@ loader.lazyRequireGetter( * This object represents DOM panel. It's responsibility is to * render Document Object Model of the current debugger target. */ -function DomPanel(iframeWindow, toolbox) { +function DomPanel(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this._toolbox = toolbox; + this._commands = commands; this.onTabNavigated = this.onTabNavigated.bind(this); this.onTargetAvailable = this.onTargetAvailable.bind(this); diff --git a/devtools/client/framework/test/browser_tab_descriptor_fission.js b/devtools/client/framework/test/browser_tab_descriptor_fission.js index 06660188d4cd..8463afa2c7f5 100644 --- a/devtools/client/framework/test/browser_tab_descriptor_fission.js +++ b/devtools/client/framework/test/browser_tab_descriptor_fission.js @@ -26,6 +26,15 @@ add_task(async function() { ); ok(tabDescriptor, "Should have a descriptor actor for the tab"); + const firstCommands = await tabDescriptor.getCommands(); + ok(firstCommands, "Got commands"); + const secondCommands = await tabDescriptor.getCommands(); + is( + firstCommands, + secondCommands, + "Multiple calls to getCommands return the same commands object" + ); + is( target.descriptorFront, tabDescriptor, diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index b7c3514d267d..2a3d4ffb48e3 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -237,6 +237,7 @@ function Toolbox( this.telemetry = new Telemetry(); this.descriptorFront = descriptorFront; + this.targetList = new TargetList(descriptorFront); this.targetList.on( "target-thread-wrong-order-on-resume", @@ -778,6 +779,12 @@ Toolbox.prototype = { ); }); + // This attribute is meant to be a public attribute on the Toolbox object + // It exposes commands modules listed in devtools/shared/commands/index.js + // which are an abstraction on top of RDP methods. + // See devtools/shared/commands/README.md + this.commands = await this.descriptorFront.getCommands(); + // Optimization: fire up a few other things before waiting on // the iframe being ready (makes startup faster) await this.targetList.startListening(); @@ -2479,7 +2486,7 @@ Toolbox.prototype = { // be fired with the panel as an argument. However, in order to keep // backward compatibility with existing extensions do a check // for a promise return value. - let built = definition.build(iframe.contentWindow, this); + let built = definition.build(iframe.contentWindow, this, this.commands); if (!(typeof built.then == "function")) { const panel = built; diff --git a/devtools/client/fronts/descriptors/descriptor-mixin.js b/devtools/client/fronts/descriptors/descriptor-mixin.js index 50ed38102c54..64d6a54d763b 100644 --- a/devtools/client/fronts/descriptors/descriptor-mixin.js +++ b/devtools/client/fronts/descriptors/descriptor-mixin.js @@ -4,6 +4,8 @@ "use strict"; +const { createCommandsDictionary } = require("devtools/shared/commands/index"); + /** * A Descriptor represents a debuggable context. It can be a browser tab, a tab on * a remote device, like a tab on Firefox for Android. But it can also be an add-on, @@ -24,6 +26,13 @@ function DescriptorMixin(parentClass) { get client() { return this._client; } + + async getCommands() { + if (!this._commands) { + this._commands = createCommandsDictionary(this); + } + return this._commands; + } } return Descriptor; } diff --git a/devtools/client/inspector/inspector.js b/devtools/client/inspector/inspector.js index 4e79338501d3..4c38f413b7d8 100644 --- a/devtools/client/inspector/inspector.js +++ b/devtools/client/inspector/inspector.js @@ -142,10 +142,11 @@ const TELEMETRY_SCALAR_NODE_SELECTION_COUNT = * Fired when the stylesheet source links have been updated (when switching * to source-mapped files) */ -function Inspector(toolbox) { +function Inspector(toolbox, commands) { EventEmitter.decorate(this); this._toolbox = toolbox; + this._commands = commands; this.panelDoc = window.document; this.panelWin = window; this.panelWin.inspector = this; @@ -284,6 +285,10 @@ Inspector.prototype = { return this._toolbox; }, + get commands() { + return this._commands; + }, + /** * Get the list of InspectorFront instances that correspond to all of the inspectable * targets in remote frames nested within the document inspected here, as well as the diff --git a/devtools/client/inspector/panel.js b/devtools/client/inspector/panel.js index 7f23b58156cc..3b2375b68b52 100644 --- a/devtools/client/inspector/panel.js +++ b/devtools/client/inspector/panel.js @@ -4,8 +4,8 @@ "use strict"; -function InspectorPanel(iframeWindow, toolbox) { - this._inspector = new iframeWindow.Inspector(toolbox); +function InspectorPanel(iframeWindow, toolbox, commands) { + this._inspector = new iframeWindow.Inspector(toolbox, commands); } InspectorPanel.prototype = { open() { diff --git a/devtools/client/memory/panel.js b/devtools/client/memory/panel.js index 71728b300533..bf647b414949 100644 --- a/devtools/client/memory/panel.js +++ b/devtools/client/memory/panel.js @@ -8,9 +8,10 @@ const EventEmitter = require("devtools/shared/event-emitter"); const { Cu } = require("chrome"); const HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient"); -function MemoryPanel(iframeWindow, toolbox) { +function MemoryPanel(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this._toolbox = toolbox; + this._commands = commands; const { BrowserLoader } = Cu.import( "resource://devtools/client/shared/browser-loader.js" diff --git a/devtools/client/netmonitor/panel.js b/devtools/client/netmonitor/panel.js index 5c0af88a0ed0..e047892504fd 100644 --- a/devtools/client/netmonitor/panel.js +++ b/devtools/client/netmonitor/panel.js @@ -4,9 +4,10 @@ "use strict"; -function NetMonitorPanel(iframeWindow, toolbox) { +function NetMonitorPanel(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this.toolbox = toolbox; + this.commands = commands; } NetMonitorPanel.prototype = { diff --git a/devtools/client/performance-new/panel.js b/devtools/client/performance-new/panel.js index 2a6394942abb..317a41cccb91 100644 --- a/devtools/client/performance-new/panel.js +++ b/devtools/client/performance-new/panel.js @@ -21,10 +21,12 @@ class PerformancePanel { /** * @param {PanelWindow} iframeWindow * @param {Toolbox} toolbox + * @param {Object} commands */ - constructor(iframeWindow, toolbox) { + constructor(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this.toolbox = toolbox; + this.commands = commands; const EventEmitter = require("devtools/shared/event-emitter"); EventEmitter.decorate(this); diff --git a/devtools/client/performance/panel.js b/devtools/client/performance/panel.js index 28fef793f027..594825e66a17 100644 --- a/devtools/client/performance/panel.js +++ b/devtools/client/performance/panel.js @@ -5,9 +5,10 @@ loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter"); -function PerformancePanel(iframeWindow, toolbox) { +function PerformancePanel(iframeWindow, toolbox, commands) { this.panelWin = iframeWindow; this.toolbox = toolbox; + this.commands = commands; this._targetAvailablePromise = Promise.resolve(); this._onTargetAvailable = this._onTargetAvailable.bind(this); diff --git a/devtools/client/storage/panel.js b/devtools/client/storage/panel.js index 3e04c7bb548d..41038b85cd37 100644 --- a/devtools/client/storage/panel.js +++ b/devtools/client/storage/panel.js @@ -9,10 +9,11 @@ const EventEmitter = require("devtools/shared/event-emitter"); loader.lazyRequireGetter(this, "StorageUI", "devtools/client/storage/ui", true); class StoragePanel { - constructor(panelWin, toolbox) { + constructor(panelWin, toolbox, commands) { EventEmitter.decorate(this); this._toolbox = toolbox; + this._commands = commands; this._panelWin = panelWin; this.destroy = this.destroy.bind(this); @@ -26,7 +27,7 @@ class StoragePanel { * open is effectively an asynchronous constructor */ async open() { - this.UI = new StorageUI(this._panelWin, this._toolbox); + this.UI = new StorageUI(this._panelWin, this._toolbox, this._commands); await this.UI.init(); diff --git a/devtools/client/storage/ui.js b/devtools/client/storage/ui.js index fbb2f2701166..3b14ed92e41b 100644 --- a/devtools/client/storage/ui.js +++ b/devtools/client/storage/ui.js @@ -109,13 +109,16 @@ const NON_ORIGINAL_L10N_IDS = new Map([ * * @param {Window} panelWin * Window of the toolbox panel to populate UI in. + * @param {Object} commands + * The commands object with all interfaces defined from devtools/shared/commands/ */ class StorageUI { - constructor(panelWin, toolbox) { + constructor(panelWin, toolbox, commands) { EventEmitter.decorate(this); this._window = panelWin; this._panelDoc = panelWin.document; this._toolbox = toolbox; + this._commands = commands; this.sidebarToggledOpen = null; this.shouldLoadMoreItems = true; diff --git a/devtools/client/styleeditor/panel.js b/devtools/client/styleeditor/panel.js index 004d68515ba0..740cbb816ef8 100644 --- a/devtools/client/styleeditor/panel.js +++ b/devtools/client/styleeditor/panel.js @@ -15,10 +15,11 @@ var { getString, } = require("resource://devtools/client/styleeditor/StyleEditorUtil.jsm"); -var StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) { +var StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox, commands) { EventEmitter.decorate(this); this._toolbox = toolbox; + this._commands = commands; this._panelWin = panelWin; this._panelDoc = panelWin.document; diff --git a/devtools/client/webconsole/browser-console-manager.js b/devtools/client/webconsole/browser-console-manager.js index e25e8ad7768f..22f19ec8e624 100644 --- a/devtools/client/webconsole/browser-console-manager.js +++ b/devtools/client/webconsole/browser-console-manager.js @@ -62,7 +62,8 @@ class BrowserConsoleManager { * A promise object for the opening of the new BrowserConsole instance. */ async openBrowserConsole(target, win) { - const hud = new BrowserConsole(target, win, win); + const commands = await target.descriptorFront.getCommands(); + const hud = new BrowserConsole(target, commands, win, win); this._browserConsole = hud; await hud.init(); return hud; diff --git a/devtools/client/webconsole/browser-console.js b/devtools/client/webconsole/browser-console.js index 171bd01a4da2..280c16542f98 100644 --- a/devtools/client/webconsole/browser-console.js +++ b/devtools/client/webconsole/browser-console.js @@ -41,10 +41,11 @@ class BrowserConsole extends WebConsole { * @param nsIDOMWindow chromeWindow * The window of the browser console owner. */ - constructor(target, iframeWindow, chromeWindow) { - super(null, iframeWindow, chromeWindow, true); + constructor(target, commands, iframeWindow, chromeWindow) { + super(null, commands, iframeWindow, chromeWindow, true); this._browserConsoleTarget = target; + this._descriptorFront = target.descriptorFront; this._targetList = new TargetList(target.descriptorFront); this._resourceWatcher = new ResourceWatcher(this._targetList); this._telemetry = new Telemetry(); diff --git a/devtools/client/webconsole/panel.js b/devtools/client/webconsole/panel.js index f456e77501ba..4e376523485a 100644 --- a/devtools/client/webconsole/panel.js +++ b/devtools/client/webconsole/panel.js @@ -16,9 +16,10 @@ loader.lazyGetter(this, "EventEmitter", () => /** * A DevToolPanel that controls the Web Console. */ -function WebConsolePanel(iframeWindow, toolbox) { +function WebConsolePanel(iframeWindow, toolbox, commands) { this._frameWindow = iframeWindow; this._toolbox = toolbox; + this._commands = commands; EventEmitter.decorate(this); } @@ -67,6 +68,7 @@ WebConsolePanel.prototype = { // Open the Web Console. this.hud = new WebConsole( this._toolbox, + this._commands, webConsoleUIWindow, chromeWindow ); diff --git a/devtools/client/webconsole/webconsole.js b/devtools/client/webconsole/webconsole.js index fa19a6331533..12d3f3ebf516 100644 --- a/devtools/client/webconsole/webconsole.js +++ b/devtools/client/webconsole/webconsole.js @@ -54,14 +54,23 @@ class WebConsole { * @constructor * @param object toolbox * The toolbox where the web console is displayed. + * @param object commands + * The commands object with all interfaces defined from devtools/shared/commands/ * @param nsIDOMWindow iframeWindow * The window where the web console UI is already loaded. * @param nsIDOMWindow chromeWindow * The window of the web console owner. * @param bool isBrowserConsole */ - constructor(toolbox, iframeWindow, chromeWindow, isBrowserConsole = false) { + constructor( + toolbox, + commands, + iframeWindow, + chromeWindow, + isBrowserConsole = false + ) { this.toolbox = toolbox; + this.commands = commands; this.iframeWindow = iframeWindow; this.chromeWindow = chromeWindow; this.hudId = "hud_" + ++gHudId; diff --git a/devtools/shared/commands/README.md b/devtools/shared/commands/README.md new file mode 100644 index 000000000000..0cbeda1f2318 --- /dev/null +++ b/devtools/shared/commands/README.md @@ -0,0 +1,46 @@ +# Commands + +Commands are singletons, which can be easily used by any frontend code. +They are meant to be exposed widely to the frontend so that any code can easily call any of their methods. + +Commands classes expose static methods, which: +* route to the right Front/Actor's method +* handle backward compatibility +* map to many target's actor if needed + +These classes are instantiated once per descriptor +and may have inner state, emit events, fire callbacks,... + +A transient backward compat need, required by Fission refactorings will be to have some code checking a trait, and either: +* call a single method on a parent process actor (like BreakpointListActor.setBreakpoint) +* otherwise, call a method on each target's scoped actor (like ThreadActor.setBreakpoint, that, for each available target) + +Without such layer, we would have to put such code here and there in the frontend code. +This will be harder to remove later, once we get rid of old pre-fission-refactoring codepaths. + +This layer already exists in some panels, but we are using slightly different names and practices: +* Debugger uses "client" (devtools/client/debugger/src/client/) and "commands" (devtools/client/debugger/src/client/firefox/commands.js) + Debugger's commands already bundle the code to dispatch an action to many target's actor. + They also contain some backward compat code. + Today, we pass around a `client` object via thunkArgs, which is mapped to commands.js, + instead we could pass a debugger command object. +* Network Monitor uses "connector" (devtools/client/netmonitor/src/connector) + Connectors also bundles backward compat and dispatch to many target's actor. + Today, we pass the `connector` to all middlewares from configureStore, + we could instead pass the netmonitor command object. +* Web Console has: + * WebConsoleConnectionProxy, but this is probably going to disappear and doesn't do much. + * WebConsoleUI, which does dispatch to many target's actor, via getAllProxies (see clearMessagesCache) + * See devtools/client/webconsole/actions/input.js:handleHelperResult(), where we have to put some code, which is a duplicate of Netmonitor Connector, + and could be shared via a netmonitor command class. +* Inspector is probably the panel doing the most dispatch to many target's actor. + Codes using getAllInspectorFronts could all be migrated to an inspector command class: + https://searchfox.org/mozilla-central/search?q=symbol:%23getAllInspectorFronts&redirect=false + and simplify a bit the frontend. + It is also one panel, which still register listener to each target's inspector/walker fronts. + Because inspector isn't using resources. + But this work, registering listeners for each target might be done by such layer and translate the many actor's event into a unified one. + +Last, but not least, this layer may allow us to slowly get rid of protocol.js. +Command classes aren't Fronts, nor are they particularly connected to protocol.js. +If we make it so that all the Frontend code using Fronts uses Commands instead, we might more easily get away from protocol.js. diff --git a/devtools/shared/commands/index.js b/devtools/shared/commands/index.js new file mode 100644 index 000000000000..44a29d3851d4 --- /dev/null +++ b/devtools/shared/commands/index.js @@ -0,0 +1,48 @@ +/* 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/. */ + +"use strict"; + +// List of all command modules +// (please try to keep the list alphabetically sorted) +/*eslint sort-keys: "error"*/ +const Commands = {}; + +/** + * For a given descriptor and its related Targets, already initialized, + * return the dictionary with all command instances. + * This dictionary is lazy and commands will be loaded and instanciated on-demand. + */ +async function createCommandsDictionary(descriptorFront) { + // Bug 1675763: Watcher actor is not available in all situations yet. + let watcherFront; + const supportsWatcher = descriptorFront.traits?.watcher; + if (supportsWatcher) { + watcherFront = await descriptorFront.getWatcher(); + } + const dictionary = {}; + for (const name in Commands) { + loader.lazyGetter(dictionary, name, () => { + const Constructor = require(Commands[name])[name]; + return new Constructor({ + // Commands can use other commands + commands: dictionary, + + // The context to inspect identified by this descriptor + descriptorFront, + + // The front for the Watcher Actor, related to the given descriptor + // This is a key actor to watch for targets and resources and pull global actors running in the parent process + watcherFront, + + // From here, we could pass DevToolsClient, or any useful protocol classes... + // so that we abstract where and how to fetch all necessary interfaces + // and avoid having to know that you might pull the client via descriptorFront.client + }); + }); + } + + return dictionary; +} +exports.createCommandsDictionary = createCommandsDictionary; diff --git a/devtools/shared/commands/moz.build b/devtools/shared/commands/moz.build new file mode 100644 index 000000000000..e1ca52aa96dc --- /dev/null +++ b/devtools/shared/commands/moz.build @@ -0,0 +1,7 @@ +# 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/. + +DevToolsModules( + "index.js", +) diff --git a/devtools/shared/moz.build b/devtools/shared/moz.build index 04d8b0a25b31..048c8937016c 100644 --- a/devtools/shared/moz.build +++ b/devtools/shared/moz.build @@ -9,6 +9,7 @@ include("../templates.mozbuild") DIRS += [ "acorn", "css", + "commands", "compatibility", "discovery", "heapsnapshot",