Bug 1390093 - Add whydidyouupdate mixin to React components r?jlast draft
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Tue, 29 Aug 2017 11:50:36 +0100
changeset 664035 4a7c9effe252e66a3544c654318cbb21340b60b6
parent 663831 1888ec2f277f6bb26271b8808e08914a21db9efe
child 664038 7a7c578c5b937f95ece33ab11b6fbba780a1f04a
push id79599
push userbmo:mratcliffe@mozilla.com
push dateWed, 13 Sep 2017 16:52:11 +0000
reviewersjlast
bugs1390093
milestone57.0a1
Bug 1390093 - Add whydidyouupdate mixin to React components r?jlast @Jason: You only really need to review devtools/shared/mixinService.js and devtools/client/jsonview/viewer-config.js because you already r+ssed the rest of the changes. This patch just provides a simple way for us to add plugins to **all** our React components. As for the whydidyouupdate mixin: I am sure you need no introduction. This mixin outputs to the browser console. It is great for understanding why a particular React render was called. Changes: - At Alex's request I have added devtools.performance.measure.whydidyouupdate.filter that matches component names. This pref can contain a string e.g. "ToolBoxToolbar" or a regex e.g. /Toolbox/. - Fixed the error in the JSON Viewer... there was a cross domain security error. Because it runs in content, it couldn't use any components that included mixinService.js. I fixed this using a define in viewer.config.js. I am in the process of creating another mixin that outputs shouldComponentUpdate methods... hopefully. MozReview-Commit-ID: D7adUCMpvOA
devtools/client/aboutdebugging/components/aboutdebugging.js
devtools/client/aboutdebugging/components/addons/controls.js
devtools/client/aboutdebugging/components/addons/install-error.js
devtools/client/aboutdebugging/components/addons/panel.js
devtools/client/aboutdebugging/components/addons/target.js
devtools/client/aboutdebugging/components/panel-header.js
devtools/client/aboutdebugging/components/panel-menu-entry.js
devtools/client/aboutdebugging/components/panel-menu.js
devtools/client/aboutdebugging/components/tabs/panel.js
devtools/client/aboutdebugging/components/tabs/target.js
devtools/client/aboutdebugging/components/target-list.js
devtools/client/aboutdebugging/components/workers/multi-e10s-warning.js
devtools/client/aboutdebugging/components/workers/panel.js
devtools/client/aboutdebugging/components/workers/service-worker-target.js
devtools/client/aboutdebugging/components/workers/target.js
devtools/client/dom/content/components/dom-tree.js
devtools/client/dom/content/components/main-frame.js
devtools/client/dom/content/components/main-toolbar.js
devtools/client/framework/components/toolbox-controller.js
devtools/client/framework/components/toolbox-tab.js
devtools/client/framework/components/toolbox-tabs.js
devtools/client/framework/components/toolbox-toolbar.js
devtools/client/inspector/boxmodel/components/BoxModel.js
devtools/client/inspector/boxmodel/components/BoxModelApp.js
devtools/client/inspector/boxmodel/components/BoxModelEditable.js
devtools/client/inspector/boxmodel/components/BoxModelInfo.js
devtools/client/inspector/boxmodel/components/BoxModelMain.js
devtools/client/inspector/boxmodel/components/BoxModelProperties.js
devtools/client/inspector/boxmodel/components/ComputedProperty.js
devtools/client/inspector/components/inspector-tab-panel.js
devtools/client/inspector/fonts/components/App.js
devtools/client/inspector/fonts/components/Font.js
devtools/client/inspector/fonts/components/FontList.js
devtools/client/inspector/grids/components/Grid.js
devtools/client/inspector/grids/components/GridDisplaySettings.js
devtools/client/inspector/grids/components/GridItem.js
devtools/client/inspector/grids/components/GridList.js
devtools/client/inspector/grids/components/GridOutline.js
devtools/client/inspector/layout/components/Accordion.js
devtools/client/inspector/layout/components/App.js
devtools/client/inspector/layout/components/LayoutPromoteBar.js
devtools/client/jsonview/components/headers-panel.js
devtools/client/jsonview/components/headers.js
devtools/client/jsonview/components/json-panel.js
devtools/client/jsonview/components/main-tabbed-area.js
devtools/client/jsonview/components/reps/toolbar.js
devtools/client/jsonview/components/search-box.js
devtools/client/jsonview/components/text-panel.js
devtools/client/jsonview/viewer-config.js
devtools/client/memory/app.js
devtools/client/memory/components/census-header.js
devtools/client/memory/components/census-tree-item.js
devtools/client/memory/components/census.js
devtools/client/memory/components/dominator-tree-header.js
devtools/client/memory/components/dominator-tree-item.js
devtools/client/memory/components/dominator-tree.js
devtools/client/memory/components/heap.js
devtools/client/memory/components/individuals-header.js
devtools/client/memory/components/individuals.js
devtools/client/memory/components/list.js
devtools/client/memory/components/shortest-paths.js
devtools/client/memory/components/snapshot-list-item.js
devtools/client/memory/components/toolbar.js
devtools/client/memory/components/tree-map.js
devtools/client/netmonitor/src/components/headers-panel.js
devtools/client/netmonitor/src/components/monitor-panel.js
devtools/client/netmonitor/src/components/properties-view.js
devtools/client/netmonitor/src/components/request-list-column-cause.js
devtools/client/netmonitor/src/components/request-list-column-content-size.js
devtools/client/netmonitor/src/components/request-list-column-cookies.js
devtools/client/netmonitor/src/components/request-list-column-domain.js
devtools/client/netmonitor/src/components/request-list-column-duration.js
devtools/client/netmonitor/src/components/request-list-column-end-time.js
devtools/client/netmonitor/src/components/request-list-column-file.js
devtools/client/netmonitor/src/components/request-list-column-latency.js
devtools/client/netmonitor/src/components/request-list-column-method.js
devtools/client/netmonitor/src/components/request-list-column-protocol.js
devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
devtools/client/netmonitor/src/components/request-list-column-response-header.js
devtools/client/netmonitor/src/components/request-list-column-response-time.js
devtools/client/netmonitor/src/components/request-list-column-scheme.js
devtools/client/netmonitor/src/components/request-list-column-set-cookies.js
devtools/client/netmonitor/src/components/request-list-column-start-time.js
devtools/client/netmonitor/src/components/request-list-column-status.js
devtools/client/netmonitor/src/components/request-list-column-transferred-size.js
devtools/client/netmonitor/src/components/request-list-column-type.js
devtools/client/netmonitor/src/components/request-list-column-waterfall.js
devtools/client/netmonitor/src/components/request-list-content.js
devtools/client/netmonitor/src/components/request-list-empty-notice.js
devtools/client/netmonitor/src/components/request-list-header.js
devtools/client/netmonitor/src/components/request-list-item.js
devtools/client/netmonitor/src/components/response-panel.js
devtools/client/netmonitor/src/components/source-editor.js
devtools/client/netmonitor/src/components/statistics-panel.js
devtools/client/netmonitor/src/components/toolbar.js
devtools/client/performance/components/jit-optimizations-item.js
devtools/client/performance/components/jit-optimizations.js
devtools/client/performance/components/waterfall-tree.js
devtools/client/responsive.html/app.js
devtools/client/responsive.html/components/browser.js
devtools/client/responsive.html/components/device-adder.js
devtools/client/responsive.html/components/device-modal.js
devtools/client/responsive.html/components/device-selector.js
devtools/client/responsive.html/components/dpr-selector.js
devtools/client/responsive.html/components/global-toolbar.js
devtools/client/responsive.html/components/network-throttling-selector.js
devtools/client/responsive.html/components/resizable-viewport.js
devtools/client/responsive.html/components/viewport-dimension.js
devtools/client/responsive.html/components/viewport-toolbar.js
devtools/client/responsive.html/components/viewport.js
devtools/client/responsive.html/components/viewports.js
devtools/client/shared/components/autocomplete-popup.js
devtools/client/shared/components/frame.js
devtools/client/shared/components/h-split-box.js
devtools/client/shared/components/notification-box.js
devtools/client/shared/components/reps/reps.js
devtools/client/shared/components/search-box.js
devtools/client/shared/components/sidebar-toggle.js
devtools/client/shared/components/splitter/draggable.js
devtools/client/shared/components/splitter/split-box.js
devtools/client/shared/components/stack-trace.js
devtools/client/shared/components/tabs/tabbar.js
devtools/client/shared/components/tabs/tabs.js
devtools/client/shared/components/tree.js
devtools/client/shared/components/tree/label-cell.js
devtools/client/shared/components/tree/tree-cell.js
devtools/client/shared/components/tree/tree-header.js
devtools/client/shared/components/tree/tree-row.js
devtools/client/shared/components/tree/tree-view.js
devtools/client/webconsole/net/components/cookies-tab.js
devtools/client/webconsole/net/components/headers-tab.js
devtools/client/webconsole/net/components/net-info-body.js
devtools/client/webconsole/net/components/net-info-group-list.js
devtools/client/webconsole/net/components/net-info-group.js
devtools/client/webconsole/net/components/net-info-params.js
devtools/client/webconsole/net/components/params-tab.js
devtools/client/webconsole/net/components/post-tab.js
devtools/client/webconsole/net/components/response-tab.js
devtools/client/webconsole/net/components/size-limit.js
devtools/client/webconsole/net/components/spinner.js
devtools/client/webconsole/net/components/stacktrace-tab.js
devtools/client/webconsole/new-console-output/components/console-output.js
devtools/client/webconsole/new-console-output/components/console-table.js
devtools/client/webconsole/new-console-output/components/filter-bar.js
devtools/client/webconsole/new-console-output/components/message-container.js
devtools/client/webconsole/new-console-output/components/message.js
devtools/shared/mixinService.js
devtools/shared/moz.build
modules/libpref/init/all.js
--- a/devtools/client/aboutdebugging/components/aboutdebugging.js
+++ b/devtools/client/aboutdebugging/components/aboutdebugging.js
@@ -18,16 +18,18 @@ loader.lazyGetter(this, "TabsPanel",
   () => createFactory(require("./tabs/panel")));
 loader.lazyGetter(this, "WorkersPanel",
   () => createFactory(require("./workers/panel")));
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
 loader.lazyRequireGetter(this, "Telemetry",
   "devtools/client/shared/telemetry");
