Bug 1310702 - use webpack-like require.context in devtools l10n; r=jryans
authorTom Tromey <tom@tromey.com>
Thu, 20 Oct 2016 11:00:28 -0600
changeset 320215 ad425b5dd87b5bae73defea1f58287306dfa9484
parent 320214 ac14755f0f77d6f71ce17ccc92f118a5ee9726f9
child 320216 ee32f39572dd76c9b6db98831d61b54c668147f5
push id33703
push userttromey@mozilla.com
push dateMon, 31 Oct 2016 14:09:46 +0000
treeherderautoland@ad425b5dd87b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs1310702
milestone52.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 1310702 - use webpack-like require.context in devtools l10n; r=jryans MozReview-Commit-ID: 5noH0y0MgaK
addon-sdk/source/lib/toolkit/loader.js
devtools/client/inspector/rules/test/head.js
devtools/client/inspector/shared/test/head.js
devtools/shared/l10n.js
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -900,16 +900,24 @@ const Require = iced(function Require(lo
   }
 
   // Expose the `resolve` function for this `Require` instance
   require.resolve = _require.resolve = function resolve(id) {
     let { uri } = getRequirements(id);
     return uri;
   }
 
+  // This is like webpack's require.context.  It returns a new require
+  // function that prepends the prefix to any requests.
+  require.context = prefix => {
+    return id => {
+      return require(prefix + id);
+    };
+  };
+
   // Make `require.main === module` evaluate to true in main module scope.
   require.main = loader.main === requirer ? requirer : undefined;
   return iced(require);
 });
 Loader.Require = Require;
 
 const main = iced(function main(loader, id) {
   // If no main entry provided, and native loader is used,
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -15,17 +15,18 @@ registerCleanupFunction(() => {
 });
 
 var {getInplaceEditorForSpan: inplaceEditor} =
   require("devtools/client/shared/inplace-editor");
 
 const ROOT_TEST_DIR = getRootDirectory(gTestPath);
 const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
 
-const STYLE_INSPECTOR_L10N = new LocalizationHelper("chrome://devtools-shared/locale/styleinspector.properties");
+const STYLE_INSPECTOR_L10N
+      = new LocalizationHelper("devtools-shared/locale/styleinspector.properties");
 
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.defaultColorUnit");
 });
 
 /**
  * The rule-view tests rely on a frame-script to be injected in the content test
  * page. So override the shared-head's addTab to load the frame script after the
--- a/devtools/client/inspector/shared/test/head.js
+++ b/devtools/client/inspector/shared/test/head.js
@@ -16,17 +16,18 @@ var {getInplaceEditorForSpan: inplaceEdi
 const {getColor: getThemeColor} = require("devtools/client/shared/theme");
 
 const TEST_URL_ROOT =
   "http://example.com/browser/devtools/client/inspector/shared/test/";
 const TEST_URL_ROOT_SSL =
   "https://example.com/browser/devtools/client/inspector/shared/test/";
 const ROOT_TEST_DIR = getRootDirectory(gTestPath);
 const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
-const STYLE_INSPECTOR_L10N = new LocalizationHelper("chrome://devtools-shared/locale/styleinspector.properties");
+const STYLE_INSPECTOR_L10N =
+      new LocalizationHelper("devtools-shared/locale/styleinspector.properties");
 
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.defaultColorUnit");
 });
 
 /**
--- a/devtools/shared/l10n.js
+++ b/devtools/shared/l10n.js
@@ -3,27 +3,68 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const parsePropertiesFile = require("devtools/shared/node-properties/node-properties");
 const { sprintf } = require("devtools/shared/sprintfjs/sprintf");
 
 const propertiesMap = {};
 
+// We need some special treatment here for webpack.
+//
+// Webpack doesn't always handle dynamic requires in the best way.  In
+// particular if it sees an unrestricted dynamic require, it will try
+// to put all the files it can find into the generated pack.  (It can
+// also try a bit to parse the expression passed to require, but in
+// our case this doesn't work, because our call below doesn't provide
+// enough information.)
+//
+// Webpack also provides a way around this: require.context.  The idea
+// here is to tell webpack some constraints so that it can include
+// fewer files in the pack.
+//
+// Here we introduce new require contexts for each possible locale
+// directory.  Then we use the correct context to load the property
+// file.  In the webpack case this results in just the locale property
+// files being included in the pack; and in the devtools case this is
+// a wordy no-op.
+const reqShared = require.context("raw!devtools-shared/locale/",
+                                  true, /^.*\.properties$/);
+const reqClient = require.context("raw!devtools/locale/",
+                                  true, /^.*\.properties$/);
+const reqGlobal = require.context("raw!global/locale/",
+                                  true, /^.*\.properties$/);
+
 /**
  * Memoized getter for properties files that ensures a given url is only required and
  * parsed once.
  *
  * @param {String} url
  *        The URL of the properties file to parse.
  * @return {Object} parsed properties mapped in an object.
  */
 function getProperties(url) {
   if (!propertiesMap[url]) {
-    propertiesMap[url] = parsePropertiesFile(require(`raw!${url}`));
+    // See the comment above about webpack and require contexts.  Here
+    // we take an input like "devtools-shared/locale/debugger.properties"
+    // and decide which context require function to use.  Despite the
+    // string processing here, in the end a string identical to |url|
+    // ends up being passed to "require".
+    let index = url.lastIndexOf("/");
+    // Turn "mumble/locale/resource.properties" => "./resource.properties".
+    let baseName = "." + url.substr(index);
+    let reqFn;
+    if (/^global/.test(url)) {
+      reqFn = reqGlobal;
+    } else if (/^devtools-shared/.test(url)) {
+      reqFn = reqShared;
+    } else {
+      reqFn = reqClient;
+    }
+    propertiesMap[url] = parsePropertiesFile(reqFn(baseName));
   }
 
   return propertiesMap[url];
 }
 
 /**
  * Localization convenience methods.
  *