Bug 1291049 - Attempt to bundle the inspector with webpack
MozReview-Commit-ID: Lk5pRrDCLV4
--- a/.hgignore
+++ b/.hgignore
@@ -70,16 +70,18 @@
^python/psutil/.*\.so
^python/psutil/.*\.pyd
^python/psutil/build/
# Git repositories
.git/
# Ignore chrome.manifest files from the devtools loader
+^devtools/client/node_modules
+^devtools/client/inspector/inspector.bundle.js
^devtools/client/chrome.manifest$
^devtools/shared/chrome.manifest$
# Ignore node_modules directories in devtools
^devtools/client/.*/node_modules/
# git checkout of libstagefright
^media/libstagefright/android$
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -765,16 +765,22 @@ 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;
}
+ 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,
new file mode 100644
--- /dev/null
+++ b/devtools/client/.babelrc
@@ -0,0 +1,1 @@
+ { "presets": [ "es2015" ] }
\ No newline at end of file
--- a/devtools/client/inspector/inspector-panel.js
+++ b/devtools/client/inspector/inspector-panel.js
@@ -597,23 +597,23 @@ InspectorPanel.prototype = {
_selectionCssSelector: null,
/**
* Set the currently selected node unique css selector.
* Will store the current target url along with it to allow pre-selection at
* reload
*/
- set selectionCssSelector(cssSelector = null) {
+ set selectionCssSelector(cssSelector) {
if (this._panelDestroyer) {
return;
}
this._selectionCssSelector = {
- selector: cssSelector,
+ selector: cssSelector || null,
url: this._target.url
};
},
/**
* Get the current selection unique css selector if any, that is, if a node
* is actually selected and that node has been selected while on the same url
*/
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/inspector.xhtml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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/. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta charset="UTF-8" />
+</head>
+<body>
+ <p>
+ Temp inspector
+ </p>
+ <script src="inspector.bundle.js"></script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "inspector",
+ "version": "1.0.0",
+ "description": "",
+ "main": "",
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "build": "webpack"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "babel-core": "^6.11.4",
+ "babel-loader": "^6.2.4",
+ "babel-preset-es2015": "^6.9.0",
+ "raw-loader": "^0.5.1",
+ "webpack": "^1.13.1"
+ }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/webpack.config.js
@@ -0,0 +1,104 @@
+/* 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";
+
+/* Note that this file is a work in progress attempt for bundling the inspector
+ with webpack.
+
+ Instructions for building:
+ cd devtools/client
+ npm install
+ webpack
+ open inspector/inspector.xhtml in a browser
+*/
+
+const path = require("path");
+const webpack = require("webpack");
+
+module.exports = {
+ bail: true,
+
+ entry: './inspector/inspector-panel.js',
+ output: {
+ filename: './inspector/inspector.bundle.js',
+ },
+ module: {
+ // Disable handling of unknown requires
+ unknownContextRegExp: /$^/,
+ unknownContextCritical: false,
+
+ // Disable handling of requires with a single expression
+ exprContextRegExp: /$^/,
+ exprContextCritical: false,
+
+ // Warn for every expression in require
+ wrappedContextCritical: true,
+
+ loaders: [
+ {
+ test: /event-emitter/,
+ exclude: /node_modules/,
+ loaders: [__dirname + '/webpack/rewrite-event-emitter'],
+ },
+ ]
+ },
+ resolveLoader: {
+ root: [
+ path.resolve('./node_modules'),
+ path.resolve("./webpack"),
+ ]
+ },
+ resolve: {
+ alias: {
+ "devtools-shared/locale": path.join(__dirname, "../shared/locales/en-US"),
+ "devtools/locale": path.join(__dirname, "./locales/en-US"),
+ "global/locale": path.join(__dirname, "../../toolkit/locales/en-US/chrome/global"),
+ "devtools/shared/platform": path.join(__dirname, "../shared/platform/content"),
+ devtools: path.join(__dirname, "../"),
+ Services: path.join(__dirname, "./shared/shim/Services.js"),
+ gcli: path.join(__dirname, "../shared/gcli/source/lib/gcli"),
+ acorn: path.join(__dirname, "../shared/acorn"),
+ "acorn/util/walk": path.join(__dirname, "../shared/acorn/walk"),
+ sdk: path.join(__dirname, "../../addon-sdk/source/lib/sdk"),
+ method: path.join(__dirname, "../../addon-sdk/source/lib/method"),
+ "modules/libpref/init/all": path.join(__dirname,
+ "../../modules/libpref/init/all.js"),
+ },
+ },
+
+ plugins: [
+ new webpack.DefinePlugin({
+ "isWorker": JSON.stringify(false),
+ "reportError": "console.error",
+ "loader": "{ lazyRequireGetter: () => {} }",
+ "dump": "console.log",
+ }),
+ ],
+
+ externals: [
+ /codemirror\//,
+ /server\//,
+ {
+ "promise": "var Promise",
+
+ // Just trying to get build to work. These should be removed eventually:
+ "chrome": "{}",
+
+ "resource://gre/modules/XPCOMUtils.jsm": "{}",
+ "resource://devtools/client/styleeditor/StyleEditorUI.jsm": "{}",
+ "resource://devtools/client/styleeditor/StyleEditorUtil.jsm": "{}",
+ "devtools/client/inspector/inspector-panel": "{}",
+ "devtools/server/actors/utils/audionodes.json": "{}",
+
+ "devtools/client/shared/developer-toolbar": "{}",
+
+ // From sdk.
+ "resource://gre/modules/Preferences.jsm": "{}",
+ "@loader/options": "{}",
+ "@loader/unload": "{}",
+ },
+
+ ],
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/webpack/prefs-loader.js
@@ -0,0 +1,52 @@
+// Rewrite devtools.js or all.js, leaving just the relevant pref() calls.
+
+"use strict";
+
+const PREF_RX = new RegExp("^ *pref\\(\"devtools");
+
+module.exports = function (content) {
+ this.cacheable && this.cacheable();
+
+ // If we're reading devtools.js we have to do some reprocessing.
+ // If we're reading all.js we just assume we can dump all the
+ // conditionals.
+ let isDevtools = this.request.endsWith("/devtools.js");
+
+ // This maps the text of a "#if" to its truth value. This has to
+ // cover all uses of #if in devtools.js.
+ const ifMap = {
+ "#if MOZ_UPDATE_CHANNEL == beta": false,
+ "#if defined(NIGHTLY_BUILD)": false,
+ "#ifdef MOZ_DEV_EDITION": false,
+ "#ifdef RELEASE_BUILD": true,
+ };
+
+ let lines = content.split("\n");
+ let ignoring = false;
+ let newLines = [];
+ let continuation = false;
+ for (let line of lines) {
+ if (line.startsWith("sticky_pref")) {
+ line = line.slice(7);
+ }
+
+ if (isDevtools) {
+ if (line.startsWith("#if")) {
+ if (!(line in ifMap)) {
+ throw new Error("missing line in ifMap: " + line);
+ }
+ ignoring = !ifMap[line];
+ } else if (line.startsWith("#else")) {
+ ignoring = !ignoring;
+ }
+ }
+
+ if (continuation || (!ignoring && PREF_RX.test(line))) {
+ newLines.push(line);
+
+ // The call to pref(...); might span more than one line.
+ continuation = !/\);/.test(line);
+ }
+ }
+ return newLines.join("\n");
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/webpack/rewrite-event-emitter.js
@@ -0,0 +1,22 @@
+// Remove the header code from event-emitter.js. This code confuses
+// webpack.
+
+"use strict";
+
+module.exports = function (content) {
+ this.cacheable && this.cacheable();
+
+ let lines = content.split("\n");
+ let ignoring = false;
+ let newLines = [];
+ for (let line of lines) {
+ if (/function \(factory\)/.test(line)) {
+ ignoring = true;
+ } else if (/call\(this, function /.test(line)) {
+ ignoring = false;
+ } else if (!ignoring && line !== "});") {
+ newLines.push(line);
+ }
+ }
+ return newLines.join("\n");
+};
--- a/devtools/shared/l10n.js
+++ b/devtools/shared/l10n.js
@@ -3,27 +3,54 @@
* 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 = {};
+// Some shenanigans are needed for LocalizationHelper's dynamic
+// require to work with Webpack. Here we a create different context
+// require for each possible locale directory. Then later we use
+// these functions, rather than plain |require|, to load the resource.
+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}`));
+ // More shenanigans. 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.
*