Bug 1287915 - support webpack "raw!" requires in devtools loader; r=jryans
authorTom Tromey <tom@tromey.com>
Thu, 28 Jul 2016 12:11:42 -0600
changeset 349243 0850c3a2f98662f55e3885bbcca3bb5a98e6f0e1
parent 349242 a9cc7c3437525533fb9643f45d4eb2a727b747bc
child 349244 65135e97b7c66c8d24c19ed5769019f8826c135b
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs1287915
milestone51.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 1287915 - support webpack "raw!" requires in devtools loader; r=jryans MozReview-Commit-ID: 1H6ogaMrZPV
.eslintignore
devtools/client/shared/browser-loader.js
devtools/client/shared/test/browser.ini
devtools/client/shared/test/browser_require_raw.js
devtools/client/shared/theme.js
devtools/shared/Loader.jsm
devtools/shared/loader-plugin-raw.jsm
devtools/shared/moz.build
devtools/shared/tests/unit/test_require_raw.js
devtools/shared/tests/unit/xpcshell.ini
--- a/.eslintignore
+++ b/.eslintignore
@@ -123,16 +123,17 @@ devtools/server/actors/**
 !devtools/server/actors/string.js
 !devtools/server/actors/csscoverage.js
 devtools/server/performance/**
 devtools/server/tests/**
 devtools/shared/*.js
 !devtools/shared/css-lexer.js
 !devtools/shared/defer.js
 !devtools/shared/event-emitter.js
+!devtools/shared/loader-plugin-raw.jsm
 !devtools/shared/task.js
 devtools/shared/*.jsm
 !devtools/shared/Loader.jsm
 devtools/shared/apps/**
 devtools/shared/client/**
 devtools/shared/discovery/**
 devtools/shared/gcli/**
 !devtools/shared/gcli/templater.js
--- a/devtools/client/shared/browser-loader.js
+++ b/devtools/client/shared/browser-loader.js
@@ -96,16 +96,22 @@ function BrowserLoaderBuilder({ baseURI,
 
   const opts = {
     id: "browser-loader",
     sharedGlobal: true,
     sandboxPrototype: window,
     paths: Object.assign({}, dynamicPaths, loaderOptions.paths),
     invisibleToDebugger: loaderOptions.invisibleToDebugger,
     requireHook: (id, require) => {
+      // If |id| requires special handling, simply defer to devtools
+      // immediately.
+      if (devtools.isLoaderPluginId(id)) {
+        return devtools.require(id);
+      }
+
       const uri = require.resolve(id);
       let isBrowserDir = BROWSER_BASED_DIRS.filter(dir => {
         return uri.startsWith(dir);
       }).length > 0;
 
       // If the URI doesn't match hardcoded paths try the regexp.
       if (!isBrowserDir) {
         isBrowserDir = uri.match(browserBasedDirsRegExp) != null;
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -142,16 +142,17 @@ skip-if = e10s # Layouthelpers test shou
 [browser_mdn-docs-03.js]
 [browser_num-l10n.js]
 [browser_options-view-01.js]
 [browser_outputparser.js]
 skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
 [browser_poller.js]
 [browser_prefs-01.js]
 [browser_prefs-02.js]
+[browser_require_raw.js]
 [browser_spectrum.js]
 [browser_theme.js]
 [browser_tableWidget_basic.js]
 [browser_tableWidget_keyboard_interaction.js]
 [browser_tableWidget_mouse_interaction.js]
 [browser_telemetry_button_eyedropper.js]
 [browser_telemetry_button_paintflashing.js]
 skip-if = e10s # Bug 937167 - e10s paintflashing
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/test/browser_require_raw.js
@@ -0,0 +1,20 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
+
+const { require: browserRequire } = BrowserLoader({
+  baseURI: "resource://devtools/client/shared/",
+  window: this
+});
+
+const variableFileContents = browserRequire("raw!devtools/client/themes/variables.css");
+
+function test() {
+  ok(variableFileContents.length > 0, "raw browserRequire worked");
+  finish();
+}
--- a/devtools/client/shared/theme.js
+++ b/devtools/client/shared/theme.js
@@ -4,55 +4,31 @@
 
 "use strict";
 
 /**
  * Colors for themes taken from:
  * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
  */
 
-const { Cu } = require("chrome");
-const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const Services = require("Services");
 const { gDevTools } = require("devtools/client/framework/devtools");
 
-const VARIABLES_URI = "chrome://devtools/skin/variables.css";
+const variableFileContents = require("raw!devtools/client/themes/variables.css");
+
 const THEME_SELECTOR_STRINGS = {
   light: ":root.theme-light {",
   dark: ":root.theme-dark {"
 };
 
