Bug 1460843 - Console clean up: split hudservice.js; r=nchevobbe draft
authorJan Odvarko <odvarko@gmail.com>
Mon, 02 Jul 2018 17:08:02 +0200
changeset 813144 ba39dc03456759368c42842beddba59596bb44ff
parent 812962 3cfc350101967376909ad3c729f9779ae0ab7a94
push id114793
push userjodvarko@mozilla.com
push dateMon, 02 Jul 2018 15:08:50 +0000
reviewersnchevobbe
bugs1460843
milestone63.0a1
Bug 1460843 - Console clean up: split hudservice.js; r=nchevobbe MozReview-Commit-ID: 41ZUhbk1fBY
devtools/client/webconsole/browser-console.js
devtools/client/webconsole/hudservice.js
devtools/client/webconsole/moz.build
devtools/client/webconsole/webconsole.js
copy from devtools/client/webconsole/hudservice.js
copy to devtools/client/webconsole/browser-console.js
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/browser-console.js
@@ -1,572 +1,45 @@
 /* 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";
 
 var Services = require("Services");
-loader.lazyRequireGetter(this, "Utils", "devtools/client/webconsole/utils", true);
 loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true);
-loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
-loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true);
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
-loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole-frame", true);
-loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
-loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
-loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
-loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
-loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/webconsole-l10n");
-loader.lazyRequireGetter(this, "openDocLink", "devtools/client/shared/link", true);
-const BC_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
+loader.lazyRequireGetter(this, "WebConsole", "devtools/client/webconsole/webconsole");
 
 // The preference prefix for all of the Browser Console filters.
 const BC_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
-var gHudId = 0;
-
-function HUD_SERVICE() {
-  this.consoles = new Map();
-  this.lastFinishedRequest = { callback: null };
-}
-
-HUD_SERVICE.prototype =
-{
-  _browserConsoleID: null,
-  _browserConsoleInitializing: null,
-
-  /**
-   * Keeps a reference for each Web Console / Browser Console that is created.
-   * @type Map
-   */
-  consoles: null,
-
-  _browerConsoleSessionState: false,
-  storeBrowserConsoleSessionState() {
-    this._browerConsoleSessionState = !!this.getBrowserConsole();
-  },
-  getBrowserConsoleSessionState() {
-    return this._browerConsoleSessionState;
-  },
-
-  /**
-   * Assign a function to this property to listen for every request that
-   * completes. Used by unit tests. The callback takes one argument: the HTTP
-   * activity object as received from the remote Web Console.
-   *
-   * @type object
-   *       Includes a property named |callback|. Assign the function to the
-   *       |callback| property of this object.
-   */
-  lastFinishedRequest: null,
-
-  /**
-   * Get the current context, which is the main application window.
-   *
-   * @returns nsIDOMWindow
-   */
-  currentContext() {
-    return Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
-  },
-
-  /**
-   * Open a Web Console for the given target.
-   *
-   * @see devtools/framework/target.js for details about targets.
-   *
-   * @param object target
-   *        The target that the web console will connect to.
-   * @param nsIDOMWindow iframeWindow
-   *        The window where the web console UI is already loaded.
-   * @param nsIDOMWindow chromeWindow
-   *        The window of the web console owner.
-   * @return object
-   *         A promise object for the opening of the new WebConsole instance.
-   */
-  openWebConsole(target, iframeWindow, chromeWindow) {
-    const hud = new WebConsole(target, iframeWindow, chromeWindow);
-    this.consoles.set(hud.hudId, hud);
-    return hud.init();
-  },
-
-  /**
-   * Open a Browser Console for the given target.
-   *
-   * @see devtools/framework/target.js for details about targets.
-   *
-   * @param object target
-   *        The target that the browser console will connect to.
-   * @param nsIDOMWindow iframeWindow
-   *        The window where the browser console UI is already loaded.
-   * @param nsIDOMWindow chromeWindow
-   *        The window of the browser console owner.
-   * @return object
-   *         A promise object for the opening of the new BrowserConsole instance.
-   */
-  openBrowserConsole(target, iframeWindow, chromeWindow) {
-    const hud = new BrowserConsole(target, iframeWindow, chromeWindow);
-    this._browserConsoleID = hud.hudId;
-    this.consoles.set(hud.hudId, hud);
-    return hud.init();
-  },
-
-  /**
-   * Returns the Web Console object associated to a content window.
-   *
-   * @param nsIDOMWindow contentWindow
-   * @returns object
-   */
-  getHudByWindow(contentWindow) {
-    for (const [, hud] of this.consoles) {
-      const target = hud.target;
-      if (target && target.tab && target.window === contentWindow) {
-        return hud;
-      }
-    }
-    return null;
-  },
-
-  /**
-   * Returns the console instance for a given id.
-   *
-   * @param string id
-   * @returns Object
-   */
-  getHudReferenceById(id) {
-    return this.consoles.get(id);
-  },
-
-  /**
-   * Find if there is a Web Console open for the current tab and return the
-   * instance.
-   * @return object|null
-   *         The WebConsole object or null if the active tab has no open Web
-   *         Console.
-   */
-  getOpenWebConsole() {
-    const tab = this.currentContext().gBrowser.selectedTab;
-    if (!tab || !TargetFactory.isKnownTab(tab)) {
-      return null;
-    }
-    const target = TargetFactory.forTab(tab);
-    const toolbox = gDevTools.getToolbox(target);
-    const panel = toolbox ? toolbox.getPanel("webconsole") : null;
-    return panel ? panel.hud : null;
-  },
-
-  /**
-   * Toggle the Browser Console.
-   */
-  async toggleBrowserConsole() {
-    if (this._browserConsoleID) {
-      const hud = this.getHudReferenceById(this._browserConsoleID);
-      return hud.destroy();
-    }
-
-    if (this._browserConsoleInitializing) {
-      return this._browserConsoleInitializing;
-    }
-
-    async function connect() {
-      // Ensure that the root actor and the target-scoped actors have been registered on
-      // the DebuggerServer, so that the Browser Console can retrieve the console actors.
-      // (See Bug 1416105 for rationale).
-      DebuggerServer.init();
-      DebuggerServer.registerActors({ root: true, target: true });
-
-      DebuggerServer.allowChromeProcess = true;
-
-      const client = new DebuggerClient(DebuggerServer.connectPipe());
-      await client.connect();
-      const response = await client.getProcess();
-      return { form: response.form, client, chrome: true, isBrowsingContext: true };
-    }
-
-    async function openWindow(t) {
-      const win = Services.ww.openWindow(null, Tools.webConsole.browserConsoleURL,
-                                       "_blank", BC_WINDOW_FEATURES, null);
-      let iframeWindow = win;
-
-      await new Promise(resolve => {
-        win.addEventListener("DOMContentLoaded", resolve, {once: true});
-      });
-
-      win.document.title = l10n.getStr("browserConsole.title");
-
-      // With a XUL wrapper doc, we host index.html in an iframe.
-      // Wait for that to be ready before resolving:
-      if (!Tools.webConsole.browserConsoleUsesHTML) {
-        const iframe = win.document.querySelector("iframe");
-        await new Promise(resolve => {
-          iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
-        });
-        iframeWindow = iframe.contentWindow;
-      }
-
-      return {iframeWindow, chromeWindow: win};
-    }
-
-    // Temporarily cache the async startup sequence so that if toggleBrowserConsole
-    // gets called again we can return this console instead of opening another one.
-    this._browserConsoleInitializing = (async () => {
-      const connection = await connect();
-      const target = await TargetFactory.forRemoteTab(connection);
-      const {iframeWindow, chromeWindow} = await openWindow(target);
-      const browserConsole =
-        await this.openBrowserConsole(target, iframeWindow, chromeWindow);
-      return browserConsole;
-    })();
-
-    const browserConsole = await this._browserConsoleInitializing;
-    this._browserConsoleInitializing = null;
-    return browserConsole;
-  },
-
-  /**
-   * Opens or focuses the Browser Console.
-   */
-  openBrowserConsoleOrFocus() {
-    const hud = this.getBrowserConsole();
-    if (hud) {
-      hud.iframeWindow.focus();
-      return Promise.resolve(hud);
-    }
-
-    return this.toggleBrowserConsole();
-  },
-
-  /**
-   * Get the Browser Console instance, if open.
-   *
-   * @return object|null
-   *         A BrowserConsole instance or null if the Browser Console is not
-   *         open.
-   */
-  getBrowserConsole() {
-    return this.getHudReferenceById(this._browserConsoleID);
-  },
-};
-
-/**
- * A WebConsole instance is an interactive console initialized *per target*
- * that displays console log data as well as provides an interactive terminal to
- * manipulate the target's document content.
- *
- * This object only wraps the iframe that holds the Web Console UI. This is
- * meant to be an integration point between the Firefox UI and the Web Console
- * UI and features.
- *
- * @constructor
- * @param object target
- *        The target that the web console will connect to.
- * @param nsIDOMWindow iframeWindow
- *        The window where the web console UI is already loaded.
- * @param nsIDOMWindow chromeWindow
- *        The window of the web console owner.
- */
-function WebConsole(target, iframeWindow, chromeWindow) {
-  this.iframeWindow = iframeWindow;
-  this.chromeWindow = chromeWindow;
-  this.hudId = "hud_" + ++gHudId;
-  this.target = target;
-  this.browserWindow = this.chromeWindow.top;
-  const element = this.browserWindow.document.documentElement;
-  if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
-    this.browserWindow = HUDService.currentContext();
-  }
-  this.ui = new WebConsoleFrame(this);
-}
-WebConsole.prototype = {
-  iframeWindow: null,
-  chromeWindow: null,
-  browserWindow: null,
-  hudId: null,
-  target: null,
-  ui: null,
-  _browserConsole: false,
-  _destroyer: null,
-
-  /**
-   * Getter for a function to to listen for every request that completes. Used
-   * by unit tests. The callback takes one argument: the HTTP activity object as
-   * received from the remote Web Console.
-   *
-   * @type function
-   */
-  get lastFinishedRequestCallback() {
-    return HUDService.lastFinishedRequest.callback;
-  },
-
-  /**
-   * Getter for the window that can provide various utilities that the web
-   * console makes use of, like opening links, managing popups, etc.  In
-   * most cases, this will be |this.browserWindow|, but in some uses (such as
-   * the Browser Toolbox), there is no browser window, so an alternative window
-   * hosts the utilities there.
-   * @type nsIDOMWindow
-   */
-  get chromeUtilsWindow() {
-    if (this.browserWindow) {
-      return this.browserWindow;
-    }
-    return this.chromeWindow.top;
-  },
-
-  /**
-   * Getter for the xul:popupset that holds any popups we open.
-   * @type Element
-   */
-  get mainPopupSet() {
-    return this.chromeUtilsWindow.document.getElementById("mainPopupSet");
-  },
-
-  /**
-   * Getter for the output element that holds messages we display.
-   * @type Element
-   */
-  get outputNode() {
-    return this.ui ? this.ui.outputNode : null;
-  },
-
-  get gViewSourceUtils() {
-    return this.chromeUtilsWindow.gViewSourceUtils;
-  },
-
-  /**
-   * Initialize the Web Console instance.
-   *
-   * @return object
-   *         A promise for the initialization.
-   */
-  init() {
-    return this.ui.init().then(() => this);
-  },
-
-  /**
-   * The JSTerm object that manages the console's input.
-   * @see webconsole.js::JSTerm
-   * @type object
-   */
-  get jsterm() {
-    return this.ui ? this.ui.jsterm : null;
-  },
-
-  /**
-   * Alias for the WebConsoleFrame.setFilterState() method.
-   * @see webconsole.js::WebConsoleFrame.setFilterState()
-   */
-  setFilterState() {
-    this.ui && this.ui.setFilterState.apply(this.ui, arguments);
-  },
-
-  /**
-   * Open a link in a new tab.
-   *
-   * @param string link
-   *        The URL you want to open in a new tab.
-   */
-  openLink(link, e) {
-    openDocLink(link);
-  },
-
-  /**
-   * Open a link in Firefox's view source.
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which should be highlighted.
-   */
-  viewSource(sourceURL, sourceLine) {
-    this.gViewSourceUtils.viewSource({ URL: sourceURL, lineNumber: sourceLine || 0 });
-  },
-
-  /**
-   * Tries to open a Stylesheet file related to the web page for the web console
-   * instance in the Style Editor. If the file is not found, it is opened in
-   * source view instead.
-   *
-   * Manually handle the case where toolbox does not exist (Browser Console).
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which you want to place the caret.
-   */
-  viewSourceInStyleEditor(sourceURL, sourceLine) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      this.viewSource(sourceURL, sourceLine);
-      return;
-    }
-    toolbox.viewSourceInStyleEditor(sourceURL, sourceLine);
-  },
-
-  /**
-   * Tries to open a JavaScript file related to the web page for the web console
-   * instance in the Script Debugger. If the file is not found, it is opened in
-   * source view instead.
-   *
-   * Manually handle the case where toolbox does not exist (Browser Console).
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which you want to place the caret.
-   */
-  viewSourceInDebugger(sourceURL, sourceLine) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      this.viewSource(sourceURL, sourceLine);
-      return;
-    }
-    toolbox.viewSourceInDebugger(sourceURL, sourceLine).then(() => {
-      this.ui.emit("source-in-debugger-opened");
-    });
-  },
-
-  /**
-   * Tries to open a JavaScript file related to the web page for the web console
-   * instance in the corresponding Scratchpad.
-   *
-   * @param string sourceURL
-   *        The URL of the file which corresponds to a Scratchpad id.
-   */
-  viewSourceInScratchpad(sourceURL, sourceLine) {
-    viewSource.viewSourceInScratchpad(sourceURL, sourceLine);
-  },
-
-  /**
-   * Retrieve information about the JavaScript debugger's stackframes list. This
-   * is used to allow the Web Console to evaluate code in the selected
-   * stackframe.
-   *
-   * @return object|null
-   *         An object which holds:
-   *         - frames: the active ThreadClient.cachedFrames array.
-   *         - selected: depth/index of the selected stackframe in the debugger
-   *         UI.
-   *         If the debugger is not open or if it's not paused, then |null| is
-   *         returned.
-   */
-  getDebuggerFrames() {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return null;
-    }
-    const panel = toolbox.getPanel("jsdebugger");
-
-    if (!panel) {
-      return null;
-    }
-
-    return panel.getFrames();
-  },
-
-  async getMappedExpression(expression) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return expression;
-    }
-    const panel = toolbox.getPanel("jsdebugger");
-
-    if (!panel) {
-      return expression;
-    }
-
-    return panel.getMappedExpression(expression);
-  },
-
-  /**
-   * Retrieves the current selection from the Inspector, if such a selection
-   * exists. This is used to pass the ID of the selected actor to the Web
-   * Console server for the $0 helper.
-   *
-   * @return object|null
-   *         A Selection referring to the currently selected node in the
-   *         Inspector.
-   *         If the inspector was never opened, or no node was ever selected,
-   *         then |null| is returned.
-   */
-  getInspectorSelection() {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return null;
-    }
-    const panel = toolbox.getPanel("inspector");
-    if (!panel || !panel.selection) {
-      return null;
-    }
-    return panel.selection;
-  },
-
-  /**
-   * Destroy the object. Call this method to avoid memory leaks when the Web
-   * Console is closed.
-   *
-   * @return object
-   *         A promise object that is resolved once the Web Console is closed.
-   */
-  async destroy() {
-    if (this._destroyer) {
-      return this._destroyer;
-    }
-
-    this._destroyer = (async () => {
-      HUDService.consoles.delete(this.hudId);
-
-      // The document may already be removed
-      if (this.chromeUtilsWindow && this.mainPopupSet) {
-        const popupset = this.mainPopupSet;
-        const panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
-        for (const panel of panels) {
-          panel.hidePopup();
-        }
-      }
-
-      if (this.ui) {
-        await this.ui.destroy();
-      }
-
-      if (!this._browserConsole) {
-        try {
-          await this.target.activeTab.focus();
-        } catch (ex) {
-          // Tab focus can fail if the tab or target is closed.
-        }
-      }
-
-      const id = Utils.supportsString(this.hudId);
-      Services.obs.notifyObservers(id, "web-console-destroyed");
-    })();
-
-    return this._destroyer;
-  },
-};
-
 /**
  * A BrowserConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
  * This object only wraps the iframe that holds the Browser Console UI. This is
  * meant to be an integration point between the Firefox UI and the Browser Console
  * UI and features.
  *
+ * This object extends the WebConsole object located in webconsole.js
+ *
  * @constructor
  * @param object target
  *        The target that the browser console will connect to.
  * @param nsIDOMWindow iframeWindow
  *        The window where the browser console UI is already loaded.
  * @param nsIDOMWindow chromeWindow
  *        The window of the browser console owner.
+ * @param object hudService
+ *        The parent HUD Service
  */
