Bug 1455226 - Load memory/initializer.js via browserRequire instead of a script tag;r=ochameau draft
authorJulian Descottes <jdescottes@mozilla.com>
Thu, 19 Apr 2018 19:12:18 +0200
changeset 785176 1d30dd878721119064081dfa33881488f7600a4b
parent 784524 0e45c13b34e815cb42a9f08bb44142d1a81e186e
push id107166
push userjdescottes@mozilla.com
push dateThu, 19 Apr 2018 19:24:20 +0000
reviewersochameau
bugs1455226
milestone61.0a1
Bug 1455226 - Load memory/initializer.js via browserRequire instead of a script tag;r=ochameau "async" methods defined in scripts loaded via a <script> tag seem to indirectly use the document's Promise, which is not usable after the DOM of the document has been destroyed. This is an issue if we invoke this code during the destroy of the toolbox. MozReview-Commit-ID: C8juQqJlVDN
browser/installer/allowed-dupes.mn
devtools/client/jar.mn
devtools/client/memory/initializer.js
devtools/client/memory/memory.xhtml
devtools/client/memory/moz.build
devtools/client/memory/panel.js
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -24,28 +24,26 @@ browser/chrome/browser/skin/classic/brow
 browser/chrome/browser/skin/classic/browser/controlcenter/warning-gray.svg
 # devtools reduction is bug 1311178
 browser/chrome/devtools/content/dom/content/dom-view.css
 browser/chrome/devtools/content/dom/dom.html
 browser/chrome/devtools/content/dom/main.js
 browser/chrome/devtools/content/framework/toolbox-options.js
 browser/chrome/devtools/content/inspector/fonts/fonts.js
 browser/chrome/devtools/content/inspector/inspector.xhtml
-browser/chrome/devtools/content/memory/initializer.js
 browser/chrome/devtools/content/projecteditor/lib/helpers/readdir.js
 browser/chrome/devtools/content/shared/theme-switching.js
 browser/chrome/devtools/modules/devtools/client/dom/content/dom-view.css
 browser/chrome/devtools/modules/devtools/client/dom/dom.html
 browser/chrome/devtools/modules/devtools/client/dom/main.js
 browser/chrome/devtools/modules/devtools/client/framework/toolbox-options.js
 browser/chrome/devtools/modules/devtools/client/inspector/fonts/fonts.js
 browser/chrome/devtools/modules/devtools/client/inspector/inspector.xhtml
 browser/chrome/devtools/modules/devtools/client/jsonview/css/controls.png
 browser/chrome/devtools/modules/devtools/client/jsonview/css/controls@2x.png
-browser/chrome/devtools/modules/devtools/client/memory/initializer.js
 browser/chrome/devtools/modules/devtools/client/projecteditor/lib/helpers/readdir.js
 browser/chrome/devtools/modules/devtools/client/shared/theme-switching.js
 browser/chrome/devtools/modules/devtools/client/themes/common.css
 browser/chrome/devtools/modules/devtools/client/themes/toolbars.css
 browser/chrome/devtools/modules/devtools/client/themes/variables.css
 browser/chrome/devtools/skin/common.css
 browser/chrome/devtools/skin/toolbars.css
 browser/chrome/devtools/skin/images/command-scratchpad.svg
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -71,17 +71,16 @@ devtools.jar:
     content/performance/views/details-abstract-subview.js (performance/views/details-abstract-subview.js)
     content/performance/views/details-waterfall.js (performance/views/details-waterfall.js)
     content/performance/views/details-js-call-tree.js (performance/views/details-js-call-tree.js)
     content/performance/views/details-js-flamegraph.js (performance/views/details-js-flamegraph.js)
     content/performance/views/details-memory-call-tree.js (performance/views/details-memory-call-tree.js)
     content/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
     content/performance/views/recordings.js (performance/views/recordings.js)
     content/memory/memory.xhtml (memory/memory.xhtml)
-    content/memory/initializer.js (memory/initializer.js)
     content/commandline/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
     content/commandline/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)
     content/framework/toolbox-window.xul (framework/toolbox-window.xul)
     content/framework/toolbox-options.xhtml (framework/toolbox-options.xhtml)
 *   content/framework/toolbox.xul (framework/toolbox.xul)
     content/framework/toolbox-init.js (framework/toolbox-init.js)
     content/framework/options-panel.css (framework/options-panel.css)
     content/framework/toolbox-process-window.xul (framework/toolbox-process-window.xul)
--- a/devtools/client/memory/initializer.js
+++ b/devtools/client/memory/initializer.js
@@ -1,70 +1,69 @@
 /* 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/. */
 
 /* exported initialize, destroy, Promise */
 
 "use strict";
 
-const BrowserLoaderModule = {};
-ChromeUtils.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
-const { require } = BrowserLoaderModule.BrowserLoader({
-  baseURI: "resource://devtools/client/memory/",
-  window
-});
 const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 const App = createFactory(require("devtools/client/memory/app"));
 const Store = require("devtools/client/memory/store");
 const { assert } = require("devtools/shared/DevToolsUtils");
-const Promise = require("Promise");
+
+// Shared variables used by several methods of this module.
+let root, store, unsubscribe;
 