-let variableFileContents;
-
-/**
- * Returns a string of the file found at URI
- */
-function readURI(uri) {
-  let stream = NetUtil.newChannel({
-    uri: NetUtil.newURI(uri, "UTF-8"),
-    loadUsingSystemPrincipal: true}
-  ).open2();
-
-  let count = stream.available();
-  let data = NetUtil.readInputStreamToString(stream, count, {
-    charset: "UTF-8"
-  });
-  stream.close();
-  return data;
-}
-
 /**
  * Takes a theme name and returns the contents of its variable rule block.
  * The first time this runs fetches the variables CSS file and caches it.
  */
 function getThemeFile(name) {
-  if (!variableFileContents) {
-    variableFileContents = readURI(VARIABLES_URI);
-  }
-
   // If there's no theme expected for this name, use `light` as default.
   let selector = THEME_SELECTOR_STRINGS[name] ||
                  THEME_SELECTOR_STRINGS.light;
 
   // This is a pretty naive way to find the contents between:
   // selector {
   //   name: val;
   // }
--- a/devtools/shared/Loader.jsm
+++ b/devtools/shared/Loader.jsm
@@ -6,16 +6,17 @@
 
 /**
  * Manages the addon-sdk loader instance used to load the developer tools.
  */
 
 var { utils: Cu } = Components;
 var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 var { Loader, descriptor, resolveURI } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
+var { requireRawId } = Cu.import("resource://devtools/shared/loader-plugin-raw.jsm", {});
 
 this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider",
                          "require", "loader"];
 
 /**
  * Providers are different strategies for loading the devtools.
  */
 
@@ -54,16 +55,22 @@ BuiltinProvider.prototype = {
       paths.promise = "resource://gre/modules/Promise-backend.js";
     }
     this.loader = new Loader.Loader({
       id: "fx-devtools",
       paths,
       invisibleToDebugger: this.invisibleToDebugger,
       sharedGlobal: true,
       sharedGlobalBlocklist,
+      requireHook: (id, require) => {
+        if (id.startsWith("raw!")) {
+          return requireRawId(id, require);
+        }
+        return require(id);
+      },
     });
   },
 
   unload: function (reason) {
     Loader.unload(this.loader, reason);
     delete this.loader;
   },
 };
@@ -116,16 +123,24 @@ DevToolsLoader.prototype = {
   require: function () {
     if (!this._provider) {
       this._loadProvider();
     }
     return this.require.apply(this, arguments);
   },
 
   /**
+   * Return true if |id| refers to something requiring help from a
+   * loader plugin.
+   */
+  isLoaderPluginId: function (id) {
+    return id.startsWith("raw!");
+  },
+
+  /**
    * Override the provider used to load the tools.
    */
   setProvider: function (provider) {
     if (provider === this._provider) {
       return;
     }
 
     if (this._provider) {
new file mode 100644
--- /dev/null
+++ b/devtools/shared/loader-plugin-raw.jsm
@@ -0,0 +1,41 @@
+/* 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 { utils: Cu } = Components;
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+
+/**
+ * A function that can be used as part of a require hook for a
+ * loader.js Loader.  This function only handles webpack-style "raw!"
+ * requires; other requires should not be passed to this.  See
+ * https://github.com/webpack/raw-loader.
+ */
+function requireRawId(id, require) {
+  let uri = require.resolve(id.slice(4));
+  // If the original string did not end with ".js", then
+  // require.resolve might have added the suffix.  We don't want to
+  // add a suffix for a raw load (if needed the caller can specify it
+  // manually), so remove it here.
+  if (!id.endsWith(".js") && uri.endsWith(".js")) {
+    uri = uri.slice(0, -3);
+  }
+  let stream = NetUtil.newChannel({
+    uri: NetUtil.newURI(uri, "UTF-8"),
+    loadUsingSystemPrincipal: true
+  }).open2();
+
+  let count = stream.available();
+  let data = NetUtil.readInputStreamToString(stream, count, {
+    charset: "UTF-8"
+  });
+  stream.close();
+
+  // For the time being it doesn't seem worthwhile to cache the
+  // result here.
+  return data;
+}
+
+this.EXPORTED_SYMBOLS = ["requireRawId"];
--- a/devtools/shared/moz.build
+++ b/devtools/shared/moz.build
@@ -49,16 +49,17 @@ DevToolsModules(
     'css-properties-db.js',
     'defer.js',
     'deprecated-sync-thenables.js',
     'DevToolsUtils.js',
     'dom-node-constants.js',
     'dom-node-filter-constants.js',
     'event-emitter.js',
     'indentation.js',
+    'loader-plugin-raw.jsm',
     'Loader.jsm',
     'Parser.jsm',
     'path.js',
     'protocol.js',
     'system.js',
     'task.js',
     'ThreadSafeDevToolsUtils.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/shared/tests/unit/test_require_raw.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test require using "raw!".
+
+function run_test() {
+  let loader = new DevToolsLoader();
+  let require = loader.require;
+
+  let variableFileContents = require("raw!devtools/client/themes/variables.css");
+  ok(variableFileContents.length > 0, "raw browserRequire worked");
+}
--- a/devtools/shared/tests/unit/xpcshell.ini
+++ b/devtools/shared/tests/unit/xpcshell.ini
@@ -20,12 +20,13 @@ support-files =
 [test_invisible_loader.js]
 [test_isSet.js]
 [test_safeErrorString.js]
 [test_defineLazyPrototypeGetter.js]
 [test_async-utils.js]
 [test_console_filtering.js]
 [test_prettifyCSS.js]
 [test_require_lazy.js]
+[test_require_raw.js]
 [test_require.js]
 [test_stack.js]
 [test_defer.js]
 [test_executeSoon.js]