-function BrowserConsole() {
-  WebConsole.apply(this, arguments);
+function BrowserConsole(target, iframeWindow, chromeWindow, hudService) {
+  WebConsole.call(this, target, iframeWindow, chromeWindow, hudService);
   this._telemetry = new Telemetry();
 }
 
 BrowserConsole.prototype = extend(WebConsole.prototype, {
   _browserConsole: true,
   _bcInit: null,
   _bcDestroyer: null,
 
@@ -579,17 +52,17 @@ BrowserConsole.prototype = extend(WebCon
    *         A promise for the initialization.
    */
   init() {
     if (this._bcInit) {
       return this._bcInit;
     }
 
     // Only add the shutdown observer if we've opened a Browser Console window.
-    ShutdownObserver.init();
+    ShutdownObserver.init(this.hudService);
 
     this.ui._filterPrefsPrefix = BC_FILTER_PREFS_PREFIX;
 
     const window = this.iframeWindow;
 
     // Make sure that the closing of the Browser Console window destroys this
     // instance.
     window.addEventListener("unload", () => {
@@ -614,46 +87,47 @@ BrowserConsole.prototype = extend(WebCon
     if (this._bcDestroyer) {
       return this._bcDestroyer;
     }
 
     this._bcDestroyer = (async () => {
       this._telemetry.toolClosed("browserconsole");
       await this.$destroy();
       await this.target.client.close();
-      HUDService._browserConsoleID = null;
+      this.hudService._browserConsoleID = null;
       this.chromeWindow.close();
     })();
 
     return this._bcDestroyer;
   },
 });
 
-const HUDService = new HUD_SERVICE();
-exports.HUDService = HUDService;
-
 /**
  * The ShutdownObserver listens for app shutdown and saves the current state
  * of the Browser Console for session restore.
  */
 var ShutdownObserver = {
   _initialized: false,
-  init() {
+
+  init(hudService) {
     if (this._initialized) {
       return;
     }
 
     Services.obs.addObserver(this, "quit-application-granted");
 
     this._initialized = true;
+    this.hudService = hudService;
   },
 
   observe(message, topic) {
     if (topic == "quit-application-granted") {
-      HUDService.storeBrowserConsoleSessionState();
+      this.hudService.storeBrowserConsoleSessionState();
       this.uninit();
     }
   },
 
   uninit() {
     Services.obs.removeObserver(this, "quit-application-granted");
   }
 };
+
+module.exports = BrowserConsole;
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -1,54 +1,47 @@
 /* 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";
 
 var Services = require("Services");
-loader.lazyRequireGetter(this, "Utils", "devtools/client/webconsole/utils", true);
-loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true);
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true);
-loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
-loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole-frame", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
-loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
 loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/webconsole-l10n");
-loader.lazyRequireGetter(this, "openDocLink", "devtools/client/shared/link", true);
+loader.lazyRequireGetter(this, "WebConsole", "devtools/client/webconsole/webconsole");
+loader.lazyRequireGetter(this, "BrowserConsole", "devtools/client/webconsole/browser-console");
+
 const BC_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
-// The preference prefix for all of the Browser Console filters.
-const BC_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
-
-var gHudId = 0;
-
-function HUD_SERVICE() {
+function HUDService() {
   this.consoles = new Map();
   this.lastFinishedRequest = { callback: null };
 }
 
-HUD_SERVICE.prototype =
-{
+HUDService.prototype = {
   _browserConsoleID: null,
   _browserConsoleInitializing: null,
 
   /**
    * Keeps a reference for each Web Console / Browser Console that is created.
    * @type Map
    */
   consoles: null,
 
   _browerConsoleSessionState: false,
+
   storeBrowserConsoleSessionState() {
     this._browerConsoleSessionState = !!this.getBrowserConsole();
   },
+
   getBrowserConsoleSessionState() {
     return this._browerConsoleSessionState;
   },
 
   /**
    * Assign a function to this property to listen for every request that
    * completes. Used by unit tests. The callback takes one argument: the HTTP
    * activity object as received from the remote Web Console.
@@ -78,17 +71,17 @@ HUD_SERVICE.prototype =
    * @param nsIDOMWindow iframeWindow
    *        The window where the web console UI is already loaded.
    * @param nsIDOMWindow chromeWindow
    *        The window of the web console owner.
    * @return object
    *         A promise object for the opening of the new WebConsole instance.
    */
   openWebConsole(target, iframeWindow, chromeWindow) {
-    const hud = new WebConsole(target, iframeWindow, chromeWindow);
+    const hud = new WebConsole(target, iframeWindow, chromeWindow, this);
     this.consoles.set(hud.hudId, hud);
     return hud.init();
   },
 
   /**
    * Open a Browser Console for the given target.
    *
    * @see devtools/framework/target.js for details about targets.
@@ -98,17 +91,17 @@ HUD_SERVICE.prototype =
    * @param nsIDOMWindow iframeWindow
    *        The window where the browser console UI is already loaded.
    * @param nsIDOMWindow chromeWindow
    *        The window of the browser console owner.
    * @return object
    *         A promise object for the opening of the new BrowserConsole instance.
    */
   openBrowserConsole(target, iframeWindow, chromeWindow) {
-    const hud = new BrowserConsole(target, iframeWindow, chromeWindow);
+    const hud = new BrowserConsole(target, iframeWindow, chromeWindow, this);
     this._browserConsoleID = hud.hudId;
     this.consoles.set(hud.hudId, hud);
     return hud.init();
   },
 
   /**
    * Returns the Web Console object associated to a content window.
    *
@@ -241,419 +234,9 @@ HUD_SERVICE.prototype =
    *         A BrowserConsole instance or null if the Browser Console is not
    *         open.
    */
   getBrowserConsole() {
     return this.getHudReferenceById(this._browserConsoleID);
   },
 };
 
-/**
- * A WebConsole instance is an interactive console initialized *per target*
- * that displays console log data as well as provides an interactive terminal to
- * manipulate the target's document content.
- *
- * This object only wraps the iframe that holds the Web Console UI. This is
- * meant to be an integration point between the Firefox UI and the Web Console
- * UI and features.
- *
- * @constructor
- * @param object target
- *        The target that the web console will connect to.
- * @param nsIDOMWindow iframeWindow
- *        The window where the web console UI is already loaded.
- * @param nsIDOMWindow chromeWindow
- *        The window of the web console owner.
- */
-function WebConsole(target, iframeWindow, chromeWindow) {
-  this.iframeWindow = iframeWindow;
-  this.chromeWindow = chromeWindow;
-  this.hudId = "hud_" + ++gHudId;
-  this.target = target;
-  this.browserWindow = this.chromeWindow.top;
-  const element = this.browserWindow.document.documentElement;
-  if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
-    this.browserWindow = HUDService.currentContext();
-  }
-  this.ui = new WebConsoleFrame(this);
-}
-WebConsole.prototype = {
-  iframeWindow: null,
-  chromeWindow: null,
-  browserWindow: null,
-  hudId: null,
-  target: null,
-  ui: null,
-  _browserConsole: false,
-  _destroyer: null,
-
-  /**
-   * Getter for a function to to listen for every request that completes. Used
-   * by unit tests. The callback takes one argument: the HTTP activity object as
-   * received from the remote Web Console.
-   *
-   * @type function
-   */
-  get lastFinishedRequestCallback() {
-    return HUDService.lastFinishedRequest.callback;
-  },
-
-  /**
-   * Getter for the window that can provide various utilities that the web
-   * console makes use of, like opening links, managing popups, etc.  In
-   * most cases, this will be |this.browserWindow|, but in some uses (such as
-   * the Browser Toolbox), there is no browser window, so an alternative window
-   * hosts the utilities there.
-   * @type nsIDOMWindow
-   */
-  get chromeUtilsWindow() {
-    if (this.browserWindow) {
-      return this.browserWindow;
-    }
-    return this.chromeWindow.top;
-  },
-
-  /**
-   * Getter for the xul:popupset that holds any popups we open.
-   * @type Element
-   */
-  get mainPopupSet() {
-    return this.chromeUtilsWindow.document.getElementById("mainPopupSet");
-  },
-
-  /**
-   * Getter for the output element that holds messages we display.
-   * @type Element
-   */
-  get outputNode() {
-    return this.ui ? this.ui.outputNode : null;
-  },
-
-  get gViewSourceUtils() {
-    return this.chromeUtilsWindow.gViewSourceUtils;
-  },
-
-  /**
-   * Initialize the Web Console instance.
-   *
-   * @return object
-   *         A promise for the initialization.
-   */
-  init() {
-    return this.ui.init().then(() => this);
-  },
-
-  /**
-   * The JSTerm object that manages the console's input.
-   * @see webconsole.js::JSTerm
-   * @type object
-   */
-  get jsterm() {
-    return this.ui ? this.ui.jsterm : null;
-  },
-
-  /**
-   * Alias for the WebConsoleFrame.setFilterState() method.
-   * @see webconsole.js::WebConsoleFrame.setFilterState()
-   */
-  setFilterState() {
-    this.ui && this.ui.setFilterState.apply(this.ui, arguments);
-  },
-
-  /**
-   * Open a link in a new tab.
-   *
-   * @param string link
-   *        The URL you want to open in a new tab.
-   */
-  openLink(link, e) {
-    openDocLink(link);
-  },
-
-  /**
-   * Open a link in Firefox's view source.
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which should be highlighted.
-   */
-  viewSource(sourceURL, sourceLine) {
-    this.gViewSourceUtils.viewSource({ URL: sourceURL, lineNumber: sourceLine || 0 });
-  },
-
-  /**
-   * Tries to open a Stylesheet file related to the web page for the web console
-   * instance in the Style Editor. If the file is not found, it is opened in
-   * source view instead.
-   *
-   * Manually handle the case where toolbox does not exist (Browser Console).
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which you want to place the caret.
-   */
-  viewSourceInStyleEditor(sourceURL, sourceLine) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      this.viewSource(sourceURL, sourceLine);
-      return;
-    }
-    toolbox.viewSourceInStyleEditor(sourceURL, sourceLine);
-  },
-
-  /**
-   * Tries to open a JavaScript file related to the web page for the web console
-   * instance in the Script Debugger. If the file is not found, it is opened in
-   * source view instead.
-   *
-   * Manually handle the case where toolbox does not exist (Browser Console).
-   *
-   * @param string sourceURL
-   *        The URL of the file.
-   * @param integer sourceLine
-   *        The line number which you want to place the caret.
-   */
-  viewSourceInDebugger(sourceURL, sourceLine) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      this.viewSource(sourceURL, sourceLine);
-      return;
-    }
-    toolbox.viewSourceInDebugger(sourceURL, sourceLine).then(() => {
-      this.ui.emit("source-in-debugger-opened");
-    });
-  },
-
-  /**
-   * Tries to open a JavaScript file related to the web page for the web console
-   * instance in the corresponding Scratchpad.
-   *
-   * @param string sourceURL
-   *        The URL of the file which corresponds to a Scratchpad id.
-   */
-  viewSourceInScratchpad(sourceURL, sourceLine) {
-    viewSource.viewSourceInScratchpad(sourceURL, sourceLine);
-  },
-
-  /**
-   * Retrieve information about the JavaScript debugger's stackframes list. This
-   * is used to allow the Web Console to evaluate code in the selected
-   * stackframe.
-   *
-   * @return object|null
-   *         An object which holds:
-   *         - frames: the active ThreadClient.cachedFrames array.
-   *         - selected: depth/index of the selected stackframe in the debugger
-   *         UI.
-   *         If the debugger is not open or if it's not paused, then |null| is
-   *         returned.
-   */
-  getDebuggerFrames() {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return null;
-    }
-    const panel = toolbox.getPanel("jsdebugger");
-
-    if (!panel) {
-      return null;
-    }
-
-    return panel.getFrames();
-  },
-
-  async getMappedExpression(expression) {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return expression;
-    }
-    const panel = toolbox.getPanel("jsdebugger");
-
-    if (!panel) {
-      return expression;
-    }
-
-    return panel.getMappedExpression(expression);
-  },
-
-  /**
-   * Retrieves the current selection from the Inspector, if such a selection
-   * exists. This is used to pass the ID of the selected actor to the Web
-   * Console server for the $0 helper.
-   *
-   * @return object|null
-   *         A Selection referring to the currently selected node in the
-   *         Inspector.
-   *         If the inspector was never opened, or no node was ever selected,
-   *         then |null| is returned.
-   */
-  getInspectorSelection() {
-    const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return null;
-    }
-    const panel = toolbox.getPanel("inspector");
-    if (!panel || !panel.selection) {
-      return null;
-    }
-    return panel.selection;
-  },
-
-  /**
-   * Destroy the object. Call this method to avoid memory leaks when the Web
-   * Console is closed.
-   *
-   * @return object
-   *         A promise object that is resolved once the Web Console is closed.
-   */
-  async destroy() {
-    if (this._destroyer) {
-      return this._destroyer;
-    }
-
-    this._destroyer = (async () => {
-      HUDService.consoles.delete(this.hudId);
-
-      // The document may already be removed
-      if (this.chromeUtilsWindow && this.mainPopupSet) {
-        const popupset = this.mainPopupSet;
-        const panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
-        for (const panel of panels) {
-          panel.hidePopup();
-        }
-      }
-
-      if (this.ui) {
-        await this.ui.destroy();
-      }
-
-      if (!this._browserConsole) {
-        try {
-          await this.target.activeTab.focus();
-        } catch (ex) {
-          // Tab focus can fail if the tab or target is closed.
-        }
-      }
-
-      const id = Utils.supportsString(this.hudId);
-      Services.obs.notifyObservers(id, "web-console-destroyed");
-    })();
-
-    return this._destroyer;
-  },
-};
-
-/**
- * A BrowserConsole instance is an interactive console initialized *per target*
- * that displays console log data as well as provides an interactive terminal to
- * manipulate the target's document content.
- *
- * This object only wraps the iframe that holds the Browser Console UI. This is
- * meant to be an integration point between the Firefox UI and the Browser Console
- * UI and features.
- *
- * @constructor
- * @param object target
- *        The target that the browser console will connect to.
- * @param nsIDOMWindow iframeWindow
- *        The window where the browser console UI is already loaded.
- * @param nsIDOMWindow chromeWindow
- *        The window of the browser console owner.
- */
-function BrowserConsole() {
-  WebConsole.apply(this, arguments);
-  this._telemetry = new Telemetry();
-}
-
-BrowserConsole.prototype = extend(WebConsole.prototype, {
-  _browserConsole: true,
-  _bcInit: null,
-  _bcDestroyer: null,
-
-  $init: WebConsole.prototype.init,
-
-  /**
-   * Initialize the Browser Console instance.
-   *
-   * @return object
-   *         A promise for the initialization.
-   */
-  init() {
-    if (this._bcInit) {
-      return this._bcInit;
-    }
-
-    // Only add the shutdown observer if we've opened a Browser Console window.
-    ShutdownObserver.init();
-
-    this.ui._filterPrefsPrefix = BC_FILTER_PREFS_PREFIX;
-
-    const window = this.iframeWindow;
-
-    // Make sure that the closing of the Browser Console window destroys this
-    // instance.
-    window.addEventListener("unload", () => {
-      this.destroy();
-    }, {once: true});
-
-    this._telemetry.toolOpened("browserconsole");
-
-    this._bcInit = this.$init();
-    return this._bcInit;
-  },
-
-  $destroy: WebConsole.prototype.destroy,
-
-  /**
-   * Destroy the object.
-   *
-   * @return object
-   *         A promise object that is resolved once the Browser Console is closed.
-   */
-  destroy() {
-    if (this._bcDestroyer) {
-      return this._bcDestroyer;
-    }
-
-    this._bcDestroyer = (async () => {
-      this._telemetry.toolClosed("browserconsole");
-      await this.$destroy();
-      await this.target.client.close();
-      HUDService._browserConsoleID = null;
-      this.chromeWindow.close();
-    })();
-
-    return this._bcDestroyer;
-  },
-});
-
-const HUDService = new HUD_SERVICE();
-exports.HUDService = HUDService;
-
-/**
- * The ShutdownObserver listens for app shutdown and saves the current state
- * of the Browser Console for session restore.
- */
-var ShutdownObserver = {
-  _initialized: false,
-  init() {
-    if (this._initialized) {
-      return;
-    }
-
-    Services.obs.addObserver(this, "quit-application-granted");
-
-    this._initialized = true;
-  },
-
-  observe(message, topic) {
-    if (topic == "quit-application-granted") {
-      HUDService.storeBrowserConsoleSessionState();
-      this.uninit();
-    }
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "quit-application-granted");
-  }
-};
+exports.HUDService = new HUDService();
--- a/devtools/client/webconsole/moz.build
+++ b/devtools/client/webconsole/moz.build
@@ -10,23 +10,25 @@ DIRS += [
     'enhancers',
     'middleware',
     'reducers',
     'selectors',
     'test',
     'utils',
 ]
 DevToolsModules(
+    'browser-console.js',
     'console-commands.js',
     'constants.js',
     'hudservice.js',
     'main.js',
     'panel.js',
     'store.js',
     'types.js',
     'utils.js',
     'webconsole-connection-proxy.js',
     'webconsole-frame.js',
     'webconsole-l10n.js',
     'webconsole-output-wrapper.js',
+    'webconsole.js',
 )
 with Files('**'):
     BUG_COMPONENT = ('DevTools', 'Console')