+loader.lazyRequireGetter(this, "mixinService",
+  "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const panels = [{
   id: "addons",
   name: Strings.GetStringFromName("addons"),
   icon: "chrome://devtools/skin/images/debugging-addons.svg",
@@ -44,16 +46,18 @@ const panels = [{
   component: WorkersPanel
 }];
 
 const defaultPanelId = "addons";
 
 module.exports = createClass({
   displayName: "AboutDebuggingApp",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     telemetry: PropTypes.instanceOf(Telemetry).isRequired
   },
 
   getInitialState() {
     return {
       selectedPanelId: defaultPanelId
--- a/devtools/client/aboutdebugging/components/addons/controls.js
+++ b/devtools/client/aboutdebugging/components/addons/controls.js
@@ -9,27 +9,32 @@
 
 loader.lazyImporter(this, "AddonManager",
   "resource://gre/modules/AddonManager.jsm");
 
 const { Cc, Ci } = require("chrome");
 const { createFactory, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
+
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const AddonsInstallError = createFactory(require("./install-error"));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const MORE_INFO_URL = "https://developer.mozilla.org/docs/Tools" +
                       "/about:debugging#Enabling_add-on_debugging";
 
 module.exports = createClass({
   displayName: "AddonsControls",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     debugDisabled: PropTypes.bool
   },
 
   getInitialState() {
     return {
       installError: null,
     };
--- a/devtools/client/aboutdebugging/components/addons/install-error.js
+++ b/devtools/client/aboutdebugging/components/addons/install-error.js
@@ -4,22 +4,26 @@
 
 /* eslint-env browser */
 "use strict";
 
 const { createClass, DOM: dom, PropTypes } = require("devtools/client/shared/vendor/react");
 
 const Services = require("Services");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "AddonsInstallError",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     error: PropTypes.string,
     retryInstall: PropTypes.func,
   },
 
   render() {
     if (!this.props.error) {
       return null;
--- a/devtools/client/aboutdebugging/components/addons/panel.js
+++ b/devtools/client/aboutdebugging/components/addons/panel.js
@@ -12,29 +12,33 @@ const Services = require("Services");
 
 const AddonsControls = createFactory(require("./controls"));
 const AddonTarget = createFactory(require("./target"));
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService",
+  "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 const CHROME_ENABLED_PREF = "devtools.chrome.enabled";
 const REMOTE_ENABLED_PREF = "devtools.debugger.remote-enabled";
 const WEB_EXT_URL = "https://developer.mozilla.org/Add-ons" +
                     "/WebExtensions/Getting_started_with_web-ext";
 
 module.exports = createClass({
   displayName: "AddonsPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     id: PropTypes.string.isRequired
   },
 
   getInitialState() {
     return {
       extensions: [],
--- a/devtools/client/aboutdebugging/components/addons/target.js
+++ b/devtools/client/aboutdebugging/components/addons/target.js
@@ -12,16 +12,18 @@ const { debugAddon, isTemporaryID, parse
   require("../../modules/addon");
 const Services = require("Services");
 
 loader.lazyImporter(this, "BrowserToolboxProcess",
   "resource://devtools/client/framework/ToolboxProcess.jsm");
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService",
+  "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const TEMP_ID_URL = "https://developer.mozilla.org/Add-ons" +
                     "/WebExtensions/WebExtensions_and_the_Add-on_ID";
 
 function filePathForTarget(target) {
@@ -120,16 +122,18 @@ function warningMessages(warnings = []) 
       { className: "addon-target-warning-message addon-target-message" },
       warning);
   });
 }
 
 module.exports = createClass({
   displayName: "AddonTarget",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     debugDisabled: PropTypes.bool,
     target: PropTypes.shape({
       addonActor: PropTypes.string.isRequired,
       addonID: PropTypes.string.isRequired,
       icon: PropTypes.string,
       name: PropTypes.string.isRequired,
--- a/devtools/client/aboutdebugging/components/panel-header.js
+++ b/devtools/client/aboutdebugging/components/panel-header.js
@@ -2,19 +2,23 @@
  * 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 { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "PanelHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     id: PropTypes.string.isRequired,
     name: PropTypes.string.isRequired
   },
 
   render() {
     let { name, id } = this.props;
 
--- a/devtools/client/aboutdebugging/components/panel-menu-entry.js
+++ b/devtools/client/aboutdebugging/components/panel-menu-entry.js
@@ -2,19 +2,23 @@
  * 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 { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "PanelMenuEntry",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     icon: PropTypes.string.isRequired,
     id: PropTypes.string.isRequired,
     name: PropTypes.string.isRequired,
     selected: PropTypes.bool,
     selectPanel: PropTypes.func.isRequired
   },
 
--- a/devtools/client/aboutdebugging/components/panel-menu.js
+++ b/devtools/client/aboutdebugging/components/panel-menu.js
@@ -3,19 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const PanelMenuEntry = createFactory(require("./panel-menu-entry"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "PanelMenu",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     panels: PropTypes.arrayOf(PropTypes.shape({
       id: PropTypes.string.isRequired,
       name: PropTypes.string.isRequired,
       icon: PropTypes.string.isRequired,
       component: PropTypes.func.isRequired
     })).isRequired,
     selectPanel: PropTypes.func.isRequired,
--- a/devtools/client/aboutdebugging/components/tabs/panel.js
+++ b/devtools/client/aboutdebugging/components/tabs/panel.js
@@ -9,25 +9,27 @@
 const { createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 const TabTarget = createFactory(require("./target"));
 
-loader.lazyRequireGetter(this, "DebuggerClient",
-  "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "TabsPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     id: PropTypes.string.isRequired
   },
 
   getInitialState() {
     return {
       tabs: []
--- a/devtools/client/aboutdebugging/components/tabs/target.js
+++ b/devtools/client/aboutdebugging/components/tabs/target.js
@@ -5,22 +5,26 @@
 /* eslint-env browser */
 
 "use strict";
 
 const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "TabTarget",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     target: PropTypes.shape({
       icon: PropTypes.string,
       outerWindowID: PropTypes.number.isRequired,
       title: PropTypes.string,
       url: PropTypes.string.isRequired
     }).isRequired
   },
--- a/devtools/client/aboutdebugging/components/target-list.js
+++ b/devtools/client/aboutdebugging/components/target-list.js
@@ -3,29 +3,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
-loader.lazyRequireGetter(this, "DebuggerClient",
-  "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const LocaleCompare = (a, b) => {
   return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
 };
 
 module.exports = createClass({
   displayName: "TargetList",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     debugDisabled: PropTypes.bool,
     error: PropTypes.node,
     id: PropTypes.string.isRequired,
     name: PropTypes.string,
     sort: PropTypes.bool,
     targetClass: PropTypes.func.isRequired,
--- a/devtools/client/aboutdebugging/components/workers/multi-e10s-warning.js
+++ b/devtools/client/aboutdebugging/components/workers/multi-e10s-warning.js
@@ -13,23 +13,27 @@ const { createClass, DOM: dom } =
 const Services = require("Services");
 const { Ci } = require("chrome");
 
 loader.lazyImporter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService",
+  "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle("chrome://devtools/locale/aboutdebugging.properties");
 const MULTI_OPT_OUT_PREF = "dom.ipc.multiOptOut";
 
 module.exports = createClass({
   displayName: "multiE10SWarning",
 
+  mixins: mixinService.mixins,
+
   onUpdatePreferenceClick() {
     let message = Strings.GetStringFromName("multiProcessWarningConfirmUpdate2");
     if (window.confirm(message)) {
       // Disable multi until at least the next experiment.
       Services.prefs.setIntPref(MULTI_OPT_OUT_PREF,
                                 Services.appinfo.E10S_MULTI_EXPERIMENT);
       // Restart the browser.
       Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
--- a/devtools/client/aboutdebugging/components/workers/panel.js
+++ b/devtools/client/aboutdebugging/components/workers/panel.js
@@ -19,29 +19,33 @@ const WorkerTarget = createFactory(requi
 const MultiE10SWarning = createFactory(require("./multi-e10s-warning"));
 const ServiceWorkerTarget = createFactory(require("./service-worker-target"));
 
 loader.lazyImporter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 loader.lazyRequireGetter(this, "DebuggerClient",
   "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService",
+  "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
 const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging" +
                       "#Service_workers_not_compatible";
 const PROCESS_COUNT_PREF = "dom.ipc.processCount";
 const MULTI_OPTOUT_PREF = "dom.ipc.multiOptOut";
 
 module.exports = createClass({
   displayName: "WorkersPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     id: PropTypes.string.isRequired
   },
 
   getInitialState() {
     return {
       workers: {
--- a/devtools/client/aboutdebugging/components/workers/service-worker-target.js
+++ b/devtools/client/aboutdebugging/components/workers/service-worker-target.js
@@ -6,25 +6,27 @@
 
 "use strict";
 
 const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { debugWorker } = require("../../modules/worker");
 const Services = require("Services");
 
-loader.lazyRequireGetter(this, "DebuggerClient",
-  "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "ServiceWorkerTarget",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     debugDisabled: PropTypes.bool,
     target: PropTypes.shape({
       active: PropTypes.bool,
       fetch: PropTypes.bool.isRequired,
       icon: PropTypes.string,
       name: PropTypes.string.isRequired,
--- a/devtools/client/aboutdebugging/components/workers/target.js
+++ b/devtools/client/aboutdebugging/components/workers/target.js
@@ -6,25 +6,27 @@
 
 "use strict";
 
 const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { debugWorker } = require("../../modules/worker");
 const Services = require("Services");
 
-loader.lazyRequireGetter(this, "DebuggerClient",
-  "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "WorkerTarget",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     client: PropTypes.instanceOf(DebuggerClient).isRequired,
     debugDisabled: PropTypes.bool,
     target: PropTypes.shape({
       icon: PropTypes.string,
       name: PropTypes.string.isRequired,
       workerActor: PropTypes.string
     }).isRequired
--- a/devtools/client/dom/content/components/dom-tree.js
+++ b/devtools/client/dom/content/components/dom-tree.js
@@ -4,16 +4,18 @@
  * 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";
 
 // React & Redux
 const React = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view"));
 
 // Reps
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 const Grip = REPS.Grip;
 
 // DOM Panel
@@ -24,16 +26,18 @@ const { DomDecorator } = require("../dom
 const PropTypes = React.PropTypes;
 
 /**
  * Renders DOM panel tree.
  */
 var DomTree = React.createClass({
   displayName: "DomTree",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     dispatch: PropTypes.func.isRequired,
     filter: PropTypes.string,
     grips: PropTypes.object,
     object: PropTypes.any,
     openLink: PropTypes.func,
   },
 
--- a/devtools/client/dom/content/components/main-frame.js
+++ b/devtools/client/dom/content/components/main-frame.js
@@ -6,31 +6,35 @@
  /* globals DomProvider */
 
 "use strict";
 
 // React & Redux
 const React = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // DOM Panel
 const DomTree = React.createFactory(require("./dom-tree"));
 const MainToolbar = React.createFactory(require("./main-toolbar"));
 
 // Shortcuts
 const { div } = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * Renders basic layout of the DOM panel. The DOM panel content consists
  * from two main parts: toolbar and tree.
  */
 var MainFrame = React.createClass({
   displayName: "MainFrame",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     dispatch: PropTypes.func.isRequired,
     filter: PropTypes.string,
     object: PropTypes.any,
   },
 
   /**
    * Render DOM panel content
--- a/devtools/client/dom/content/components/main-toolbar.js
+++ b/devtools/client/dom/content/components/main-toolbar.js
@@ -4,16 +4,18 @@
  * 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";
 
 // React
 const React = require("devtools/client/shared/vendor/react");
 const { l10n } = require("../utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Reps
 const { createFactories } = require("devtools/client/shared/react-utils");
 const { Toolbar, ToolbarButton } = createFactories(require("devtools/client/jsonview/components/reps/toolbar"));
 
 // DOM Panel
 const SearchBox = React.createFactory(require("devtools/client/shared/components/search-box"));
 
 // Actions
@@ -25,16 +27,18 @@ const PropTypes = React.PropTypes;
 
 /**
  * This template is responsible for rendering a toolbar
  * within the 'Headers' panel.
  */
 var MainToolbar = React.createClass({
   displayName: "MainToolbar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     object: PropTypes.any.isRequired,
     dispatch: PropTypes.func.isRequired,
   },
 
   onRefresh: function () {
     this.props.dispatch(fetchProperties(this.props.object));
   },
--- a/devtools/client/framework/components/toolbox-controller.js
+++ b/devtools/client/framework/components/toolbox-controller.js
@@ -2,25 +2,29 @@
  * 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 {createClass, createFactory} = require("devtools/client/shared/vendor/react");
 const ToolboxToolbar = createFactory(require("devtools/client/framework/components/toolbox-toolbar"));
 const ELEMENT_PICKER_ID = "command-button-pick";
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * This component serves as a state controller for the toolbox React component. It's a
  * thin layer for translating events and state of the outside world into the React update
  * cycle. This solution was used to keep the amount of code changes to a minimimum while
  * adapting the existing codebase to start using React.
  */
 module.exports = createClass({
   displayName: "ToolboxController",
 
+  mixins: mixinService.mixins,
+
   getInitialState() {
     // See the ToolboxToolbar propTypes for documentation on each of these items in state,
     // and for the defintions of the props that are expected to be passed in.
     return {
       focusedButton: ELEMENT_PICKER_ID,
       currentToolId: null,
       canRender: false,
       highlightedTool: "",
--- a/devtools/client/framework/components/toolbox-tab.js
+++ b/devtools/client/framework/components/toolbox-tab.js
@@ -1,19 +1,23 @@
 /* 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";
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const {DOM, createClass} = require("devtools/client/shared/vendor/react");
 const {img, button, span} = DOM;
 
 module.exports = createClass({
   displayName: "ToolboxTab",
 
+  mixins: mixinService.mixins,
+
   renderIcon(definition, isHighlighted) {
     const {icon, highlightedicon} = definition;
     if (!icon) {
       return [];
     }
     return [
       img({
         className: "default-icon",
--- a/devtools/client/framework/components/toolbox-tabs.js
+++ b/devtools/client/framework/components/toolbox-tabs.js
@@ -3,23 +3,27 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {DOM, createClass, createFactory, PropTypes} = require("devtools/client/shared/vendor/react");
 
 const {findDOMNode} = require("devtools/client/shared/vendor/react-dom");
 const {button, div} = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 
 module.exports = createClass({
   displayName: "ToolboxTabs",
 
+  mixins: mixinService.mixins,
+
   // See toolbox-toolbar propTypes for details on the props used here.
   propTypes: {
     currentToolId: PropTypes.string,
     focusButton: PropTypes.func,
     focusedButton: PropTypes.string,
     highlightedTool: PropTypes.string,
     panelDefinitions: PropTypes.array,
     selectTool: PropTypes.func,
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -1,28 +1,32 @@
 /* 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 {DOM, createClass, createFactory, PropTypes} = require("devtools/client/shared/vendor/react");
 const {div, button} = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 const ToolboxTabs = createFactory(require("devtools/client/framework/components/toolbox-tabs"));
 
 /**
  * This is the overall component for the toolbox toolbar. It is designed to not know how
  * the state is being managed, and attempts to be as pure as possible. The
  * ToolboxController component controls the changing state, and passes in everything as
  * props.
  */
 module.exports = createClass({
   displayName: "ToolboxToolbar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // The currently focused item (for arrow keyboard navigation)
     // This ID determines the tabindex being 0 or -1.
     focusedButton: PropTypes.string,
     // List of command button definitions.
     toolboxButtons: PropTypes.array,
     // The id of the currently selected tool, e.g. "inspector"
     currentToolId: PropTypes.string,
--- a/devtools/client/inspector/boxmodel/components/BoxModel.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModel.js
@@ -2,16 +2,18 @@
  * 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 { addons, createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const BoxModelInfo = createFactory(require("./BoxModelInfo"));
 const BoxModelMain = createFactory(require("./BoxModelMain"));
 const BoxModelProperties = createFactory(require("./BoxModelProperties"));
 
 const Types = require("../types");
 
 module.exports = createClass({
 
@@ -23,17 +25,17 @@ module.exports = createClass({
     showBoxModelProperties: PropTypes.bool.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelEditor: PropTypes.func.isRequired,
     onShowBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
     onToggleGeometryEditor: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   onKeyDown(event) {
     let { target } = event;
 
     if (target == this.boxModelContainer) {
       this.boxModelMain.onKeyDown(event);
     }
   },
--- a/devtools/client/inspector/boxmodel/components/BoxModelApp.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelApp.js
@@ -12,16 +12,18 @@ const { connect } = require("devtools/cl
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const Accordion =
   createFactory(require("devtools/client/inspector/layout/components/Accordion"));
 const BoxModel = createFactory(require("./BoxModel"));
 
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
 const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
 
 const BOXMODEL_OPENED_PREF = "devtools.computed.boxmodel.opened";
 
 const BoxModelApp = createClass({
 
   displayName: "BoxModelApp",
@@ -32,17 +34,17 @@ const BoxModelApp = createClass({
     showBoxModelProperties: PropTypes.bool.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelEditor: PropTypes.func.isRequired,
     onShowBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
     onToggleGeometryEditor: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     return Accordion({
       items: [
         {
           header: BOXMODEL_L10N.getStr("boxmodel.title"),
           component: BoxModel,
           componentProps: this.props,
--- a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js
@@ -3,33 +3,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { editableItem } = require("devtools/client/shared/inplace-editor");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const LONG_TEXT_ROTATE_LIMIT = 3;
 
 module.exports = createClass({
 
   displayName: "BoxModelEditable",
 
   propTypes: {
     box: PropTypes.string.isRequired,
     direction: PropTypes.string,
     focusable: PropTypes.bool.isRequired,
     level: PropTypes.string,
     property: PropTypes.string.isRequired,
     textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
     onShowBoxModelEditor: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   componentDidMount() {
     let { property, onShowBoxModelEditor } = this.props;
 
     editableItem({
       element: this.boxModelEditable,
     }, (element, event) => {
       onShowBoxModelEditor(element, event, property);
--- a/devtools/client/inspector/boxmodel/components/BoxModelInfo.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelInfo.js
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Types = require("../types");
 
 const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
 const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
 
 const SHARED_STRINGS_URI = "devtools/client/locales/shared.properties";
 const SHARED_L10N = new LocalizationHelper(SHARED_STRINGS_URI);
 
@@ -20,17 +22,17 @@ module.exports = createClass({
 
   displayName: "BoxModelInfo",
 
   propTypes: {
     boxModel: PropTypes.shape(Types.boxModel).isRequired,
     onToggleGeometryEditor: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   onToggleGeometryEditor(e) {
     this.props.onToggleGeometryEditor();
   },
 
   render() {
     let { boxModel } = this.props;
     let { geometryEditorEnabled, layout } = boxModel;
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -10,16 +10,18 @@ const { findDOMNode } = require("devtool
 const { KeyCodes } = require("devtools/client/shared/keycodes");
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const BoxModelEditable = createFactory(require("./BoxModelEditable"));
 
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
 const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
 
 const SHARED_STRINGS_URI = "devtools/client/locales/shared.properties";
 const SHARED_L10N = new LocalizationHelper(SHARED_STRINGS_URI);
 
 module.exports = createClass({
 
@@ -28,17 +30,17 @@ module.exports = createClass({
   propTypes: {
     boxModel: PropTypes.shape(Types.boxModel).isRequired,
     boxModelContainer: PropTypes.object,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelEditor: PropTypes.func.isRequired,
     onShowBoxModelHighlighter: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {
       activeDescendant: null,
       focusable: false,
     };
   },
 
--- a/devtools/client/inspector/boxmodel/components/BoxModelProperties.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelProperties.js
@@ -8,31 +8,33 @@ const { addons, createClass, createFacto
   require("devtools/client/shared/vendor/react");
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const ComputedProperty = createFactory(require("./ComputedProperty"));
 
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
 const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
 
 module.exports = createClass({
 
   displayName: "BoxModelProperties",
 
   propTypes: {
     boxModel: PropTypes.shape(Types.boxModel).isRequired,
     setSelectedNode: PropTypes.func.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {
       isOpen: true,
     };
   },
 
   /**
--- a/devtools/client/inspector/boxmodel/components/ComputedProperty.js
+++ b/devtools/client/inspector/boxmodel/components/ComputedProperty.js
@@ -4,31 +4,33 @@
 
 "use strict";
 
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "ComputedProperty",
 
   propTypes: {
     name: PropTypes.string.isRequired,
     value: PropTypes.string,
     referenceElement: PropTypes.object,
     referenceElementType: PropTypes.string,
     setSelectedNode: PropTypes.func.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   /**
    * While waiting for a reps fix in https://github.com/devtools-html/reps/issues/92,
    * translate nodeFront to a grip-like object that can be used with an ElementNode rep.
    *
    * @param  {NodeFront} nodeFront
    *         The NodeFront for which we want to create a grip-like object.
    * @return {Object} a grip-like object that can be used with Reps.
--- a/devtools/client/inspector/components/inspector-tab-panel.js
+++ b/devtools/client/inspector/components/inspector-tab-panel.js
@@ -6,24 +6,28 @@
 
 "use strict";
 
 const { DOM, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
 // Shortcuts
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Helper panel component that is using an existing DOM node
  * as the content. It's used by Sidebar as well as SplitBox
  * components.
  */
 var InspectorTabPanel = createClass({
   displayName: "InspectorTabPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // ID of the node that should be rendered as the content.
     id: PropTypes.string.isRequired,
     // Optional prefix for panel IDs.
     idPrefix: PropTypes.string,
     // Optional mount callback
     onMount: PropTypes.func,
   },
--- a/devtools/client/inspector/fonts/components/App.js
+++ b/devtools/client/inspector/fonts/components/App.js
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { addons, createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const SearchBox = createFactory(require("devtools/client/shared/components/search-box"));
 const FontList = createFactory(require("./FontList"));
 
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 const PREVIEW_UPDATE_DELAY = 150;
 
@@ -21,17 +23,17 @@ const App = createClass({
   displayName: "App",
 
   propTypes: {
     fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired,
     onPreviewFonts: PropTypes.func.isRequired,
     onShowAllFont: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let {
       fonts,
       onPreviewFonts,
       onShowAllFont,
     } = this.props;
 
--- a/devtools/client/inspector/fonts/components/Font.js
+++ b/devtools/client/inspector/fonts/components/Font.js
@@ -4,23 +4,25 @@
 
 "use strict";
 
 const { addons, createClass, DOM: dom, PropTypes } = require("devtools/client/shared/vendor/react");
 
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "Font",
 
   propTypes: PropTypes.shape(Types.font).isRequired,
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getSectionClasses() {
     let { font } = this.props;
 
     let classes = ["font"];
     classes.push((font.URI) ? "is-remote" : "is-local");
 
     if (font.rule) {
--- a/devtools/client/inspector/fonts/components/FontList.js
+++ b/devtools/client/inspector/fonts/components/FontList.js
@@ -6,25 +6,27 @@
 
 const { addons, createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Font = createFactory(require("./Font"));
 
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "FontList",
 
   propTypes: {
     fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let { fonts } = this.props;
 
     return dom.div(
       {
         id: "font-container"
       },
--- a/devtools/client/inspector/grids/components/Grid.js
+++ b/devtools/client/inspector/grids/components/Grid.js
@@ -9,16 +9,18 @@ const { addons, createClass, createFacto
 
 const GridDisplaySettings = createFactory(require("./GridDisplaySettings"));
 const GridList = createFactory(require("./GridList"));
 const GridOutline = createFactory(require("./GridOutline"));
 
 const Types = require("../types");
 const { getStr } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "Grid",
 
   propTypes: {
     getSwatchColorPickerTooltip: PropTypes.func.isRequired,
     grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
     highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
@@ -30,17 +32,17 @@ module.exports = createClass({
     onShowGridCellHighlight: PropTypes.func.isRequired,
     onShowGridLineNamesHighlight: PropTypes.func.isRequired,
     onToggleGridHighlighter: PropTypes.func.isRequired,
     onToggleShowGridAreas: PropTypes.func.isRequired,
     onToggleShowGridLineNumbers: PropTypes.func.isRequired,
     onToggleShowInfiniteLines: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let {
       getSwatchColorPickerTooltip,
       grids,
       highlighterSettings,
       setSelectedNode,
       onHideBoxModelHighlighter,
--- a/devtools/client/inspector/grids/components/GridDisplaySettings.js
+++ b/devtools/client/inspector/grids/components/GridDisplaySettings.js
@@ -5,28 +5,30 @@
 "use strict";
 
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const { getStr } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "GridDisplaySettings",
 
   propTypes: {
     highlighterSettings: PropTypes.shape(Types.highlighterSettings).isRequired,
     onToggleShowGridAreas: PropTypes.func.isRequired,
     onToggleShowGridLineNumbers: PropTypes.func.isRequired,
     onToggleShowInfiniteLines: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   onShowGridAreasCheckboxClick() {
     let {
       highlighterSettings,
       onToggleShowGridAreas,
     } = this.props;
 
     onToggleShowGridAreas(!highlighterSettings.showGridAreasOverlay);
--- a/devtools/client/inspector/grids/components/GridItem.js
+++ b/devtools/client/inspector/grids/components/GridItem.js
@@ -9,31 +9,33 @@ const { findDOMNode } = require("devtool
 
 // Reps
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 const ElementNode = REPS.ElementNode;
 
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "GridItem",
 
   propTypes: {
     getSwatchColorPickerTooltip: PropTypes.func.isRequired,
     grid: PropTypes.shape(Types.grid).isRequired,
     setSelectedNode: PropTypes.func.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onSetGridOverlayColor: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
     onToggleGridHighlighter: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, mixinService.mixins ],
 
   componentDidMount() {
     let tooltip = this.props.getSwatchColorPickerTooltip();
     let swatchEl = findDOMNode(this).querySelector(".grid-color-swatch");
 
     let previousColor;
     tooltip.addSwatch(swatchEl, {
       onCommit: this.setGridColor,
--- a/devtools/client/inspector/grids/components/GridList.js
+++ b/devtools/client/inspector/grids/components/GridList.js
@@ -7,31 +7,33 @@
 const { addons, createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const GridItem = createFactory(require("./GridItem"));
 
 const Types = require("../types");
 const { getStr } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "GridList",
 
   propTypes: {
     getSwatchColorPickerTooltip: PropTypes.func.isRequired,
     grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
     setSelectedNode: PropTypes.func.isRequired,
     onHideBoxModelHighlighter: PropTypes.func.isRequired,
     onSetGridOverlayColor: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
     onToggleGridHighlighter: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let {
       getSwatchColorPickerTooltip,
       grids,
       setSelectedNode,
       onHideBoxModelHighlighter,
       onSetGridOverlayColor,
--- a/devtools/client/inspector/grids/components/GridOutline.js
+++ b/devtools/client/inspector/grids/components/GridOutline.js
@@ -6,16 +6,18 @@
 
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Services = require("Services");
 const Types = require("../types");
 const { getStr } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // The delay prior to executing the grid cell highlighting.
 const GRID_HIGHLIGHTING_DEBOUNCE = 50;
 
 // Prefs for the max number of rows/cols a grid container can have for
 // the outline to display.
 const GRID_OUTLINE_MAX_ROWS_PREF =
   Services.prefs.getIntPref("devtools.gridinspector.gridOutlineMaxRows");
 const GRID_OUTLINE_MAX_COLUMNS_PREF =
@@ -36,17 +38,17 @@ module.exports = createClass({
   displayName: "GridOutline",
 
   propTypes: {
     grids: PropTypes.arrayOf(PropTypes.shape(Types.grid)).isRequired,
     onShowGridAreaHighlight: PropTypes.func.isRequired,
     onShowGridCellHighlight: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {
       height: 0,
       selectedGrid: null,
       showOutline: true,
       width: 0,
     };
--- a/devtools/client/inspector/layout/components/Accordion.js
+++ b/devtools/client/inspector/layout/components/Accordion.js
@@ -9,24 +9,26 @@
 
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 const { DOM: dom, PropTypes } = React;
 
 const { div, span } = dom;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Accordion = React.createClass({
   displayName: "Accordion",
 
   propTypes: {
     items: PropTypes.array
   },
 
-  mixins: [ React.addons.PureRenderMixin ],
+  mixins: [ React.addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState: function () {
     return { opened: this.props.items.map(item => item.opened),
              created: [] };
   },
 
   handleHeaderClick: function (i) {
     const opened = [...this.state.opened];
--- a/devtools/client/inspector/layout/components/App.js
+++ b/devtools/client/inspector/layout/components/App.js
@@ -6,16 +6,18 @@
 
 const Services = require("Services");
 const { addons, createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const BoxModel = createFactory(require("devtools/client/inspector/boxmodel/components/BoxModel"));
 const Grid = createFactory(require("devtools/client/inspector/grids/components/Grid"));
 
 const BoxModelTypes = require("devtools/client/inspector/boxmodel/types");
 const GridTypes = require("devtools/client/inspector/grids/types");
 
 const Accordion = createFactory(require("./Accordion"));
 const LayoutPromoteBar = createFactory(require("./LayoutPromoteBar"));
@@ -46,17 +48,17 @@ const App = createClass({
     onShowBoxModelEditor: PropTypes.func.isRequired,
     onShowBoxModelHighlighter: PropTypes.func.isRequired,
     onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
     onToggleGridHighlighter: PropTypes.func.isRequired,
     onToggleShowGridLineNumbers: PropTypes.func.isRequired,
     onToggleShowInfiniteLines: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let { onPromoteLearnMoreClick } = this.props;
 
     return dom.div(
       {
         id: "layout-container",
       },
--- a/devtools/client/inspector/layout/components/LayoutPromoteBar.js
+++ b/devtools/client/inspector/layout/components/LayoutPromoteBar.js
@@ -13,30 +13,32 @@
  */
 
 const Services = require("Services");
 const { addons, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
 const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
 
 const SHOW_PROMOTE_BAR_PREF = "devtools.promote.layoutview.showPromoteBar";
 
 module.exports = createClass({
 
   displayName: "LayoutPromoteBar",
 
   propTypes: {
     onPromoteLearnMoreClick: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {
       showPromoteBar: Services.prefs.getBoolPref(SHOW_PROMOTE_BAR_PREF)
     };
   },
 
   onPromoteCloseButtonClick() {
--- a/devtools/client/jsonview/components/headers-panel.js
+++ b/devtools/client/jsonview/components/headers-panel.js
@@ -11,23 +11,27 @@ define(function (require, exports, modul
 
   const { createFactories } = require("devtools/client/shared/react-utils");
 
   const { Headers } = createFactories(require("./headers"));
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
 
   const { div } = dom;
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   /**
    * This template represents the 'Headers' panel
    * s responsible for rendering its content.
    */
   let HeadersPanel = createClass({
     displayName: "HeadersPanel",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
       data: PropTypes.object,
     },
 
     getInitialState: function () {
       return {
         data: {}
@@ -50,16 +54,18 @@ define(function (require, exports, modul
 
   /**
    * This template is responsible for rendering a toolbar
    * within the 'Headers' panel.
    */
   let HeadersToolbar = createFactory(createClass({
     displayName: "HeadersToolbar",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
     },
 
     // Commands
 
     onCopy: function (event) {
       this.props.actions.onCopyHeaders();
--- a/devtools/client/jsonview/components/headers.js
+++ b/devtools/client/jsonview/components/headers.js
@@ -4,26 +4,30 @@
  * 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";
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   const { div, span, table, tbody, tr, td, } = dom;
 
   /**
    * This template is responsible for rendering basic layout
    * of the 'Headers' panel. It displays HTTP headers groups such as
    * received or response headers.
    */
   let Headers = createClass({
     displayName: "Headers",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       data: PropTypes.object,
     },
 
     getInitialState: function () {
       return {};
     },
 
@@ -55,16 +59,18 @@ define(function (require, exports, modul
 
   /**
    * This template renders headers list,
    * name + value pairs.
    */
   let HeaderList = createFactory(createClass({
     displayName: "HeaderList",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       headers: PropTypes.arrayOf(PropTypes.shape({
         name: PropTypes.string,
         value: PropTypes.string
       }))
     },
 
     getInitialState: function () {
--- a/devtools/client/jsonview/components/json-panel.js
+++ b/devtools/client/jsonview/components/json-panel.js
@@ -6,16 +6,18 @@
 
 "use strict";
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
   const TreeViewClass = require("devtools/client/shared/components/tree/tree-view");
   const TreeView = createFactory(TreeViewClass);
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
   const { createFactories } = require("devtools/client/shared/react-utils");
   const { Rep } = REPS;
 
   const { SearchBox } = createFactories(require("./search-box"));
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
 
   const { div } = dom;
@@ -29,16 +31,18 @@ define(function (require, exports, modul
   /**
    * This template represents the 'JSON' panel. The panel is
    * responsible for rendering an expandable tree that allows simple
    * inspection of JSON structure.
    */
   let JsonPanel = createClass({
     displayName: "JsonPanel",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       data: PropTypes.oneOfType([
         PropTypes.string,
         PropTypes.array,
         PropTypes.object
       ]),
       jsonTextLength: PropTypes.number,
       searchFilter: PropTypes.string,
@@ -140,16 +144,18 @@ define(function (require, exports, modul
   });
 
   /**
    * This template represents a toolbar within the 'JSON' panel.
    */
   let JsonToolbar = createFactory(createClass({
     displayName: "JsonToolbar",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
     },
 
     // Commands
 
     onSave: function (event) {
       this.props.actions.onSaveJson();
--- a/devtools/client/jsonview/components/main-tabbed-area.js
+++ b/devtools/client/jsonview/components/main-tabbed-area.js
@@ -10,23 +10,27 @@ define(function (require, exports, modul
   const { createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
   const { createFactories } = require("devtools/client/shared/react-utils");
   const { JsonPanel } = createFactories(require("./json-panel"));
   const { TextPanel } = createFactories(require("./text-panel"));
   const { HeadersPanel } = createFactories(require("./headers-panel"));
   const { Tabs, TabPanel } = createFactories(require("devtools/client/shared/components/tabs/tabs"));
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   /**
    * This object represents the root application template
    * responsible for rendering the basic tab layout.
    */
   let MainTabbedArea = createClass({
     displayName: "MainTabbedArea",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       jsonText: PropTypes.string,
       tabActive: PropTypes.number,
       actions: PropTypes.object,
       headers: PropTypes.object,
       searchFilter: PropTypes.string,
       json: PropTypes.oneOfType([
         PropTypes.string,
--- a/devtools/client/jsonview/components/reps/toolbar.js
+++ b/devtools/client/jsonview/components/reps/toolbar.js
@@ -5,22 +5,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const React = require("devtools/client/shared/vendor/react");
   const DOM = React.DOM;
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   /**
    * Renders a simple toolbar.
    */
   let Toolbar = React.createClass({
     displayName: "Toolbar",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       children: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.element
       ])
     },
 
     render: function () {
@@ -33,16 +37,18 @@ define(function (require, exports, modul
   });
 
   /**
    * Renders a simple toolbar button.
    */
   let ToolbarButton = React.createClass({
     displayName: "ToolbarButton",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       active: React.PropTypes.bool,
       disabled: React.PropTypes.bool,
       children: React.PropTypes.string,
     },
 
     render: function () {
       let props = Object.assign({className: "btn"}, this.props);
--- a/devtools/client/jsonview/components/search-box.js
+++ b/devtools/client/jsonview/components/search-box.js
@@ -4,28 +4,32 @@
  * 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";
 
 define(function (require, exports, module) {
   const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   const { input } = dom;
 
   // For smooth incremental searching (in case the user is typing quickly).
   const searchDelay = 250;
 
   /**
    * This object represents a search box located at the
    * top right corner of the application.
    */
   let SearchBox = createClass({
     displayName: "SearchBox",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
     },
 
     onSearch: function (event) {
       let searchBox = event.target;
       let win = searchBox.ownerDocument.defaultView;
 
--- a/devtools/client/jsonview/components/text-panel.js
+++ b/devtools/client/jsonview/components/text-panel.js
@@ -8,23 +8,27 @@
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
   const { createFactories } = require("devtools/client/shared/react-utils");
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
   const { div, pre } = dom;
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   /**
    * This template represents the 'Raw Data' panel displaying
    * JSON as a text received from the server.
    */
   let TextPanel = createClass({
     displayName: "TextPanel",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
       data: PropTypes.string
     },
 
     getInitialState: function () {
       return {};
     },
@@ -45,16 +49,18 @@ define(function (require, exports, modul
 
   /**
    * This object represents a toolbar displayed within the
    * 'Raw Data' panel.
    */
   let TextToolbar = createFactory(createClass({
     displayName: "TextToolbar",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       actions: PropTypes.object,
     },
 
     // Commands
 
     onPrettify: function (event) {
       this.props.actions.onPrettify();
--- a/devtools/client/jsonview/viewer-config.js
+++ b/devtools/client/jsonview/viewer-config.js
@@ -15,16 +15,22 @@
  *
  * In order to use the developer version you need to specify the following
  * in your .mozconfig (see also bug 1181646):
  * ac_add_options --enable-debug-js-modules
  *
  * React module ID is using exactly the same (relative) path as the rest
  * of the code base, so it's consistent and modules can be easily reused.
  */
+define("devtools/shared/mixinService", {
+  mixinService: {
+    mixins: []
+  }
+});
+
 require.config({
   baseUrl: "resource://devtools-client-jsonview/",
   paths: {
     "devtools/client/shared": "resource://devtools-client-shared",
     "devtools/shared": "resource://devtools/shared",
     "devtools/client/shared/vendor/react":
       JSONView.debug
       ? "resource://devtools-client-shared/vendor/react-dev"
--- a/devtools/client/memory/app.js
+++ b/devtools/client/memory/app.js
@@ -46,19 +46,23 @@ const {
 const { changeViewAndRefresh, popViewAndRefresh } = require("./actions/view");
 const { resizeShortestPaths } = require("./actions/sizes");
 const Toolbar = createFactory(require("./components/toolbar"));
 const List = createFactory(require("./components/list"));
 const SnapshotListItem = createFactory(require("./components/snapshot-list-item"));
 const Heap = createFactory(require("./components/heap"));
 const { app: appModel } = require("./models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const MemoryApp = createClass({
   displayName: "MemoryApp",
 
+  mixins: mixinService.mixins,
+
   propTypes: appModel,
 
   childContextTypes: {
     front: PropTypes.any,
     heapWorker: PropTypes.any,
     toolbox: PropTypes.any,
   },
 
--- a/devtools/client/memory/components/census-header.js
+++ b/devtools/client/memory/components/census-header.js
@@ -3,19 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { DOM: dom, createClass } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils");
 const models = require("../models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "CensusHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     diffing: models.diffingModel,
   },
 
   render() {
     let individualsCell;
     if (!this.props.diffing) {
       individualsCell = dom.span({
--- a/devtools/client/memory/components/census-tree-item.js
+++ b/devtools/client/memory/components/census-tree-item.js
@@ -10,19 +10,23 @@ const {
   createFactory,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { L10N, formatNumber, formatPercent } = require("../utils");
 const Frame = createFactory(require("devtools/client/shared/components/frame"));
 const { TREE_ROW_HEIGHT } = require("../constants");
 const models = require("../models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "CensusTreeItem",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     arrow: PropTypes.any,
     depth: PropTypes.number.isRequired,
     diffing: models.app.diffing,
     expanded: PropTypes.bool.isRequired,
     focused: PropTypes.bool.isRequired,
     getPercentBytes: PropTypes.func.isRequired,
     getPercentCount: PropTypes.func.isRequired,
--- a/devtools/client/memory/components/census.js
+++ b/devtools/client/memory/components/census.js
@@ -5,19 +5,23 @@
 "use strict";
 
 const { createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
 const Tree = createFactory(require("devtools/client/shared/components/tree"));
 const CensusTreeItem = createFactory(require("./census-tree-item"));
 const { TREE_ROW_HEIGHT } = require("../constants");
 const { censusModel, diffingModel } = require("../models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "Census",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     census: censusModel,
     onExpand: PropTypes.func.isRequired,
     onCollapse: PropTypes.func.isRequired,
     onFocus: PropTypes.func.isRequired,
     onViewSourceInDebugger: PropTypes.func.isRequired,
     onViewIndividuals: PropTypes.func.isRequired,
     diffing: diffingModel,
--- a/devtools/client/memory/components/dominator-tree-header.js
+++ b/devtools/client/memory/components/dominator-tree-header.js
@@ -2,19 +2,23 @@
  * 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 { DOM: dom, createClass } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "DominatorTreeHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: { },
 
   render() {
     return dom.div(
       {
         className: "header"
       },
 
--- a/devtools/client/memory/components/dominator-tree-item.js
+++ b/devtools/client/memory/components/dominator-tree-item.js
@@ -5,27 +5,33 @@
 "use strict";
 
 const { assert, isSavedFrame } = require("devtools/shared/DevToolsUtils");
 const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
 const { L10N, formatNumber, formatPercent } = require("../utils");
 const Frame = createFactory(require("devtools/client/shared/components/frame"));
 const { TREE_ROW_HEIGHT } = require("../constants");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Separator = createFactory(createClass({
   displayName: "Separator",
 
+  mixins: mixinService.mixins,
+
   render() {
     return dom.span({ className: "separator" }, "›");
   }
 }));
 
 module.exports = createClass({
   displayName: "DominatorTreeItem",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
     depth: PropTypes.number.isRequired,
     arrow: PropTypes.object,
     expanded: PropTypes.bool.isRequired,
     focused: PropTypes.bool.isRequired,
     getPercentSize: PropTypes.func.isRequired,
     onViewSourceInDebugger: PropTypes.func.isRequired,
--- a/devtools/client/memory/components/dominator-tree.js
+++ b/devtools/client/memory/components/dominator-tree.js
@@ -11,23 +11,27 @@ const Tree = createFactory(require("devt
 const DominatorTreeItem = createFactory(require("./dominator-tree-item"));
 const { L10N } = require("../utils");
 const { TREE_ROW_HEIGHT, dominatorTreeState } = require("../constants");
 const { dominatorTreeModel } = require("../models");
 const DominatorTreeLazyChildren = require("../dominator-tree-lazy-children");
 
 const DOMINATOR_TREE_AUTO_EXPAND_DEPTH = 3;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * A throbber that represents a subtree in the dominator tree that is actively
  * being incrementally loaded and fetched from the `HeapAnalysesWorker`.
  */
 const DominatorTreeSubtreeFetching = createFactory(createClass({
   displayName: "DominatorTreeSubtreeFetching",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     depth: PropTypes.number.isRequired,
     focused: PropTypes.bool.isRequired,
   },
 
   shouldComponentUpdate(nextProps, nextState) {
     return this.props.depth !== nextProps.depth
       || this.props.focused !== nextProps.focused;
@@ -55,16 +59,18 @@ const DominatorTreeSubtreeFetching = cre
 
 /**
  * A link to fetch and load more siblings in the dominator tree, when there are
  * already many loaded above.
  */
 const DominatorTreeSiblingLink = createFactory(createClass({
   displayName: "DominatorTreeSiblingLink",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     depth: PropTypes.number.isRequired,
     focused: PropTypes.bool.isRequired,
     item: PropTypes.instanceOf(DominatorTreeLazyChildren).isRequired,
     onLoadMoreSiblings: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps, nextState) {
@@ -103,16 +109,18 @@ const DominatorTreeSiblingLink = createF
 }));
 
 /**
  * The actual dominator tree rendered as an expandable and collapsible tree.
  */
 module.exports = createClass({
   displayName: "DominatorTree",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     dominatorTree: dominatorTreeModel.isRequired,
     onLoadMoreSiblings: PropTypes.func.isRequired,
     onViewSourceInDebugger: PropTypes.func.isRequired,
     onExpand: PropTypes.func.isRequired,
     onCollapse: PropTypes.func.isRequired,
     onFocus: PropTypes.func.isRequired,
   },
--- a/devtools/client/memory/components/heap.js
+++ b/devtools/client/memory/components/heap.js
@@ -23,16 +23,18 @@ const {
   censusState,
   treeMapState,
   dominatorTreeState,
   individualsState,
 } = require("../constants");
 const models = require("../models");
 const { snapshot: snapshotModel, diffingModel } = models;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Get the app state's current state atom.
  *
  * @see the relevant state string constants in `../constants.js`.
  *
  * @param {models.view} view
  * @param {snapshotModel} snapshot
  * @param {diffingModel} diffing
@@ -178,16 +180,18 @@ function getError(snapshot, diffing, ind
  *
  * The Heap component contains several panels for different states; an initial
  * state of only a button to take a snapshot, loading states, the census view
  * tree, the dominator tree, etc.
  */
 module.exports = createClass({
   displayName: "Heap",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onSnapshotClick: PropTypes.func.isRequired,
     onLoadMoreSiblings: PropTypes.func.isRequired,
     onCensusExpand: PropTypes.func.isRequired,
     onCensusCollapse: PropTypes.func.isRequired,
     onDominatorTreeExpand: PropTypes.func.isRequired,
     onDominatorTreeCollapse: PropTypes.func.isRequired,
     onCensusFocus: PropTypes.func.isRequired,
--- a/devtools/client/memory/components/individuals-header.js
+++ b/devtools/client/memory/components/individuals-header.js
@@ -2,19 +2,23 @@
  * 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 { DOM: dom, createClass } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "IndividualsHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: { },
 
   render() {
     return dom.div(
       {
         className: "header"
       },
 
--- a/devtools/client/memory/components/individuals.js
+++ b/devtools/client/memory/components/individuals.js
@@ -5,22 +5,26 @@
 "use strict";
 
 const { createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
 const Tree = createFactory(require("devtools/client/shared/components/tree"));
 const DominatorTreeItem = createFactory(require("./dominator-tree-item"));
 const { TREE_ROW_HEIGHT } = require("../constants");
 const models = require("../models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * The list of individuals in a census group.
  */
 module.exports = createClass({
   displayName: "Individuals",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onViewSourceInDebugger: PropTypes.func.isRequired,
     onFocus: PropTypes.func.isRequired,
     individuals: models.individuals,
     dominatorTree: models.dominatorTreeModel,
   },
 
   render() {
--- a/devtools/client/memory/components/list.js
+++ b/devtools/client/memory/components/list.js
@@ -1,24 +1,28 @@
 /* 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 { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Generic list component that takes another react component to represent
  * the children nodes as `itemComponent`, and a list of items to render
  * as that component with a click handler.
  */
 module.exports = createClass({
   displayName: "List",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     itemComponent: PropTypes.any.isRequired,
     onClick: PropTypes.func,
     items: PropTypes.array.isRequired,
   },
 
   render() {
     let { items, onClick, itemComponent: Item } = this.props;
--- a/devtools/client/memory/components/shortest-paths.js
+++ b/devtools/client/memory/components/shortest-paths.js
@@ -8,16 +8,18 @@ const {
   DOM: dom,
   createClass,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { isSavedFrame } = require("devtools/shared/DevToolsUtils");
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const { L10N } = require("../utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const GRAPH_DEFAULTS = {
   translate: [20, 20],
   scale: 1
 };
 
 const NO_STACK = "noStack";
 const NO_FILENAME = "noFilename";
 const ROOT_LIST = "JS::ubi::RootList";
@@ -48,16 +50,18 @@ function stringifyLabel(label, id) {
   }
 
   return `${sanitized.join(" › ")} @ 0x${id.toString(16)}`;
 }
 
 module.exports = createClass({
   displayName: "ShortestPaths",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     graph: PropTypes.shape({
       nodes: PropTypes.arrayOf(PropTypes.object),
       edges: PropTypes.arrayOf(PropTypes.object),
     }),
   },
 
   getInitialState() {
--- a/devtools/client/memory/components/snapshot-list-item.js
+++ b/devtools/client/memory/components/snapshot-list-item.js
@@ -11,19 +11,23 @@ const {
   getSnapshotTotals,
   getStatusText,
   snapshotIsDiffable,
   getSavedCensus
 } = require("../utils");
 const { diffingState } = require("../constants");
 const { snapshot: snapshotModel, app: appModel } = require("../models");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "SnapshotListItem",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onClick: PropTypes.func.isRequired,
     onSave: PropTypes.func.isRequired,
     onDelete: PropTypes.func.isRequired,
     item: snapshotModel.isRequired,
     index: PropTypes.number.isRequired,
     diffing: appModel.diffing,
   },
--- a/devtools/client/memory/components/toolbar.js
+++ b/devtools/client/memory/components/toolbar.js
@@ -4,19 +4,23 @@
 "use strict";
 
 const { assert } = require("devtools/shared/DevToolsUtils");
 const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils");
 const models = require("../models");
 const { viewState } = require("../constants");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "Toolbar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     censusDisplays: PropTypes.arrayOf(PropTypes.shape({
       displayName: PropTypes.string.isRequired,
     })).isRequired,
     censusDisplay: PropTypes.shape({
       displayName: PropTypes.string.isRequired,
     }).isRequired,
     onTakeSnapshotClick: PropTypes.func.isRequired,
--- a/devtools/client/memory/components/tree-map.js
+++ b/devtools/client/memory/components/tree-map.js
@@ -3,19 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { DOM: dom, createClass } = require("devtools/client/shared/vendor/react");
 const { treeMapModel } = require("../models");
 const startVisualization = require("./tree-map/start");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "TreeMap",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     treeMap: treeMapModel
   },
 
   getInitialState() {
     return {};
   },
 
--- a/devtools/client/netmonitor/src/components/headers-panel.js
+++ b/devtools/client/netmonitor/src/components/headers-panel.js
@@ -39,23 +39,27 @@ const REQUEST_HEADERS = L10N.getStr("req
 const REQUEST_HEADERS_FROM_UPLOAD = L10N.getStr("requestHeadersFromUpload");
 const RESPONSE_HEADERS = L10N.getStr("responseHeaders");
 const SUMMARY_ADDRESS = L10N.getStr("netmonitor.summary.address");
 const SUMMARY_METHOD = L10N.getStr("netmonitor.summary.method");
 const SUMMARY_URL = L10N.getStr("netmonitor.summary.url");
 const SUMMARY_STATUS = L10N.getStr("netmonitor.summary.status");
 const SUMMARY_VERSION = L10N.getStr("netmonitor.summary.version");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /*
  * Headers panel component
  * Lists basic information about the request
  */
 const HeadersPanel = createClass({
   displayName: "HeadersPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     cloneSelectedRequest: PropTypes.func.isRequired,
     request: PropTypes.object.isRequired,
     renderValue: PropTypes.func,
     openLink: PropTypes.func,
   },
 
   getInitialState() {
--- a/devtools/client/netmonitor/src/components/monitor-panel.js
+++ b/devtools/client/netmonitor/src/components/monitor-panel.js
@@ -21,23 +21,27 @@ const { getSelectedRequest } = require("
 // Components
 const SplitBox = createFactory(require("devtools/client/shared/components/splitter/split-box"));
 const NetworkDetailsPanel = createFactory(require("./network-details-panel"));
 const RequestList = createFactory(require("./request-list"));
 const Toolbar = createFactory(require("./toolbar"));
 const { div } = DOM;
 const MediaQueryList = window.matchMedia("(min-width: 700px)");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /*
  * Monitor panel component
  * The main panel for displaying various network request information
  */
 const MonitorPanel = createClass({
   displayName: "MonitorPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     isEmpty: PropTypes.bool.isRequired,
     networkDetailsOpen: PropTypes.bool.isRequired,
     openNetworkDetails: PropTypes.func.isRequired,
     request: PropTypes.object,
     // Service to enable the source map feature.
     sourceMapService: PropTypes.object,
     openLink: PropTypes.func,
--- a/devtools/client/netmonitor/src/components/properties-view.js
+++ b/devtools/client/netmonitor/src/components/properties-view.js
@@ -13,16 +13,18 @@ const {
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 
 const { FILTER_SEARCH_DELAY } = require("../constants");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Components
 const SearchBox = createFactory(require("devtools/client/shared/components/search-box"));
 const TreeViewClass = require("devtools/client/shared/components/tree/tree-view");
 const TreeView = createFactory(TreeViewClass);
 const TreeRow = createFactory(require("devtools/client/shared/components/tree/tree-row"));
 const SourceEditor = createFactory(require("./source-editor"));
 
 const { div, tr, td } = DOM;
@@ -38,16 +40,18 @@ const EDITOR_CONFIG_ID = "EDITOR_CONFIG"
  * Search filter - Set enableFilter to enable / disable SearchBox feature.
  * Tree view - Default enabled.
  * Source editor - Enable by specifying object level 1 property name to EDITOR_CONFIG_ID.
  * Rep - Default enabled.
  */
 const PropertiesView = createClass({
   displayName: "PropertiesView",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     object: PropTypes.object,
     enableInput: PropTypes.bool,
     expandableStrings: PropTypes.bool,
     filterPlaceHolder: PropTypes.string,
     sectionNames: PropTypes.array,
     openLink: PropTypes.func,
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-cause.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-cause.js
@@ -5,21 +5,25 @@
 "use strict";
 
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const { div } = DOM;
 
 const RequestListColumnCause = createClass({
   displayName: "RequestListColumnCause",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
     onCauseBadgeMouseDown: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.cause !== nextProps.item.cause;
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-content-size.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-content-size.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedSize } = require("../utils/format-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnContentSize = createClass({
   displayName: "RequestListColumnContentSize",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.contentSize !== nextProps.item.contentSize;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-cookies.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-cookies.js
@@ -7,19 +7,23 @@
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnCookies = createClass({
   displayName: "RequestListColumnCookies",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     let { requestCookies: currRequestCookies = { cookies: [] } } = this.props.item;
     let { requestCookies: nextRequestCookies = { cookies: [] } } = nextProps.item;
     currRequestCookies = currRequestCookies.cookies || currRequestCookies;
--- a/devtools/client/netmonitor/src/components/request-list-column-domain.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-domain.js
@@ -10,25 +10,29 @@ const {
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedIPAndPort } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const UPDATED_DOMAIN_PROPS = [
   "remoteAddress",
   "securityState",
   "urlDetails",
 ];
 
 const RequestListColumnDomain = createClass({
   displayName: "RequestListColumnDomain",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
     onSecurityIconMouseDown: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-duration.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-duration.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedTime } = require("../utils/format-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnDuration = createClass({
   displayName: "RequestListColumnDuration",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.totalTime !== nextProps.item.totalTime;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-end-time.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-end-time.js
@@ -9,19 +9,23 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedTime } = require("../utils/format-utils");
 const { getEndTime } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnEndTime = createClass({
   displayName: "RequestListColumnEndTime",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     firstRequestStartedMillis: PropTypes.number.isRequired,
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return getEndTime(this.props.item) !== getEndTime(nextProps.item);
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-file.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-file.js
@@ -8,24 +8,28 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div, img } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const UPDATED_FILE_PROPS = [
   "responseContentDataUri",
   "urlDetails",
 ];
 
 const RequestListColumnFile = createClass({
   displayName: "RequestListColumnFile",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
     onThumbnailMouseDown: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item);
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-latency.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-latency.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedTime } = require("../utils/format-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnLatency = createClass({
   displayName: "RequestListColumnLatency",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     let { eventTimings: currEventTimings = { timings: {} } } = this.props.item;
     let { eventTimings: nextEventTimings = { timings: {} } } = nextProps.item;
     return currEventTimings.timings.wait !== nextEventTimings.timings.wait;
--- a/devtools/client/netmonitor/src/components/request-list-column-method.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-method.js
@@ -7,19 +7,23 @@
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnMethod = createClass({
   displayName: "RequestListColumnMethod",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.method !== nextProps.item.method;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-protocol.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-protocol.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedProtocol } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnProtocol = createClass({
   displayName: "RequestListColumnProtocol",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return getFormattedProtocol(this.props.item) !==
       getFormattedProtocol(nextProps.item);
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-remote-ip.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedIPAndPort } = require("../utils/format-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnRemoteIP = createClass({
   displayName: "RequestListColumnRemoteIP",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.remoteAddress !== nextProps.item.remoteAddress;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-response-header.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-response-header.js
@@ -8,23 +8,27 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getResponseHeader } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Renders a response header column in the requests list.  The actual
  * header to show is passed as a prop.
  */
 const RequestListColumnResponseHeader = createClass({
   displayName: "RequestListColumnResponseHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
     header: PropTypes.string.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     const currHeader = getResponseHeader(this.props.item, this.props.header);
     const nextHeader = getResponseHeader(nextProps.item, nextProps.header);
--- a/devtools/client/netmonitor/src/components/request-list-column-response-time.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-response-time.js
@@ -9,19 +9,23 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedTime } = require("../utils/format-utils");
 const { getResponseTime } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnResponseTime = createClass({
   displayName: "RequestListColumnResponseTime",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     firstRequestStartedMillis: PropTypes.number.isRequired,
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return getResponseTime(this.props.item) !== getResponseTime(nextProps.item);
   },
--- a/devtools/client/netmonitor/src/components/request-list-column-scheme.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-scheme.js
@@ -7,19 +7,23 @@
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnScheme = createClass({
   displayName: "RequestListColumnScheme",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.urlDetails.scheme !== nextProps.item.urlDetails.scheme;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-set-cookies.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-set-cookies.js
@@ -7,19 +7,23 @@
 const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnSetCookies = createClass({
   displayName: "RequestListColumnSetCookies",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     let { responseCookies: currResponseCookies = { cookies: [] } } = this.props.item;
     let { responseCookies: nextResponseCookies = { cookies: [] } } = nextProps.item;
     currResponseCookies = currResponseCookies.cookies || currResponseCookies;
--- a/devtools/client/netmonitor/src/components/request-list-column-start-time.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-start-time.js
@@ -9,19 +9,23 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedTime } = require("../utils/format-utils");
 const { getStartTime } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnStartTime = createClass({
   displayName: "RequestListColumnStartTime",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     firstRequestStartedMillis: PropTypes.number.isRequired,
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return getStartTime(this.props.item, this.props.firstRequestStartedMillis)
       !== getStartTime(nextProps.item, nextProps.firstRequestStartedMillis);
--- a/devtools/client/netmonitor/src/components/request-list-column-status.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-status.js
@@ -9,26 +9,30 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils/l10n");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const UPDATED_STATUS_PROPS = [
   "fromCache",
   "fromServiceWorker",
   "status",
   "statusText",
 ];
 
 const RequestListColumnStatus = createClass({
   displayName: "RequestListColumnStatus",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_STATUS_PROPS, this.props.item, nextProps.item);
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-transferred-size.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-transferred-size.js
@@ -10,25 +10,29 @@ const {
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getFormattedSize } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const UPDATED_TRANSFERRED_PROPS = [
   "transferredSize",
   "fromCache",
   "fromServiceWorker",
 ];
 
 const RequestListColumnTransferredSize = createClass({
   displayName: "RequestListColumnTransferredSize",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_TRANSFERRED_PROPS, this.props.item, nextProps.item);
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-type.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-type.js
@@ -8,19 +8,23 @@ const {
   createClass,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { getAbbreviatedMimeType } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const RequestListColumnType = createClass({
   displayName: "RequestListColumnType",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.object.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return this.props.item.mimeType !== nextProps.item.mimeType;
   },
 
--- a/devtools/client/netmonitor/src/components/request-list-column-waterfall.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-waterfall.js
@@ -9,28 +9,32 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils/l10n");
 const { propertiesEqual } = require("../utils/request-utils");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const UPDATED_WATERFALL_PROPS = [
   "eventTimings",
   "fromCache",
   "fromServiceWorker",
   "totalTime",
 ];
 // List of properties of the timing info we want to create boxes for
 const TIMING_KEYS = ["blocked", "dns", "connect", "ssl", "send", "wait", "receive"];
 
 const RequestListColumnWaterfall = createClass({
   displayName: "RequestListColumnWaterfall",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     firstRequestStartedMillis: PropTypes.number.isRequired,
     item: PropTypes.object.isRequired,
     onWaterfallMouseDown: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_WATERFALL_PROPS, this.props.item, nextProps.item) ||
--- a/devtools/client/netmonitor/src/components/request-list-content.js
+++ b/devtools/client/netmonitor/src/components/request-list-content.js
@@ -14,31 +14,35 @@ const { connect } = require("devtools/cl
 const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
 const Actions = require("../actions/index");
 const { setTooltipImageContent } = require("../request-list-tooltip");
 const {
   getDisplayedRequests,
   getWaterfallScale,
 } = require("../selectors/index");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Components
 const RequestListItem = createFactory(require("./request-list-item"));
 const RequestListContextMenu = require("../request-list-context-menu");
 
 const { div } = DOM;
 
 // tooltip show/hide delay in ms
 const REQUESTS_TOOLTIP_TOGGLE_DELAY = 500;
 
 /**
  * Renders the actual contents of the request list.
  */
 const RequestListContent = createClass({
   displayName: "RequestListContent",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     columns: PropTypes.object.isRequired,
     dispatch: PropTypes.func.isRequired,
     displayedRequests: PropTypes.object.isRequired,
     firstRequestStartedMillis: PropTypes.number.isRequired,
     fromCache: PropTypes.bool,
     onCauseBadgeMouseDown: PropTypes.func.isRequired,
     onItemMouseDown: PropTypes.func.isRequired,
--- a/devtools/client/netmonitor/src/components/request-list-empty-notice.js
+++ b/devtools/client/netmonitor/src/components/request-list-empty-notice.js
@@ -12,28 +12,32 @@ const {
 } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const Actions = require("../actions/index");
 const { triggerActivity } = require("../connector/index");
 const { ACTIVITY_TYPE } = require("../constants");
 const { L10N } = require("../utils/l10n");
 const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Components
 const MDNLink = createFactory(require("./mdn-link"));
 
 const { button, div, span } = DOM;
 
 /**
  * UI displayed when the request list is empty. Contains instructions on reloading
  * the page and on triggering performance analysis of the page.
  */
 const RequestListEmptyNotice = createClass({
   displayName: "RequestListEmptyNotice",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onReloadClick: PropTypes.func.isRequired,
     onPerfClick: PropTypes.func.isRequired,
   },
 
   render() {
     return div(
       {
--- a/devtools/client/netmonitor/src/components/request-list-header.js
+++ b/devtools/client/netmonitor/src/components/request-list-header.js
@@ -17,24 +17,28 @@ const { HEADERS, REQUESTS_WATERFALL } = 
 const { getWaterfallScale } = require("../selectors/index");
 const { getFormattedTime } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const WaterfallBackground = require("../waterfall-background");
 const RequestListHeaderContextMenu = require("../request-list-header-context-menu");
 
 const { div, button } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Render the request list header with sorting arrows for columns.
  * Displays tick marks in the waterfall column header.
  * Also draws the waterfall background canvas and updates it when needed.
  */
 const RequestListHeader = createClass({
   displayName: "RequestListHeader",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     columns: PropTypes.object.isRequired,
     resetColumns: PropTypes.func.isRequired,
     resizeWaterfall: PropTypes.func.isRequired,
     scale: PropTypes.number,
     sort: PropTypes.object,
     sortBy: PropTypes.func.isRequired,
     toggleColumn: PropTypes.func.isRequired,
--- a/devtools/client/netmonitor/src/components/request-list-item.js
+++ b/devtools/client/netmonitor/src/components/request-list-item.js
@@ -33,16 +33,18 @@ const RequestListColumnSetCookies = crea
 const RequestListColumnStartTime = createFactory(require("./request-list-column-start-time"));
 const RequestListColumnStatus = createFactory(require("./request-list-column-status"));
 const RequestListColumnTransferredSize = createFactory(require("./request-list-column-transferred-size"));
 const RequestListColumnType = createFactory(require("./request-list-column-type"));
 const RequestListColumnWaterfall = createFactory(require("./request-list-column-waterfall"));
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * Used by shouldComponentUpdate: compare two items, and compare only properties
  * relevant for rendering the RequestListItem. Other properties (like request and
  * response headers, cookies, bodies) are ignored. These are very useful for the
  * network details, but not here.
  */
 const UPDATED_REQ_ITEM_PROPS = [
   "mimeType",
@@ -71,16 +73,18 @@ const UPDATED_REQ_PROPS = [
 ];
 
 /**
  * Render one row in the request list.
  */
 const RequestListItem = createClass({
   displayName: "RequestListItem",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     columns: PropTypes.object.isRequired,
     item: PropTypes.object.isRequired,
     index: PropTypes.number.isRequired,
     isSelected: PropTypes.bool.isRequired,
     firstRequestStartedMillis: PropTypes.number.isRequired,
     fromCache: PropTypes.bool,
     onCauseBadgeMouseDown: PropTypes.func.isRequired,
--- a/devtools/client/netmonitor/src/components/response-panel.js
+++ b/devtools/client/netmonitor/src/components/response-panel.js
@@ -19,23 +19,27 @@ const PropertiesView = createFactory(req
 const { div, img } = DOM;
 const JSON_SCOPE_NAME = L10N.getStr("jsonScopeName");
 const JSON_FILTER_TEXT = L10N.getStr("jsonFilterText");
 const RESPONSE_IMG_NAME = L10N.getStr("netmonitor.response.name");
 const RESPONSE_IMG_DIMENSIONS = L10N.getStr("netmonitor.response.dimensions");
 const RESPONSE_IMG_MIMETYPE = L10N.getStr("netmonitor.response.mime");
 const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /*
  * Response panel component
  * Displays the GET parameters and POST data of a request
  */
 const ResponsePanel = createClass({
   displayName: "ResponsePanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     request: PropTypes.object.isRequired,
     openLink: PropTypes.func,
   },
 
   getInitialState() {
     return {
       imageDimensions: {
--- a/devtools/client/netmonitor/src/components/source-editor.js
+++ b/devtools/client/netmonitor/src/components/source-editor.js
@@ -9,22 +9,26 @@ const {
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const Editor = require("devtools/client/sourceeditor/editor");
 const { SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE } = require("../constants");
 
 const { div } = DOM;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * CodeMirror editor as a React component
  */
 const SourceEditor = createClass({
   displayName: "SourceEditor",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // Source editor syntax hightligh mode, which is a mime type defined in CodeMirror
     mode: PropTypes.string,
     // Source editor content
     text: PropTypes.string,
   },
 
   componentDidMount() {
--- a/devtools/client/netmonitor/src/components/statistics-panel.js
+++ b/devtools/client/netmonitor/src/components/statistics-panel.js
@@ -18,16 +18,18 @@ const Actions = require("../actions/inde
 const { Filters } = require("../utils/filter-predicates");
 const {
   getSizeWithDecimals,
   getTimeWithDecimals
 } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
 const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Components
 const MDNLink = createFactory(require("./mdn-link"));
 
 const { button, div } = DOM;
 const MediaQueryList = window.matchMedia("(min-width: 700px)");
 
 const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
 const BACK_BUTTON = L10N.getStr("netmonitor.backButton");
@@ -37,16 +39,18 @@ const CHARTS_CACHE_DISABLED = L10N.getSt
 /*
  * Statistics panel component
  * Performance analysis tool which shows you how long the browser takes to
  * download the different parts of your site.
  */
 const StatisticsPanel = createClass({
   displayName: "StatisticsPanel",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     closeStatistics: PropTypes.func.isRequired,
     enableRequestFilterTypeOnly: PropTypes.func.isRequired,
     requests: PropTypes.object,
   },
 
   getInitialState() {
     return {
--- a/devtools/client/netmonitor/src/components/toolbar.js
+++ b/devtools/client/netmonitor/src/components/toolbar.js
@@ -19,16 +19,18 @@ const {
   getRequestFilterTypes,
   getTypeFilteredRequests,
   isNetworkDetailsToggleButtonDisabled,
 } = require("../selectors/index");
 
 const { autocompleteProvider } = require("../utils/filter-autocomplete-provider");
 const { L10N } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Components
 const SearchBox = createFactory(require("devtools/client/shared/components/search-box"));
 
 const { button, div, input, label, span } = DOM;
 
 const COLLPASE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
 const EXPAND_DETAILS_PANE = L10N.getStr("expandDetailsPane");
 const SEARCH_KEY_SHORTCUT = L10N.getStr("netmonitor.toolbar.filterFreetext.key");
@@ -40,16 +42,18 @@ const DEVTOOLS_ENABLE_PERSISTENT_LOG_PRE
 
 /*
  * Network monitor toolbar component
  * Toolbar contains a set of useful tools to control network requests
  */
 const Toolbar = createClass({
   displayName: "Toolbar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     clearRequests: PropTypes.func.isRequired,
     requestFilterTypes: PropTypes.array.isRequired,
     setRequestFilterText: PropTypes.func.isRequired,
     networkDetailsToggleDisabled: PropTypes.bool.isRequired,
     networkDetailsOpen: PropTypes.bool.isRequired,
     toggleNetworkDetails: PropTypes.func.isRequired,
     enablePersistentLogs: PropTypes.func.isRequired,
--- a/devtools/client/performance/components/jit-optimizations-item.js
+++ b/devtools/client/performance/components/jit-optimizations-item.js
@@ -13,16 +13,18 @@ const Frame = createFactory(require("dev
 const PROPNAME_MAX_LENGTH = 4;
 // If TREE_ROW_HEIGHT changes, be sure to change `var(--jit-tree-row-height)`
 // in `devtools/client/themes/jit-optimizations.css`
 const TREE_ROW_HEIGHT = 14;
 
 const OPTIMIZATION_ITEM_TYPES = ["site", "attempts", "types", "attempt", "type",
                                  "observedtype"];
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /* eslint-disable no-unused-vars */
 /**
  * TODO - Re-enable this eslint rule. The JIT tool is a work in progress, and isn't fully
  *        integrated as of yet.
  */
 const {
   JITOptimizations, hasSuccessfulOutcome, isSuccessfulOutcome
 } = require("devtools/client/performance/modules/logic/jit");
@@ -30,16 +32,18 @@ const OPTIMIZATION_FAILURE = L10N.getStr
 const JIT_SAMPLES = L10N.getStr("jit.samples");
 const JIT_TYPES = L10N.getStr("jit.types");
 const JIT_ATTEMPTS = L10N.getStr("jit.attempts");
 /* eslint-enable no-unused-vars */
 
 const JITOptimizationsItem = createClass({
   displayName: "JITOptimizationsItem",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onViewSourceInDebugger: PropTypes.func.isRequired,
     frameData: PropTypes.object.isRequired,
     type: PropTypes.oneOf(OPTIMIZATION_ITEM_TYPES).isRequired,
     depth: PropTypes.number.isRequired,
     arrow: PropTypes.element.isRequired,
     item: PropTypes.object,
     focused: PropTypes.bool
--- a/devtools/client/performance/components/jit-optimizations.js
+++ b/devtools/client/performance/components/jit-optimizations.js
@@ -12,16 +12,18 @@ const { DOM: dom, createClass, createFac
 const Tree = createFactory(require("../../shared/components/tree"));
 const OptimizationsItem = createFactory(require("./jit-optimizations-item"));
 const FrameView = createFactory(require("../../shared/components/frame"));
 const JIT_TITLE = L10N.getStr("jit.title");
 // If TREE_ROW_HEIGHT changes, be sure to change `var(--jit-tree-row-height)`
 // in `devtools/client/themes/jit-optimizations.css`
 const TREE_ROW_HEIGHT = 14;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /* eslint-disable no-unused-vars */
 /**
  * TODO - Re-enable this eslint rule. The JIT tool is a work in progress, and isn't fully
  *        integrated as of yet, and this may represent intended functionality.
  */
 const onClickTooltipString = frame =>
   L10N.getFormatStr("viewsourceindebugger",
                     `${frame.source}:${frame.line}:${frame.column}`);
@@ -56,16 +58,18 @@ const optimizationSiteModel = {
     attempts: PropTypes.arrayOf(optimizationAttemptModel).isRequired,
     types: PropTypes.arrayOf(optimizationIonTypeModel).isRequired,
   }).isRequired,
 };
 
 const JITOptimizations = createClass({
   displayName: "JITOptimizations",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onViewSourceInDebugger: PropTypes.func.isRequired,
     frameData: PropTypes.object.isRequired,
     optimizationSites: PropTypes.arrayOf(optimizationSiteModel).isRequired,
     autoExpandDepth: PropTypes.number,
   },
 
   getDefaultProps() {
--- a/devtools/client/performance/components/waterfall-tree.js
+++ b/devtools/client/performance/components/waterfall-tree.js
@@ -2,16 +2,18 @@
  * 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 { createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
 const Tree = createFactory(require("devtools/client/shared/components/tree"));
 const WaterfallTreeRow = createFactory(require("./waterfall-tree-row"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Keep in sync with var(--waterfall-tree-row-height) in performance.css
 const WATERFALL_TREE_ROW_HEIGHT = 15; // px
 
 /**
  * Checks if a given marker is in the specified time range.
  *
  * @param object e
  *        The marker containing the { start, end } timestamps.
@@ -36,16 +38,18 @@ function isMarkerInRange(e, start, end) 
     // overlap end
     (mEnd > end && mStart >= start && mStart <= end)
   );
 }
 
 const WaterfallTree = createClass({
   displayName: "WaterfallTree",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     marker: PropTypes.object.isRequired,
     startTime: PropTypes.number.isRequired,
     endTime: PropTypes.number.isRequired,
     dataScale: PropTypes.number.isRequired,
     sidebarWidth: PropTypes.number.isRequired,
     waterfallWidth: PropTypes.number.isRequired,
     onFocus: PropTypes.func,
--- a/devtools/client/responsive.html/app.js
+++ b/devtools/client/responsive.html/app.js
@@ -27,19 +27,23 @@ const {
   resizeViewport,
   rotateViewport,
 } = require("./actions/viewports");
 const DeviceModal = createFactory(require("./components/device-modal"));
 const GlobalToolbar = createFactory(require("./components/global-toolbar"));
 const Viewports = createFactory(require("./components/viewports"));
 const Types = require("./types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 let App = createClass({
   displayName: "App",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     dispatch: PropTypes.func.isRequired,
     displayPixelRatio: Types.pixelRatio.value.isRequired,
     networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
     viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
--- a/devtools/client/responsive.html/components/browser.js
+++ b/devtools/client/responsive.html/components/browser.js
@@ -10,33 +10,35 @@ const { Task } = require("devtools/share
 const flags = require("devtools/shared/flags");
 const { getToplevelWindow } = require("../utils/window");
 const { DOM: dom, createClass, addons, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const e10s = require("../utils/e10s");
 const message = require("../utils/message");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   /**
    * This component is not allowed to depend directly on frequently changing
    * data (width, height) due to the use of `dangerouslySetInnerHTML` below.
    * Any changes in props will cause the <iframe> to be removed and added again,
    * throwing away the current state of the page.
    */
   displayName: "Browser",
 
   propTypes: {
     swapAfterMount: PropTypes.bool.isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   /**
    * Once the browser element has mounted, load the frame script and enable
    * various features, like floating scrollbars.
    */
   componentDidMount: Task.async(function* () {
     // If we are not swapping browsers after mount, it's safe to start the frame
     // script now.
--- a/devtools/client/responsive.html/components/device-adder.js
+++ b/devtools/client/responsive.html/components/device-adder.js
@@ -8,26 +8,28 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const { getFormatStr, getStr } = require("../utils/l10n");
 const Types = require("../types");
 const ViewportDimension = createFactory(require("./viewport-dimension"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "DeviceAdder",
 
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     viewportTemplate: PropTypes.shape(Types.viewport).isRequired,
     onAddCustomDevice: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {};
   },
 
   componentWillReceiveProps(nextProps) {
     let {
       width,
--- a/devtools/client/responsive.html/components/device-modal.js
+++ b/devtools/client/responsive.html/components/device-modal.js
@@ -8,30 +8,32 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const { getStr, getFormatStr } = require("../utils/l10n");
 const Types = require("../types");
 const DeviceAdder = createFactory(require("./device-adder"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "DeviceModal",
 
   propTypes: {
     deviceAdderViewportTemplate: PropTypes.shape(Types.viewport).isRequired,
     devices: PropTypes.shape(Types.devices).isRequired,
     onAddCustomDevice: PropTypes.func.isRequired,
     onDeviceListUpdate: PropTypes.func.isRequired,
     onRemoveCustomDevice: PropTypes.func.isRequired,
     onUpdateDeviceDisplayed: PropTypes.func.isRequired,
     onUpdateDeviceModal: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {};
   },
 
   componentDidMount() {
     window.addEventListener("keydown", this.onKeyDown, true);
   },
--- a/devtools/client/responsive.html/components/device-selector.js
+++ b/devtools/client/responsive.html/components/device-selector.js
@@ -6,29 +6,31 @@
 
 const { getStr } = require("../utils/l10n");
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "DeviceSelector",
 
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     selectedDevice: PropTypes.string.isRequired,
     viewportId: PropTypes.number.isRequired,
     onChangeDevice: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onUpdateDeviceModal: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   onSelectChange({ target }) {
     let {
       devices,
       viewportId,
       onChangeDevice,
       onResizeViewport,
       onUpdateDeviceModal,
--- a/devtools/client/responsive.html/components/dpr-selector.js
+++ b/devtools/client/responsive.html/components/dpr-selector.js
@@ -7,16 +7,18 @@
 "use strict";
 
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const { getStr, getFormatStr } = require("../utils/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const PIXEL_RATIO_PRESET = [1, 2, 3];
 
 const createVisibleOption = value =>
   dom.option({
     value,
     title: value,
     key: value,
   }, value);
@@ -35,17 +37,17 @@ module.exports = createClass({
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     displayPixelRatio: Types.pixelRatio.value.isRequired,
     selectedDevice: PropTypes.string.isRequired,
     selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
     onChangePixelRatio: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   getInitialState() {
     return {
       isFocused: false
     };
   },
 
   onFocusChange({type}) {
--- a/devtools/client/responsive.html/components/global-toolbar.js
+++ b/devtools/client/responsive.html/components/global-toolbar.js
@@ -7,16 +7,18 @@
 const { DOM: dom, createClass, createFactory, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 const DPRSelector = createFactory(require("./dpr-selector"));
 const NetworkThrottlingSelector = createFactory(require("./network-throttling-selector"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "GlobalToolbar",
 
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     displayPixelRatio: Types.pixelRatio.value.isRequired,
     networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
@@ -25,17 +27,17 @@ module.exports = createClass({
     touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
     onChangeNetworkThrottling: PropTypes.func.isRequired,
     onChangePixelRatio: PropTypes.func.isRequired,
     onChangeTouchSimulation: PropTypes.func.isRequired,
     onExit: PropTypes.func.isRequired,
     onScreenshot: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let {
       devices,
       displayPixelRatio,
       networkThrottling,
       screenshot,
       selectedDevice,
--- a/devtools/client/responsive.html/components/network-throttling-selector.js
+++ b/devtools/client/responsive.html/components/network-throttling-selector.js
@@ -6,26 +6,28 @@
 
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const { getStr } = require("../utils/l10n");
 const throttlingProfiles = require("devtools/client/shared/network-throttling-profiles");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "NetworkThrottlingSelector",
 
   propTypes: {
     networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
     onChangeNetworkThrottling: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [addons.PureRenderMixin, ...mixinService.mixins ],
 
   onSelectChange({ target }) {
     let {
       onChangeNetworkThrottling,
     } = this.props;
 
     if (target.value == getStr("responsive.noThrottling")) {
       onChangeNetworkThrottling(false, "");
--- a/devtools/client/responsive.html/components/resizable-viewport.js
+++ b/devtools/client/responsive.html/components/resizable-viewport.js
@@ -9,23 +9,27 @@
 const { DOM: dom, createClass, createFactory, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Constants = require("../constants");
 const Types = require("../types");
 const Browser = createFactory(require("./browser"));
 const ViewportToolbar = createFactory(require("./viewport-toolbar"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION;
 const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;
 
 module.exports = createClass({
 
   displayName: "ResizableViewport",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     swapAfterMount: PropTypes.bool.isRequired,
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
--- a/devtools/client/responsive.html/components/viewport-dimension.js
+++ b/devtools/client/responsive.html/components/viewport-dimension.js
@@ -5,19 +5,23 @@
 "use strict";
 
 const { DOM: dom, createClass, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Constants = require("../constants");
 const Types = require("../types");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "ViewportDimension",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onChangeSize: PropTypes.func.isRequired,
     onRemoveDeviceAssociation: PropTypes.func.isRequired,
   },
 
   getInitialState() {
     let { width, height } = this.props.viewport;
--- a/devtools/client/responsive.html/components/viewport-toolbar.js
+++ b/devtools/client/responsive.html/components/viewport-toolbar.js
@@ -6,29 +6,31 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 const DeviceSelector = createFactory(require("./device-selector"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "ViewportToolbar",
 
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onChangeDevice: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onRotateViewport: PropTypes.func.isRequired,
     onUpdateDeviceModal: PropTypes.func.isRequired,
   },
 
-  mixins: [ addons.PureRenderMixin ],
+  mixins: [ addons.PureRenderMixin, ...mixinService.mixins ],
 
   render() {
     let {
       devices,
       viewport,
       onChangeDevice,
       onResizeViewport,
       onRotateViewport,
--- a/devtools/client/responsive.html/components/viewport.js
+++ b/devtools/client/responsive.html/components/viewport.js
@@ -6,20 +6,24 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const ResizableViewport = createFactory(require("./resizable-viewport"));
 const ViewportDimension = createFactory(require("./viewport-dimension"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "Viewport",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     swapAfterMount: PropTypes.bool.isRequired,
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
--- a/devtools/client/responsive.html/components/viewports.js
+++ b/devtools/client/responsive.html/components/viewports.js
@@ -5,20 +5,24 @@
 "use strict";
 
 const { DOM: dom, createClass, createFactory, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const Viewport = createFactory(require("./viewport"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
 
   displayName: "Viewports",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
     onRemoveDeviceAssociation: PropTypes.func.isRequired,
--- a/devtools/client/shared/components/autocomplete-popup.js
+++ b/devtools/client/shared/components/autocomplete-popup.js
@@ -1,19 +1,23 @@
 /* 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 { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "AutocompletePopup",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     /**
      * autocompleteProvider takes search-box's entire input text as `filter` argument
      * ie. "is:cached pr"
      * returned value is array of objects like below
      * [{value: "is:cached protocol", displayValue: "protocol"}[, ...]]
      * `value` is used to update the search-box input box for given item
      * `displayValue` is used to render the autocomplete list
--- a/devtools/client/shared/components/frame.js
+++ b/devtools/client/shared/components/frame.js
@@ -4,22 +4,26 @@
 
 "use strict";
 
 const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 const { getSourceNames, parseURL,
         isScratchpadScheme, getSourceMappedFile } = require("devtools/client/shared/source-utils");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const l10n = new LocalizationHelper("devtools/client/locales/components.properties");
 const webl10n = new LocalizationHelper("devtools/client/locales/webconsole.properties");
 
 module.exports = createClass({
   displayName: "Frame",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // SavedFrame, or an object containing all the required properties.
     frame: PropTypes.shape({
       functionDisplayName: PropTypes.string,
       source: PropTypes.string.isRequired,
       line: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
       column: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
     }).isRequired,
--- a/devtools/client/shared/components/h-split-box.js
+++ b/devtools/client/shared/components/h-split-box.js
@@ -25,19 +25,23 @@
 
 const {
   DOM: dom,
   createClass,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 const { assert } = require("devtools/shared/DevToolsUtils");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 module.exports = createClass({
   displayName: "HSplitBox",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // The contents of the start pane.
     start: PropTypes.any.isRequired,
 
     // The contents of the end pane.
     end: PropTypes.any.isRequired,
 
     // The relative width of the start pane, expressed as a number between 0 and
--- a/devtools/client/shared/components/notification-box.js
+++ b/devtools/client/shared/components/notification-box.js
@@ -4,16 +4,18 @@
 
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 const Immutable = require("devtools/client/shared/vendor/immutable");
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const l10n = new LocalizationHelper("devtools/client/locales/components.properties");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const { PropTypes, createClass, DOM } = React;
 const { div, span, button } = DOM;
 
 // Priority Levels
 const PriorityLevels = {
   PRIORITY_INFO_LOW: 1,
   PRIORITY_INFO_MEDIUM: 2,
@@ -32,16 +34,18 @@ const PriorityLevels = {
  * <xul:notificationbox> binding.
  *
  * See also MDN for more info about <xul:notificationbox>:
  * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/notificationbox
  */
 var NotificationBox = createClass({
   displayName: "NotificationBox",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // List of notifications appended into the box.
     notifications: PropTypes.arrayOf(PropTypes.shape({
       // label to appear on the notification.
       label: PropTypes.string.isRequired,
 
       // Value used to identify the notification
       value: PropTypes.string.isRequired,
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -5005,28 +5005,31 @@ module.exports = {
 
 /***/ }),
 /* 58 */
 /***/ (function(module, exports, __webpack_require__) {
 
 /* 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/. */
+const { mixinService } = require("devtools/shared/mixinService");
 
 const { DOM: dom, createClass, createFactory, PropTypes } = __webpack_require__(0);
 
 const AUTO_EXPAND_DEPTH = 0; // depth
 
 /**
  * An arrow that displays whether its node is expanded (â–¼) or collapsed
  * (â–¶). When its node has no children, it is hidden.
  */
 const ArrowExpander = createFactory(createClass({
   displayName: "ArrowExpander",
 
+  mixins: mixinService.mixins,
+
   shouldComponentUpdate(nextProps, nextState) {
     return this.props.item !== nextProps.item || this.props.visible !== nextProps.visible || this.props.expanded !== nextProps.expanded;
   },
 
   render() {
     const attrs = {
       className: "arrow theme-twisty",
       onClick: this.props.expanded ? () => this.props.onCollapse(this.props.item) : e => this.props.onExpand(this.props.item, e.altKey)
@@ -5044,16 +5047,18 @@ const ArrowExpander = createFactory(crea
 
     return dom.div(attrs, this.props.children);
   }
 }));
 
 const TreeNode = createFactory(createClass({
   displayName: "TreeNode",
 
+  mixins: mixinService.mixins,
+
   componentDidMount() {
     if (this.props.focused) {
       this.refs.button.focus();
     }
   },
 
   componentDidUpdate() {
     if (this.props.focused) {
@@ -5138,16 +5143,18 @@ const NUMBER_OF_OFFSCREEN_ITEMS = 1;
  * A generic tree component. See propTypes for the public API.
  *
  * @see `devtools/client/memory/components/test/mochitest/head.js` for usage
  * @see `devtools/client/memory/components/heap.js` for usage
  */
 const Tree = module.exports = createClass({
   displayName: "Tree",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // Required props
 
     // A function to get an item's parent, or null if it is a root.
     getParent: PropTypes.func.isRequired,
     // A function to get an item's children.
     getChildren: PropTypes.func.isRequired,
     // A function which takes an item and ArrowExpander and returns a
@@ -5726,37 +5733,37 @@ var freeGlobal = typeof global == 'objec
 module.exports = freeGlobal;
 
 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(65)))
 
 /***/ }),
 /* 65 */
 /***/ (function(module, exports) {
 
-var g;
-
-// This works in non-strict mode
-g = (function() {
-	return this;
-})();
-
-try {
-	// This works if eval is allowed (see CSP)
-	g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
-	// This works if the window reference is available
-	if(typeof window === "object")
-		g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
+var g;
+
+// This works in non-strict mode
+g = (function() {
+	return this;
+})();
+
+try {
+	// This works if eval is allowed (see CSP)
+	g = g || Function("return this")() || (1,eval)("this");
+} catch(e) {
+	// This works if the window reference is available
+	if(typeof window === "object")
+		g = window;
+}
+
+// g can still be undefined, but nothing to do about it...
+// We return undefined, instead of nothing here, so it's
+// easier to handle this case. if(!global) { ...}
+
+module.exports = g;
 
 
 /***/ }),
 /* 66 */
 /***/ (function(module, exports, __webpack_require__) {
 
 var Symbol = __webpack_require__(13);
 
--- a/devtools/client/shared/components/search-box.js
+++ b/devtools/client/shared/components/search-box.js
@@ -5,22 +5,26 @@
 /* global window */
 
 "use strict";
 
 const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
 const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
 const AutocompletePopup = createFactory(require("devtools/client/shared/components/autocomplete-popup"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * A generic search box component for use across devtools
  */
 module.exports = createClass({
   displayName: "SearchBox",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     delay: PropTypes.number,
     keyShortcut: PropTypes.string,
     onChange: PropTypes.func,
     placeholder: PropTypes.string,
     type: PropTypes.string,
     autocompleteProvider: PropTypes.func,
   },
--- a/devtools/client/shared/components/sidebar-toggle.js
+++ b/devtools/client/shared/components/sidebar-toggle.js
@@ -3,26 +3,30 @@
 /* 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 { DOM, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const { button } = DOM;
 
 /**
  * Sidebar toggle button. This button is used to exapand
  * and collapse Sidebar.
  */
 var SidebarToggle = createClass({
   displayName: "SidebarToggle",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // Set to true if collapsed.
     collapsed: PropTypes.bool.isRequired,
     // Tooltip text used when the button indicates expanded state.
     collapsePaneTitle: PropTypes.string.isRequired,
     // Tooltip text used when the button indicates collapsed state.
     expandPaneTitle: PropTypes.string.isRequired,
     // Click callback
--- a/devtools/client/shared/components/splitter/draggable.js
+++ b/devtools/client/shared/components/splitter/draggable.js
@@ -3,19 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const { DOM: dom, PropTypes } = React;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Draggable = React.createClass({
   displayName: "Draggable",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     onMove: PropTypes.func.isRequired,
     onStart: PropTypes.func,
     onStop: PropTypes.func,
     style: PropTypes.object,
     className: PropTypes.string
   },
 
--- a/devtools/client/shared/components/splitter/split-box.js
+++ b/devtools/client/shared/components/splitter/split-box.js
@@ -4,23 +4,27 @@
 
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const Draggable = React.createFactory(require("devtools/client/shared/components/splitter/draggable"));
 const { DOM: dom, PropTypes } = React;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 /**
  * This component represents a Splitter. The splitter supports vertical
  * as well as horizontal mode.
  */
 const SplitBox = React.createClass({
   displayName: "SplitBox",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // Custom class name. You can use more names separated by a space.
     className: PropTypes.string,
     // Initial size of controlled panel.
     initialSize: PropTypes.string,
     // Initial width of controlled panel.
     initialWidth: PropTypes.string,
     // Initial height of controlled panel.
--- a/devtools/client/shared/components/stack-trace.js
+++ b/devtools/client/shared/components/stack-trace.js
@@ -6,19 +6,23 @@
 
 const React = require("devtools/client/shared/vendor/react");
 const { DOM: dom, createClass, createFactory, PropTypes } = React;
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const Frame = createFactory(require("./frame"));
 
 const l10n = new LocalizationHelper("devtools/client/locales/webconsole.properties");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const AsyncFrame = createFactory(createClass({
   displayName: "AsyncFrame",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     asyncCause: PropTypes.string.isRequired
   },
 
   render() {
     let { asyncCause } = this.props;
 
     return dom.span(
@@ -26,16 +30,18 @@ const AsyncFrame = createFactory(createC
       l10n.getFormatStr("stacktrace.asyncStack", asyncCause)
     );
   }
 }));
 
 const StackTrace = createClass({
   displayName: "StackTrace",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     stacktrace: PropTypes.array.isRequired,
     onViewSourceInDebugger: PropTypes.func.isRequired,
     onViewSourceInScratchpad: PropTypes.func,
     // Service to enable the source map feature.
     sourceMapService: PropTypes.object,
   },
 
--- a/devtools/client/shared/components/tabs/tabbar.js
+++ b/devtools/client/shared/components/tabs/tabbar.js
@@ -9,25 +9,29 @@
 "use strict";
 
 const { DOM, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
 const Tabs = createFactory(require("devtools/client/shared/components/tabs/tabs").Tabs);
 
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const { div } = DOM;
 
 /**
  * Renders Tabbar component.
  */
 let Tabbar = createClass({
   displayName: "Tabbar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     children: PropTypes.array,
     menuDocument: PropTypes.object,
     onSelect: PropTypes.func,
     showAllTabsMenu: PropTypes.bool,
     activeTabId: PropTypes.string,
     renderOnlySelected: PropTypes.bool,
   },
--- a/devtools/client/shared/components/tabs/tabs.js
+++ b/devtools/client/shared/components/tabs/tabs.js
@@ -6,16 +6,18 @@
 
 "use strict";
 
 define(function (require, exports, module) {
   const React = require("devtools/client/shared/vendor/react");
   const { DOM } = React;
   const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   /**
    * Renders simple 'tab' widget.
    *
    * Based on ReactSimpleTabs component
    * https://github.com/pedronauck/react-simpletabs
    *
    * Component markup (+CSS) example:
    *
@@ -29,16 +31,18 @@ define(function (require, exports, modul
    *  <div class='panels'>
    *    The content of active panel here
    *  </div>
    * <div>
    */
   let Tabs = React.createClass({
     displayName: "Tabs",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       className: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.string,
         React.PropTypes.object
       ]),
       tabActive: React.PropTypes.number,
       onMount: React.PropTypes.func,
@@ -366,16 +370,18 @@ define(function (require, exports, modul
   });
 
   /**
    * Renders simple tab 'panel'.
    */
   let Panel = React.createClass({
     displayName: "Panel",
 
+    mixins: mixinService.mixins,
+
     propTypes: {
       title: React.PropTypes.string.isRequired,
       children: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.element
       ]).isRequired
     },
 
--- a/devtools/client/shared/components/tree.js
+++ b/devtools/client/shared/components/tree.js
@@ -2,16 +2,18 @@
  * 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/. */
 /* eslint-env browser */
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 const { DOM: dom, createClass, createFactory, PropTypes } = React;
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const AUTO_EXPAND_DEPTH = 0;
 const NUMBER_OF_OFFSCREEN_ITEMS = 1;
 
 /**
  * A fast, generic, expandable and collapsible tree component.
  *
  * This tree component is fast: it can handle trees with *many* items. It only
  * renders the subset of those items which are visible in the viewport. It's
@@ -95,16 +97,18 @@ const NUMBER_OF_OFFSCREEN_ITEMS = 1;
  *           onCollapse: item => dispatchCollapseActionToRedux(item),
  *         });
  *       }
  *     });
  */
 module.exports = createClass({
   displayName: "Tree",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     // Required props
 
     // A function to get an item's parent, or null if it is a root.
     //
     // Type: getParent(item: Item) -> Maybe<Item>
     //
     // Example:
@@ -660,16 +664,18 @@ module.exports = createClass({
 
 /**
  * An arrow that displays whether its node is expanded (â–¼) or collapsed
  * (â–¶). When its node has no children, it is hidden.
  */
 const ArrowExpander = createFactory(createClass({
   displayName: "ArrowExpander",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     item: PropTypes.any.isRequired,
     visible: PropTypes.bool.isRequired,
     expanded: PropTypes.bool.isRequired,
     onCollapse: PropTypes.func.isRequired,
     onExpand: PropTypes.func.isRequired,
   },
 
--- a/devtools/client/shared/components/tree/label-cell.js
+++ b/devtools/client/shared/components/tree/label-cell.js
@@ -5,26 +5,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 // Make this available to both AMD and CJS environments
 define(function (require, exports, module) {
   // ReactJS
   const React = require("devtools/client/shared/vendor/react");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   // Shortcuts
   const { td, span } = React.DOM;
   const PropTypes = React.PropTypes;
 
   /**
    * Render the default cell used for toggle buttons
    */
   let LabelCell = React.createClass({
     displayName: "LabelCell",
 
+    mixins: mixinService.mixins,
+
     // See the TreeView component for details related
     // to the 'member' object.
     propTypes: {
       id: PropTypes.string.isRequired,
       member: PropTypes.object.isRequired
     },
 
     render: function () {
--- a/devtools/client/shared/components/tree/tree-cell.js
+++ b/devtools/client/shared/components/tree/tree-cell.js
@@ -4,27 +4,31 @@
  * 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";
 
 // Make this available to both AMD and CJS environments
 define(function (require, exports, module) {
   const React = require("devtools/client/shared/vendor/react");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   // Shortcuts
   const { input, span, td } = React.DOM;
   const PropTypes = React.PropTypes;
 
   /**
    * This template represents a cell in TreeView row. It's rendered
    * using <td> element (the row is <tr> and the entire tree is <table>).
    */
   let TreeCell = React.createClass({
     displayName: "TreeCell",
 
+    mixins: mixinService.mixins,
+
     // See TreeView component for detailed property explanation.
     propTypes: {
       value: PropTypes.any,
       decorator: PropTypes.object,
       id: PropTypes.string.isRequired,
       member: PropTypes.object.isRequired,
       renderValue: PropTypes.func.isRequired,
       enableInput: PropTypes.bool,
--- a/devtools/client/shared/components/tree/tree-header.js
+++ b/devtools/client/shared/components/tree/tree-header.js
@@ -5,27 +5,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 // Make this available to both AMD and CJS environments
 define(function (require, exports, module) {
   // ReactJS
   const React = require("devtools/client/shared/vendor/react");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   // Shortcuts
   const { thead, tr, td, div } = React.DOM;
   const PropTypes = React.PropTypes;
 
   /**
    * This component is responsible for rendering tree header.
    * It's based on <thead> element.
    */
   let TreeHeader = React.createClass({
     displayName: "TreeHeader",
 
+    mixins: mixinService.mixins,
+
     // See also TreeView component for detailed info about properties.
     propTypes: {
       // Custom tree decorator
       decorator: PropTypes.object,
       // True if the header should be visible
       header: PropTypes.bool,
       // Array with column definition
       columns: PropTypes.array
--- a/devtools/client/shared/components/tree/tree-row.js
+++ b/devtools/client/shared/components/tree/tree-row.js
@@ -13,27 +13,31 @@ define(function (require, exports, modul
 
   // Tree
   const TreeCell = React.createFactory(require("./tree-cell"));
   const LabelCell = React.createFactory(require("./label-cell"));
 
   // Scroll
   const { scrollIntoViewIfNeeded } = require("devtools/client/shared/scroll");
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   // Shortcuts
   const { tr } = React.DOM;
   const PropTypes = React.PropTypes;
 
   /**
    * This template represents a node in TreeView component. It's rendered
    * using <tr> element (the entire tree is one big <table>).
    */
   let TreeRow = React.createClass({
     displayName: "TreeRow",
 
+    mixins: mixinService.mixins,
+
     // See TreeView component for more details about the props and
     // the 'member' object.
     propTypes: {
       member: PropTypes.shape({
         object: PropTypes.obSject,
         name: PropTypes.sring,
         type: PropTypes.string.isRequired,
         rowClass: PropTypes.string.isRequired,
--- a/devtools/client/shared/components/tree/tree-view.js
+++ b/devtools/client/shared/components/tree/tree-view.js
@@ -10,16 +10,18 @@ define(function (require, exports, modul
   // ReactJS
   const React = require("devtools/client/shared/vendor/react");
 
   // Reps
   const { ObjectProvider } = require("./object-provider");
   const TreeRow = React.createFactory(require("./tree-row"));
   const TreeHeader = React.createFactory(require("./tree-header"));
 
+  const { mixinService } = require("devtools/shared/mixinService");
+
   // Shortcuts
   const DOM = React.DOM;
   const PropTypes = React.PropTypes;
 
   /**
    * This component represents a tree view with expandable/collapsible nodes.
    * The tree is rendered using <table> element where every node is represented
    * by <tr> element. The tree is one big table where nodes (rows) are properly
@@ -51,16 +53,18 @@ define(function (require, exports, modul
    *   renderRow: function(object);
    *   renderCell: function(object, colId);
    *   renderLabelCell: function(object);
    * }
    */
   let TreeView = React.createClass({
     displayName: "TreeView",
 
+    mixins: mixinService.mixins,
+
     // The only required property (not set by default) is the input data
     // object that is used to puputate the tree.
     propTypes: {
       // The input data object.
       object: PropTypes.any,
       className: PropTypes.string,
       label: PropTypes.string,
       // Data provider (see also the interface above)
--- a/devtools/client/webconsole/net/components/cookies-tab.js
+++ b/devtools/client/webconsole/net/components/cookies-tab.js
@@ -2,16 +2,18 @@
  * 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 React = require("devtools/client/shared/vendor/react");
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents 'Cookies' tab displayed when the user
  * expands network log in the Console panel. It's responsible for rendering
  * sent and received cookies.
@@ -21,16 +23,18 @@ var CookiesTab = React.createClass({
     actions: PropTypes.shape({
       requestData: PropTypes.func.isRequired
     }),
     data: PropTypes.object.isRequired,
   },
 
   displayName: "CookiesTab",
 
+  mixins: mixinService.mixins,
+
   componentDidMount() {
     let { actions, data } = this.props;
     let requestCookies = data.request.cookies;
     let responseCookies = data.response.cookies;
 
     // TODO: use async action objects as soon as Redux is in place
     if (!requestCookies || !requestCookies.length) {
       actions.requestData("requestCookies");
--- a/devtools/client/webconsole/net/components/headers-tab.js
+++ b/devtools/client/webconsole/net/components/headers-tab.js
@@ -2,16 +2,18 @@
  * 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 React = require("devtools/client/shared/vendor/react");
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents 'Headers' tab displayed when the user
  * expands network log in the Console panel. It's responsible for rendering
  * request and response HTTP headers.
@@ -21,16 +23,18 @@ var HeadersTab = React.createClass({
     actions: PropTypes.shape({
       requestData: PropTypes.func.isRequired
     }),
     data: PropTypes.object.isRequired,
   },
 
   displayName: "HeadersTab",
 
+  mixins: mixinService.mixins,
+
   componentDidMount() {
     let { actions, data } = this.props;
     let requestHeaders = data.request.headers;
     let responseHeaders = data.response.headers;
 
     // Request headers if they are not available yet.
     // TODO: use async action objects as soon as Redux is in place
     if (!requestHeaders) {
--- a/devtools/client/webconsole/net/components/net-info-body.js
+++ b/devtools/client/webconsole/net/components/net-info-body.js
@@ -2,16 +2,18 @@
  * 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 React = require("devtools/client/shared/vendor/react");
 const { createFactories } = require("devtools/client/shared/react-utils");
 const { Tabs, TabPanel } = createFactories(require("devtools/client/shared/components/tabs/tabs"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Network
 const HeadersTab = React.createFactory(require("./headers-tab"));
 const ResponseTab = React.createFactory(require("./response-tab"));
 const ParamsTab = React.createFactory(require("./params-tab"));
 const CookiesTab = React.createFactory(require("./cookies-tab"));
 const PostTab = React.createFactory(require("./post-tab"));
 const StackTraceTab = React.createFactory(require("./stacktrace-tab"));
 const NetUtils = require("../utils/net");
@@ -40,16 +42,18 @@ var NetInfoBody = React.createClass({
       response: PropTypes.object.isRequired
     }),
     // Service to enable the source map feature.
     sourceMapService: PropTypes.object,
   },
 
   displayName: "NetInfoBody",
 
+  mixins: mixinService.mixins,
+
   getDefaultProps() {
     return {
       tabActive: 0
     };
   },
 
   getInitialState() {
     return {
--- a/devtools/client/webconsole/net/components/net-info-group-list.js
+++ b/devtools/client/webconsole/net/components/net-info-group-list.js
@@ -1,31 +1,35 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 const NetInfoGroup = React.createFactory(require("./net-info-group"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template is responsible for rendering sections/groups inside tabs.
  * It's used e.g to display Response and Request headers as separate groups.
  */
 var NetInfoGroupList = React.createClass({
   propTypes: {
     groups: PropTypes.array.isRequired,
   },
 
   displayName: "NetInfoGroupList",
 
+  mixins: mixinService.mixins,
+
   render() {
     let groups = this.props.groups;
 
     // Filter out empty groups.
     groups = groups.filter(group => {
       return group && ((group.params && group.params.length) || group.content);
     });
 
--- a/devtools/client/webconsole/net/components/net-info-group.js
+++ b/devtools/client/webconsole/net/components/net-info-group.js
@@ -1,16 +1,18 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 const NetInfoParams = React.createFactory(require("./net-info-params"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents a group of data within a tab. For example,
  * Headers tab has two groups 'Request Headers' and 'Response Headers'
  * The Response tab can also have two groups 'Raw Data' and 'JSON'
@@ -21,16 +23,18 @@ var NetInfoGroup = React.createClass({
     name: PropTypes.string.isRequired,
     params: PropTypes.array,
     content: PropTypes.element,
     open: PropTypes.bool
   },
 
   displayName: "NetInfoGroup",
 
+  mixins: mixinService.mixins,
+
   getDefaultProps() {
     return {
       open: true,
     };
   },
 
   getInitialState() {
     return {
--- a/devtools/client/webconsole/net/components/net-info-params.js
+++ b/devtools/client/webconsole/net/components/net-info-params.js
@@ -1,26 +1,30 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template renders list of parameters within a group.
  * It's essentially a list of name + value pairs.
  */
 var NetInfoParams = React.createClass({
   displayName: "NetInfoParams",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     params: PropTypes.arrayOf(PropTypes.shape({
       name: PropTypes.string.isRequired,
       value: PropTypes.string.isRequired
     })).isRequired,
   },
 
   render() {
--- a/devtools/client/webconsole/net/components/params-tab.js
+++ b/devtools/client/webconsole/net/components/params-tab.js
@@ -1,16 +1,18 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 const NetInfoParams = React.createFactory(require("./net-info-params"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents 'Params' tab displayed when the user
  * expands network log in the Console panel. It's responsible for
  * displaying URL parameters (query string).
@@ -19,16 +21,18 @@ var ParamsTab = React.createClass({
   propTypes: {
     data: PropTypes.shape({
       request: PropTypes.object.isRequired
     })
   },
 
   displayName: "ParamsTab",
 
+  mixins: mixinService.mixins,
+
   render() {
     let data = this.props.data;
 
     return (
       DOM.div({className: "paramsTabBox"},
         DOM.div({className: "panelContent"},
           NetInfoParams({params: data.request.queryString})
         )
--- a/devtools/client/webconsole/net/components/post-tab.js
+++ b/devtools/client/webconsole/net/components/post-tab.js
@@ -13,16 +13,18 @@ const { Rep } = REPS;
 // Network
 const NetInfoParams = React.createFactory(require("./net-info-params"));
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 const SizeLimit = React.createFactory(require("./size-limit"));
 const NetUtils = require("../utils/net");
 const Json = require("../utils/json");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents 'Post' tab displayed when the user
  * expands network log in the Console panel. It's responsible for
  * displaying posted data (HTTP post body).
@@ -32,16 +34,18 @@ var PostTab = React.createClass({
     data: PropTypes.shape({
       request: PropTypes.object.isRequired
     }),
     actions: PropTypes.object.isRequired
   },
 
   displayName: "PostTab",
 
+  mixins: mixinService.mixins,
+
   isJson(file) {
     let text = file.request.postData.text;
     let value = NetUtils.getHeaderValue(file.request.headers, "content-type");
     return Json.isJSON(value, text);
   },
 
   parseJson(file) {
     let postData = file.request.postData;
--- a/devtools/client/webconsole/net/components/response-tab.js
+++ b/devtools/client/webconsole/net/components/response-tab.js
@@ -12,16 +12,18 @@ const { Rep } = REPS;
 
 // Network
 const SizeLimit = React.createFactory(require("./size-limit"));
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 const Json = require("../utils/json");
 const NetUtils = require("../utils/net");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents 'Response' tab displayed when the user
  * expands network log in the Console panel. It's responsible for
  * rendering HTTP response body.
@@ -36,16 +38,18 @@ var ResponseTab = React.createClass({
       request: PropTypes.object.isRequired,
       response: PropTypes.object.isRequired
     }),
     actions: PropTypes.object.isRequired
   },
 
   displayName: "ResponseTab",
 
+  mixins: mixinService.mixins,
+
   // Response Types
 
   isJson(content) {
     if (isLongString(content.text)) {
       return false;
     }
 
     return Json.isJSON(content.mimeType, content.text);
--- a/devtools/client/webconsole/net/components/size-limit.js
+++ b/devtools/client/webconsole/net/components/size-limit.js
@@ -1,15 +1,17 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template represents a size limit notification message
  * used e.g. in the Response tab when response body exceeds
  * size limit. The message contains a link allowing the user
@@ -22,16 +24,18 @@ var SizeLimit = React.createClass({
     link: PropTypes.string.isRequired,
     actions: PropTypes.shape({
       resolveString: PropTypes.func.isRequired
     }),
   },
 
   displayName: "SizeLimit",
 
+  mixins: mixinService.mixins,
+
   // Event Handlers
 
   onClickLimit(event) {
     let actions = this.props.actions;
     let content = this.props.data;
 
     actions.resolveString(content, "text");
   },
--- a/devtools/client/webconsole/net/components/spinner.js
+++ b/devtools/client/webconsole/net/components/spinner.js
@@ -1,25 +1,29 @@
 /* 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 React = require("devtools/client/shared/vendor/react");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 // Shortcuts
 const DOM = React.DOM;
 
 /**
  * This template represents a throbber displayed when the UI
  * is waiting for data coming from the backend (debugging server).
  */
 var Spinner = React.createClass({
   displayName: "Spinner",
 
+  mixins: mixinService.mixins,
+
   render() {
     return (
       DOM.div({className: "devtools-throbber"})
     );
   }
 });
 
 // Exports from this module
--- a/devtools/client/webconsole/net/components/stacktrace-tab.js
+++ b/devtools/client/webconsole/net/components/stacktrace-tab.js
@@ -1,19 +1,23 @@
 /* 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 { PropTypes, createClass, createFactory } = require("devtools/client/shared/vendor/react");
 const StackTrace = createFactory(require("devtools/client/shared/components/stack-trace"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const StackTraceTab = createClass({
   displayName: "StackTraceTab",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     data: PropTypes.object.isRequired,
     actions: PropTypes.shape({
       onViewSourceInDebugger: PropTypes.func.isRequired
     }),
     // Service to enable the source map feature.
     sourceMapService: PropTypes.object,
   },
--- a/devtools/client/webconsole/new-console-output/components/console-output.js
+++ b/devtools/client/webconsole/new-console-output/components/console-output.js
@@ -21,20 +21,24 @@ const {
   getVisibleMessages,
   getAllRepeatById,
 } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer);
 const {
   MESSAGE_TYPE,
 } = require("devtools/client/webconsole/new-console-output/constants");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const ConsoleOutput = createClass({
 
   displayName: "ConsoleOutput",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     messages: PropTypes.object.isRequired,
     messagesUi: PropTypes.object.isRequired,
     serviceContainer: PropTypes.shape({
       attachRefToHud: PropTypes.func.isRequired,
       openContextMenu: PropTypes.func.isRequired,
       sourceMapService: PropTypes.object,
     }),
--- a/devtools/client/webconsole/new-console-output/components/console-table.js
+++ b/devtools/client/webconsole/new-console-output/components/console-table.js
@@ -10,23 +10,27 @@ const {
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { ObjectClient } = require("devtools/shared/client/main");
 const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
 const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const { MODE } = require("devtools/client/shared/components/reps/reps");
 const GripMessageBody = createFactory(require("devtools/client/webconsole/new-console-output/components/grip-message-body"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const TABLE_ROW_MAX_ITEMS = 1000;
 const TABLE_COLUMN_MAX_ITEMS = 10;
 
 const ConsoleTable = createClass({
 
   displayName: "ConsoleTable",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     dispatch: PropTypes.func.isRequired,
     parameters: PropTypes.array.isRequired,
     serviceContainer: PropTypes.shape({
       hudProxyClient: PropTypes.object.isRequired,
     }),
     id: PropTypes.string.isRequired,
     tableData: PropTypes.object,
--- a/devtools/client/webconsole/new-console-output/components/filter-bar.js
+++ b/devtools/client/webconsole/new-console-output/components/filter-bar.js
@@ -18,20 +18,24 @@ const { PluralForm } = require("devtools
 const {
   DEFAULT_FILTERS,
   FILTERS,
 } = require("../constants");
 
 const FilterButton = require("devtools/client/webconsole/new-console-output/components/filter-button");
 const FilterCheckbox = require("devtools/client/webconsole/new-console-output/components/filter-checkbox");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const FilterBar = createClass({
 
   displayName: "FilterBar",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     dispatch: PropTypes.func.isRequired,
     filter: PropTypes.object.isRequired,
     serviceContainer: PropTypes.shape({
       attachRefToHud: PropTypes.func.isRequired,
     }).isRequired,
     filterBarVisible: PropTypes.bool.isRequired,
     persistLogs: PropTypes.bool.isRequired,
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -12,28 +12,32 @@ const {
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 
 const {
   MESSAGE_SOURCE,
   MESSAGE_TYPE
 } = require("devtools/client/webconsole/new-console-output/constants");
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const componentMap = new Map([
   ["ConsoleApiCall", require("./message-types/console-api-call")],
   ["ConsoleCommand", require("./message-types/console-command")],
   ["DefaultRenderer", require("./message-types/default-renderer")],
   ["EvaluationResult", require("./message-types/evaluation-result")],
   ["NetworkEventMessage", require("./message-types/network-event-message")],
   ["PageError", require("./message-types/page-error")]
 ]);
 
 const MessageContainer = createClass({
   displayName: "MessageContainer",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     messageId: PropTypes.string.isRequired,
     open: PropTypes.bool.isRequired,
     serviceContainer: PropTypes.object.isRequired,
     tableData: PropTypes.object,
     timestampsVisible: PropTypes.bool.isRequired,
     repeat: PropTypes.number,
     networkMessageUpdate: PropTypes.object,
--- a/devtools/client/webconsole/new-console-output/components/message.js
+++ b/devtools/client/webconsole/new-console-output/components/message.js
@@ -18,19 +18,23 @@ const actions = require("devtools/client
 const {MESSAGE_SOURCE} = require("devtools/client/webconsole/new-console-output/constants");
 const CollapseButton = require("devtools/client/webconsole/new-console-output/components/collapse-button");
 const MessageIndent = require("devtools/client/webconsole/new-console-output/components/message-indent").MessageIndent;
 const MessageIcon = require("devtools/client/webconsole/new-console-output/components/message-icon");
 const MessageRepeat = require("devtools/client/webconsole/new-console-output/components/message-repeat");
 const FrameView = createFactory(require("devtools/client/shared/components/frame"));
 const StackTrace = createFactory(require("devtools/client/shared/components/stack-trace"));
 
+loader.lazyRequireGetter(this, "mixinService", "devtools/shared/mixinService", true);
+
 const Message = createClass({
   displayName: "Message",
 
+  mixins: mixinService.mixins,
+
   propTypes: {
     open: PropTypes.bool,
     collapsible: PropTypes.bool,
     collapseTitle: PropTypes.string,
     source: PropTypes.string.isRequired,
     type: PropTypes.string.isRequired,
     level: PropTypes.string.isRequired,
     indent: PropTypes.number.isRequired,
new file mode 100644
--- /dev/null
+++ b/devtools/shared/mixinService.js
@@ -0,0 +1,115 @@
+/* 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/. */
+/* globals Services */
+
+"use strict";
+
+const { Cu } = require("chrome");
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+const lodash = require("devtools/client/shared/vendor/lodash");
+
+const whyDidYouUpdateFilter =
+  Services.prefs.getStringPref("devtools.performance.measure.whydidyouupdate.filter");
+
+const MATCH_OPERATORS_REGEX = /[|\\{}()[\]^$+*?.]/g;
+
+class MixinService {
+  constructor() {
+    this.whyDidYouUpdateEnabled =
+      Services.prefs.getBoolPref("devtools.performance.measure.whydidyouupdate");
+  }
+
+  get mixins() {
+    let _mixins = [];
+
+    if (this.whyDidYouUpdateEnabled) {
+      _mixins.push(WhyDidYouUpdateMixin);
+    }
+
+    return _mixins;
+  }
+}
+
+const WhyDidYouUpdateMixin = {
+  componentDidUpdate(prevProps, prevState) {
+    this.deepDiff({props: prevProps, state: prevState},
+                  {props: this.props, state: this.state},
+                  this.constructor.displayName);
+  },
+
+  isRequiredUpdateObject(o) {
+    return Array.isArray(o) || (o && o.constructor === Object.prototype.constructor);
+  },
+
+  deepDiff(prev, next, name) {
+    if (!this.shouldIncludeComponent()) {
+      return;
+    }
+
+    const notify = (status) => {
+      console.warn(status);
+      console.log("before ", prev);
+      console.log("after ", next);
+    };
+
+    if (!lodash.isEqual(prev, next)) {
+      console.group(name);
+      if ([prev, next].every(lodash.isFunction)) {
+        notify("Value is a function. Possible avoidable re-render?");
+      } else if (![prev, next].every(this.isRequiredUpdateObject)) {
+        notify("Unavoidable re-render.");
+      } else {
+        const allKeys = lodash.union(lodash.keys(prev), lodash.keys(next));
+        for (const currKey of allKeys) {
+          this.deepDiff(prev[currKey], next[currKey], currKey);
+        }
+      }
+      console.groupEnd();
+    } else if (prev !== next) {
+      console.group(name);
+      notify("Value did not change. Avoidable re-render!");
+      if (lodash.isObject(prev) && lodash.isObject(next)) {
+        const allKeys = lodash.union(lodash.keys(prev), lodash.keys(next));
+        for (const currKey of allKeys) {
+          this.deepDiff(prev[currKey], next[currKey], currKey);
+        }
+      }
+      console.groupEnd();
+    }
+  },
+
+  shouldIncludeComponent() {
+    let filter = whyDidYouUpdateFilter;
+
+    if (!filter) {
+      return true;
+    }
+
+    let name = this.constructor.displayName;
+
+    // First check for a regular expression.
+    if (filter.startsWith("/") && filter.endsWith("/")) {
+      filter = filter.substr(1, filter.length - 2);
+
+      let pattern = filter.replace(MATCH_OPERATORS_REGEX, "\\$&");
+
+      try {
+        let rx = new RegExp(pattern);
+        return rx.test(name);
+      } catch (e) {
+        // Do nothing
+      }
+    }
+
+    // Check for a string match.
+    return name === filter;
+  }
+};
+
+// Make this.mixinService a singleton.
+if (!this.mixinService) {
+  this.mixinService = new MixinService();
+}
+
+exports.mixinService = this.mixinService;
--- a/devtools/shared/moz.build
+++ b/devtools/shared/moz.build
@@ -57,16 +57,17 @@ DevToolsModules(
     'extend.js',
     'flags.js',
     'generate-uuid.js',
     'indentation.js',
     'indexed-db.js',
     'l10n.js',
     'loader-plugin-raw.jsm',
     'Loader.jsm',
+    'mixinService.js',
     'old-event-emitter.js',
     'Parser.jsm',
     'path.js',
     'plural-form.js',
     'protocol.js',
     'system.js',
     'task.js',
     'ThreadSafeDevToolsUtils.js',
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1064,16 +1064,20 @@ pref("devtools.debugger.forbid-certified
 pref("devtools.defaultColorUnit", "authored");
 
 // Used for devtools debugging
 pref("devtools.dump.emit", false);
 
 // Controls whether EventEmitter module throws dump message on each emit
 pref("toolkit.dump.emit", false);
 
+// Performance measurement options
+pref("devtools.performance.measure.whydidyouupdate", false);
+pref("devtools.performance.measure.whydidyouupdate.filter", "");
+
 // Disable device discovery logging
 pref("devtools.discovery.log", false);
 // Whether to scan for DevTools devices via WiFi
 pref("devtools.remote.wifi.scan", true);
 // Whether UI options for controlling device visibility over WiFi are shown
 // N.B.: This does not set whether the device can be discovered via WiFi, only
 // whether the UI control to make such a choice is shown to the user
 pref("devtools.remote.wifi.visible", true);