Bug 1286356 - isolate import of Console in event-emitter; r?gregtatum draft
authorTom Tromey <tom@tromey.com>
Thu, 21 Jul 2016 13:12:21 -0600
changeset 392356 59d2a8eadb45e42ca0d3659e0208f1e817e9fa69
parent 392313 1bb05a19ff9d70ed1d858d526fdbe27a8408f19f
child 526325 5a09ce5ed50e4f02bb13057b233aa7e4c4ed8d63
push id24017
push userbmo:ttromey@mozilla.com
push dateMon, 25 Jul 2016 14:34:55 +0000
reviewersgregtatum
bugs1286356
milestone50.0a1
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.