copy from devtools/client/webconsole/hudservice.js
copy to devtools/client/webconsole/webconsole.js
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -1,285 +1,57 @@
 /* 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";
 
 var Services = require("Services");
 loader.lazyRequireGetter(this, "Utils", "devtools/client/webconsole/utils", true);
-loader.lazyRequireGetter(this, "extend", "devtools/shared/extend", true);
-loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
-loader.lazyRequireGetter(this, "Tools", "devtools/client/definitions", true);
-loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole-frame", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
-loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
-loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
-loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/webconsole-l10n");
 loader.lazyRequireGetter(this, "openDocLink", "devtools/client/shared/link", true);
-const BC_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
-
-// The preference prefix for all of the Browser Console filters.
-const BC_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
 var gHudId = 0;
 
-function HUD_SERVICE() {
-  this.consoles = new Map();
-  this.lastFinishedRequest = { callback: null };
-}
-
-HUD_SERVICE.prototype =
-{
-  _browserConsoleID: null,
-  _browserConsoleInitializing: null,
-
-  /**
-   * Keeps a reference for each Web Console / Browser Console that is created.
-   * @type Map
-   */
-  consoles: null,
-
-  _browerConsoleSessionState: false,
-  storeBrowserConsoleSessionState() {
-    this._browerConsoleSessionState = !!this.getBrowserConsole();
-  },
-  getBrowserConsoleSessionState() {
-    return this._browerConsoleSessionState;
-  },
-
-  /**
-   * Assign a function to this property to listen for every request that
-   * completes. Used by unit tests. The callback takes one argument: the HTTP
-   * activity object as received from the remote Web Console.
-   *
-   * @type object
-   *       Includes a property named |callback|. Assign the function to the
-   *       |callback| property of this object.
-   */
-  lastFinishedRequest: null,
-
-  /**
-   * Get the current context, which is the main application window.
-   *
-   * @returns nsIDOMWindow
-   */
-  currentContext() {
-    return Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
-  },
-
-  /**
-   * Open a Web Console for the given target.
-   *
-   * @see devtools/framework/target.js for details about targets.
-   *
-   * @param object target
-   *        The target that the web console will connect to.
-   * @param nsIDOMWindow iframeWindow
-   *        The window where the web console UI is already loaded.
-   * @param nsIDOMWindow chromeWindow
-   *        The window of the web console owner.
-   * @return object
-   *         A promise object for the opening of the new WebConsole instance.
-   */
-  openWebConsole(target, iframeWindow, chromeWindow) {
-    const hud = new WebConsole(target, iframeWindow, chromeWindow);
-    this.consoles.set(hud.hudId, hud);
-    return hud.init();
-  },
-
-  /**
-   * Open a Browser Console for the given target.
-   *
-   * @see devtools/framework/target.js for details about targets.
-   *
-   * @param object target
-   *        The target that the browser console will connect to.
-   * @param nsIDOMWindow iframeWindow
-   *        The window where the browser console UI is already loaded.
-   * @param nsIDOMWindow chromeWindow
-   *        The window of the browser console owner.
-   * @return object
-   *         A promise object for the opening of the new BrowserConsole instance.
-   */
-  openBrowserConsole(target, iframeWindow, chromeWindow) {
-    const hud = new BrowserConsole(target, iframeWindow, chromeWindow);
-    this._browserConsoleID = hud.hudId;
-    this.consoles.set(hud.hudId, hud);
-    return hud.init();
-  },
-
-  /**
-   * Returns the Web Console object associated to a content window.
-   *
-   * @param nsIDOMWindow contentWindow
-   * @returns object
-   */
-  getHudByWindow(contentWindow) {
-    for (const [, hud] of this.consoles) {
-      const target = hud.target;
-      if (target && target.tab && target.window === contentWindow) {
-        return hud;
-      }
-    }
-    return null;
-  },
-
-  /**
-   * Returns the console instance for a given id.
-   *
-   * @param string id
-   * @returns Object
-   */
-  getHudReferenceById(id) {
-    return this.consoles.get(id);
-  },
-
-  /**
-   * Find if there is a Web Console open for the current tab and return the
-   * instance.
-   * @return object|null
-   *         The WebConsole object or null if the active tab has no open Web
-   *         Console.
-   */
-  getOpenWebConsole() {
-    const tab = this.currentContext().gBrowser.selectedTab;
-    if (!tab || !TargetFactory.isKnownTab(tab)) {
-      return null;
-    }
-    const target = TargetFactory.forTab(tab);
-    const toolbox = gDevTools.getToolbox(target);
-    const panel = toolbox ? toolbox.getPanel("webconsole") : null;
-    return panel ? panel.hud : null;
-  },
-
-  /**
-   * Toggle the Browser Console.
-   */
-  async toggleBrowserConsole() {
-    if (this._browserConsoleID) {
-      const hud = this.getHudReferenceById(this._browserConsoleID);
-      return hud.destroy();
-    }
-
-    if (this._browserConsoleInitializing) {
-      return this._browserConsoleInitializing;
-    }
-
-    async function connect() {
-      // Ensure that the root actor and the target-scoped actors have been registered on
-      // the DebuggerServer, so that the Browser Console can retrieve the console actors.
-      // (See Bug 1416105 for rationale).
-      DebuggerServer.init();
-      DebuggerServer.registerActors({ root: true, target: true });
-
-      DebuggerServer.allowChromeProcess = true;
-
-      const client = new DebuggerClient(DebuggerServer.connectPipe());
-      await client.connect();
-      const response = await client.getProcess();
-      return { form: response.form, client, chrome: true, isBrowsingContext: true };
-    }
-
-    async function openWindow(t) {
-      const win = Services.ww.openWindow(null, Tools.webConsole.browserConsoleURL,
-                                       "_blank", BC_WINDOW_FEATURES, null);
-      let iframeWindow = win;
-
-      await new Promise(resolve => {
-        win.addEventListener("DOMContentLoaded", resolve, {once: true});
-      });
-
-      win.document.title = l10n.getStr("browserConsole.title");
-
-      // With a XUL wrapper doc, we host index.html in an iframe.
-      // Wait for that to be ready before resolving:
-      if (!Tools.webConsole.browserConsoleUsesHTML) {
-        const iframe = win.document.querySelector("iframe");
-        await new Promise(resolve => {
-          iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
-        });
-        iframeWindow = iframe.contentWindow;
-      }
-
-      return {iframeWindow, chromeWindow: win};
-    }
-
-    // Temporarily cache the async startup sequence so that if toggleBrowserConsole
-    // gets called again we can return this console instead of opening another one.
-    this._browserConsoleInitializing = (async () => {
-      const connection = await connect();
-      const target = await TargetFactory.forRemoteTab(connection);
-      const {iframeWindow, chromeWindow} = await openWindow(target);
-      const browserConsole =
-        await this.openBrowserConsole(target, iframeWindow, chromeWindow);
-      return browserConsole;
-    })();
-
-    const browserConsole = await this._browserConsoleInitializing;
-    this._browserConsoleInitializing = null;
-    return browserConsole;
-  },
-
-  /**
-   * Opens or focuses the Browser Console.
-   */
-  openBrowserConsoleOrFocus() {
-    const hud = this.getBrowserConsole();
-    if (hud) {
-      hud.iframeWindow.focus();
-      return Promise.resolve(hud);
-    }
-
-    return this.toggleBrowserConsole();
-  },
-
-  /**
-   * Get the Browser Console instance, if open.
-   *
-   * @return object|null
-   *         A BrowserConsole instance or null if the Browser Console is not
-   *         open.
-   */
-  getBrowserConsole() {
-    return this.getHudReferenceById(this._browserConsoleID);
-  },
-};
-
 /**
  * A WebConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
  * This object only wraps the iframe that holds the Web Console UI. This is
  * meant to be an integration point between the Firefox UI and the Web Console
  * UI and features.
  *
  * @constructor
  * @param object target
  *        The target that the web console will connect to.
  * @param nsIDOMWindow iframeWindow
  *        The window where the web console UI is already loaded.
  * @param nsIDOMWindow chromeWindow
  *        The window of the web console owner.
+ * @param object hudService
+ *        The parent HUD Service
  */
