Bug 1286356 - isolate import of Console in event-emitter; r=gregtatum
authorTom Tromey <tom@tromey.com>
Thu, 21 Jul 2016 13:12:21 -0600
changeset 348587 46de97426f7b5467a37e1512ed022f2908d8626a
parent 348586 ddcceb6bf9a6e4a1dc12df5967d78674f7d0bd62
child 348588 0c8cfad5d7a4dc003fb6f1708559ae041ce0ed05
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgregtatum
bugs1286356
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1286356 - isolate import of Console in event-emitter; r=gregtatum MozReview-Commit-ID: HIgYdui8wwO
devtools/shared/event-emitter.js
--- a/devtools/shared/event-emitter.js
+++ b/devtools/shared/event-emitter.js
@@ -1,66 +1,86 @@
 /* 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";
 
 (function (factory) {
+  // This file can be loaded in several different ways.  It can be
+  // require()d, either from the main thread or from a worker thread;
+  // or it can be imported via Cu.import.  These different forms
+  // explain some of the hairiness of this code.
+  //
+  // It's important for the devtools-as-html project that a require()
+  // on the main thread not use any chrome privileged APIs.  Instead,
+  // the body of the main function can only require() (not Cu.import)
+  // modules that are available in the devtools content mode.  This,
+  // plus the lack of |console| in workers, results in some gyrations
+  // in the definition of |console|.
   if (this.module && module.id.indexOf("event-emitter") >= 0) {
+    let console;
+    if (isWorker) {
+      console = {
+        error: () => {}
+      };
+    } else {
+      console = this.console;
+    }
     // require
-    factory.call(this, require, exports, module);
+    factory.call(this, require, exports, module, console);
   } else {
-    // Cu.import
+    // Cu.import.  This snippet implements a sort of miniature loader,
+    // which is responsible for appropriately translating require()
+    // requests from the client function.  This code can use
+    // Cu.import, because it is never run in the devtools-in-content
+    // mode.
     this.isWorker = false;
+    const Cu = Components.utils;
+    let console = Cu.import("resource://gre/modules/Console.jsm", {}).console;
     // Bug 1259045: This module is loaded early in firefox startup as a JSM,
     // but it doesn't depends on any real module. We can save a few cycles
     // and bytes by not loading Loader.jsm.
     let require = function (module) {
-      const Cu = Components.utils;
       switch (module) {
         case "devtools/shared/defer":
           return Cu.import("resource://gre/modules/Promise.jsm", {}).Promise.defer;
         case "Services":
           return Cu.import("resource://gre/modules/Services.jsm", {}).Services;
-        case "resource://gre/modules/Console.jsm":
-          return Cu.import("resource://gre/modules/Console.jsm", {});
         case "chrome":
           return {
             Cu,
             components: Components
           };
       }
       return null;
     };
-    factory.call(this, require, this, { exports: this });
+    factory.call(this, require, this, { exports: this }, console);
     this.EXPORTED_SYMBOLS = ["EventEmitter"];
   }
-}).call(this, function (require, exports, module) {
+}).call(this, function (require, exports, module, console) {
+  // ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
+  // After this point the code may not use Cu.import, and should only
+  // require() modules that are "clean-for-content".
   let EventEmitter = this.EventEmitter = function () {};
   module.exports = EventEmitter;
 
   // See comment in JSM module boilerplate when adding a new dependency.
   const { components } = require("chrome");
   const Services = require("Services");
   const defer = require("devtools/shared/defer");
   let loggingEnabled = true;
 
-  let console = {};
   if (!isWorker) {
-    console = require("resource://gre/modules/Console.jsm").console;
     loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
     Services.prefs.addObserver("devtools.dump.emit", {
       observe: () => {
         loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
       }
     }, false);
-  } else {
-    // Workers can't load JSMs, so we can't import Console.jsm here.
-    console.error = () => {};
   }
 
   /**
    * Decorate an object with event emitter functionality.
    *
    * @param Object objectToDecorate
    *        Bind all public methods of EventEmitter to
    *        the objectToDecorate object.