-/**
- * The current target, toolbox, MemoryFront, and HeapAnalysesClient,
- * set by this tool's host.
- */
-var gToolbox, gFront, gHeapAnalysesClient;
+const initialize = async function() {
+  // Exposed by panel.js
+  let { gFront, gToolbox, gHeapAnalysesClient } = window;
 
-/**
- * Variables set by `initialize()`
- */
-var gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted;
+  root = document.querySelector("#app");
+  store = Store();
+  const app = createElement(App, {
+    toolbox: gToolbox,
+    front: gFront,
+    heapWorker: gHeapAnalysesClient
+  });
+  const provider = createElement(Provider, { store }, app);
+  ReactDOM.render(provider, root);
+  unsubscribe = store.subscribe(onStateChange);
 
-var initialize = async function() {
-  gRoot = document.querySelector("#app");
-  gStore = Store();
-  gApp = createElement(App,
-    { toolbox: gToolbox, front: gFront, heapWorker: gHeapAnalysesClient });
-  gProvider = createElement(Provider, { store: gStore }, gApp);
-  ReactDOM.render(gProvider, gRoot);
-  unsubscribe = gStore.subscribe(onStateChange);
+  // Exposed for tests.
+  window.gStore = store;
 };
 
-var destroy = async function() {
-  const ok = ReactDOM.unmountComponentAtNode(gRoot);
+const destroy = async function() {
+  const ok = ReactDOM.unmountComponentAtNode(root);
   assert(ok, "Should successfully unmount the memory tool's top level React component");
 
   unsubscribe();
+};
 
-  gStore = gRoot = gApp = gProvider = unsubscribe = isHighlighted = null;
-};
+// Current state
+let isHighlighted;
 
 /**
  * Fired on any state change, currently only handles toggling
  * the highlighting of the tool when recording allocations.
  */
 function onStateChange() {
-  let isRecording = gStore.getState().allocations.recording;
+  let { gToolbox } = window;
+
+  let isRecording = store.getState().allocations.recording;
   if (isRecording === isHighlighted) {
     return;
   }
 
   if (isRecording) {
     gToolbox.highlightTool("memory");
   } else {
     gToolbox.unhighlightTool("memory");
   }
 
   isHighlighted = isRecording;
 }
+
+module.exports = { initialize, destroy };
--- a/devtools/client/memory/memory.xhtml
+++ b/devtools/client/memory/memory.xhtml
@@ -20,21 +20,16 @@
     <div id="app"></div>
 
     <script type="application/javascript"
             src="chrome://devtools/content/shared/theme-switching.js"
             defer="true">
     </script>
 
     <script type="application/javascript"
-            src="initializer.js"
-            defer="true">
-    </script>
-
-    <script type="application/javascript"
             src="chrome://devtools/content/shared/vendor/d3.js"
             defer="true">
     </script>
 
     <script type="application/javascript"
             src="chrome://devtools/content/shared/vendor/dagre-d3.js"
             defer="true">
     </script>
--- a/devtools/client/memory/moz.build
+++ b/devtools/client/memory/moz.build
@@ -11,16 +11,17 @@ DIRS += [
     'components',
     'reducers',
 ]
 
 DevToolsModules(
     'app.js',
     'constants.js',
     'dominator-tree-lazy-children.js',
+    'initializer.js',
     'models.js',
     'panel.js',
     'reducers.js',
     'store.js',
     'utils.js',
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
--- a/devtools/client/memory/panel.js
+++ b/devtools/client/memory/panel.js
@@ -1,22 +1,30 @@
 /* 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";
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const { MemoryFront } = require("devtools/shared/fronts/memory");
+const { Cu } = require("chrome");
 const HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient");
 
 function MemoryPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
 
+  const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
+  const browserRequire = BrowserLoader({
+    baseURI: "resource://devtools/client/memory/",
+    window: this.panelWin
+  }).require;
+  this.initializer = browserRequire("devtools/client/memory/initializer");
+
   EventEmitter.decorate(this);
 }
 
 MemoryPanel.prototype = {
   async open() {
     if (this._opening) {
       return this._opening;
     }
@@ -27,17 +35,17 @@ MemoryPanel.prototype = {
     const rootForm = await this.target.root;
     this.panelWin.gFront = new MemoryFront(this.target.client,
                                            this.target.form,
                                            rootForm);
     this.panelWin.gHeapAnalysesClient = new HeapAnalysesClient();
 
     await this.panelWin.gFront.attach();
 
-    this._opening = this.panelWin.initialize().then(() => {
+    this._opening = this.initializer.initialize().then(() => {
       this.isReady = true;
       this.emit("ready");
       return this;
     });
 
     return this._opening;
   },
 
@@ -50,17 +58,17 @@ MemoryPanel.prototype = {
   async destroy() {
     // Make sure this panel is not already destroyed.
     if (this._destroyer) {
       return this._destroyer;
     }
 
     await this.panelWin.gFront.detach();
 
-    this._destroyer = this.panelWin.destroy().then(() => {
+    this._destroyer = this.initializer.destroy().then(() => {
       // Destroy front to ensure packet handler is removed from client
       this.panelWin.gFront.destroy();
       this.panelWin.gHeapAnalysesClient.destroy();
       this.panelWin = null;
       this._opening = null;
       this.isReady = false;
       this.emit("destroyed");
     });