-function WebConsole(target, iframeWindow, chromeWindow) {
+function WebConsole(target, iframeWindow, chromeWindow, hudService) {
   this.iframeWindow = iframeWindow;
   this.chromeWindow = chromeWindow;
   this.hudId = "hud_" + ++gHudId;
   this.target = target;
   this.browserWindow = this.chromeWindow.top;
+  this.hudService = hudService;
+
   const element = this.browserWindow.document.documentElement;
   if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
-    this.browserWindow = HUDService.currentContext();
+    this.browserWindow = this.hudService.currentContext();
   }
   this.ui = new WebConsoleFrame(this);
 }
+
 WebConsole.prototype = {
   iframeWindow: null,
   chromeWindow: null,
   browserWindow: null,
   hudId: null,
   target: null,
   ui: null,
   _browserConsole: false,
@@ -288,17 +60,17 @@ WebConsole.prototype = {
   /**
    * Getter for a function to to listen for every request that completes. Used
    * by unit tests. The callback takes one argument: the HTTP activity object as
    * received from the remote Web Console.
    *
    * @type function
    */
   get lastFinishedRequestCallback() {
-    return HUDService.lastFinishedRequest.callback;
+    return this.hudService.lastFinishedRequest.callback;
   },
 
   /**
    * Getter for the window that can provide various utilities that the web
    * console makes use of, like opening links, managing popups, etc.  In
    * most cases, this will be |this.browserWindow|, but in some uses (such as
    * the Browser Toolbox), there is no browser window, so an alternative window
    * hosts the utilities there.
@@ -507,17 +279,17 @@ WebConsole.prototype = {
    *         A promise object that is resolved once the Web Console is closed.
    */
   async destroy() {
     if (this._destroyer) {
       return this._destroyer;
     }
 
     this._destroyer = (async () => {
-      HUDService.consoles.delete(this.hudId);
+      this.hudService.consoles.delete(this.hudId);
 
       // The document may already be removed
       if (this.chromeUtilsWindow && this.mainPopupSet) {
         const popupset = this.mainPopupSet;
         const panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
         for (const panel of panels) {
           panel.hidePopup();
         }
@@ -538,122 +310,9 @@ WebConsole.prototype = {
       const id = Utils.supportsString(this.hudId);
       Services.obs.notifyObservers(id, "web-console-destroyed");
     })();
 
     return this._destroyer;
   },
 };
 
-/**
- * A BrowserConsole instance is an interactive console initialized *per target*
- * that displays console log data as well as provides an interactive terminal to
- * manipulate the target's document content.
- *
- * This object only wraps the iframe that holds the Browser Console UI. This is
- * meant to be an integration point between the Firefox UI and the Browser Console
- * UI and features.
- *
- * @constructor
- * @param object target
- *        The target that the browser console will connect to.
- * @param nsIDOMWindow iframeWindow
- *        The window where the browser console UI is already loaded.
- * @param nsIDOMWindow chromeWindow
- *        The window of the browser console owner.
- */
-function BrowserConsole() {
-  WebConsole.apply(this, arguments);
-  this._telemetry = new Telemetry();
-}
-
-BrowserConsole.prototype = extend(WebConsole.prototype, {
-  _browserConsole: true,
-  _bcInit: null,
-  _bcDestroyer: null,
-
-  $init: WebConsole.prototype.init,
-
-  /**
-   * Initialize the Browser Console instance.
-   *
-   * @return object
-   *         A promise for the initialization.
-   */
-  init() {
-    if (this._bcInit) {
-      return this._bcInit;
-    }
-
-    // Only add the shutdown observer if we've opened a Browser Console window.
-    ShutdownObserver.init();
-
-    this.ui._filterPrefsPrefix = BC_FILTER_PREFS_PREFIX;
-
-    const window = this.iframeWindow;
-
-    // Make sure that the closing of the Browser Console window destroys this
-    // instance.
-    window.addEventListener("unload", () => {
-      this.destroy();
-    }, {once: true});
-
-    this._telemetry.toolOpened("browserconsole");
-
-    this._bcInit = this.$init();
-    return this._bcInit;
-  },
-
-  $destroy: WebConsole.prototype.destroy,
-
-  /**
-   * Destroy the object.
-   *
-   * @return object
-   *         A promise object that is resolved once the Browser Console is closed.
-   */
-  destroy() {
-    if (this._bcDestroyer) {
-      return this._bcDestroyer;
-    }
-
-    this._bcDestroyer = (async () => {
-      this._telemetry.toolClosed("browserconsole");
-      await this.$destroy();
-      await this.target.client.close();
-      HUDService._browserConsoleID = null;
-      this.chromeWindow.close();
-    })();
-
-    return this._bcDestroyer;
-  },
-});
-
-const HUDService = new HUD_SERVICE();
-exports.HUDService = HUDService;
-
-/**
- * The ShutdownObserver listens for app shutdown and saves the current state
- * of the Browser Console for session restore.
- */
-var ShutdownObserver = {
-  _initialized: false,
-  init() {
-    if (this._initialized) {
-      return;
-    }
-
-    Services.obs.addObserver(this, "quit-application-granted");
-
-    this._initialized = true;
-  },
-
-  observe(message, topic) {
-    if (topic == "quit-application-granted") {
-      HUDService.storeBrowserConsoleSessionState();
-      this.uninit();
-    }
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "quit-application-granted");
-  }
-};
+module.exports = WebConsole;