Bug 1525332 - Lazy load components and modules we don't need right away at console initialization; r=Honza.
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Wed, 06 Feb 2019 14:00:59 +0000
changeset 457605 dda7c63c1c185ca67f5bb7a67855f3d96f407edc
parent 457604 526f7b418884ec46195b4f7f03f14d7a609bb248
child 457606 6836ad129868dac54c41b17f0d70f6e5c962506e
push id35516
push userrmaries@mozilla.com
push dateFri, 08 Feb 2019 04:23:26 +0000
treeherdermozilla-central@d599d1a73a3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1525332
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1525332 - Lazy load components and modules we don't need right away at console initialization; r=Honza. There was quite some file that was required directly but that may not be used until later (or maybe never), which means we were doing extra work. Lazily loading those files seems to improve opening time significantly. Differential Revision: https://phabricator.services.mozilla.com/D18819
devtools/client/webconsole/components/App.js
devtools/client/webconsole/components/ConsoleOutput.js
devtools/client/webconsole/components/ConsoleTable.js
devtools/client/webconsole/components/FilterBar.js
devtools/client/webconsole/components/Message.js
devtools/client/webconsole/components/MessageContainer.js
devtools/client/webconsole/components/ReverseSearchInput.js
devtools/client/webconsole/components/SideBar.js
devtools/client/webconsole/reducers/messages.js
devtools/client/webconsole/reducers/notifications.js
devtools/client/webconsole/utils/object-inspector.js
--- a/devtools/client/webconsole/components/App.js
+++ b/devtools/client/webconsole/components/App.js
@@ -1,16 +1,16 @@
 /* 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 Services = require("Services");
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
 
 const actions = require("devtools/client/webconsole/actions/index");
 const ConsoleOutput = createFactory(require("devtools/client/webconsole/components/ConsoleOutput"));
 const FilterBar = createFactory(require("devtools/client/webconsole/components/FilterBar"));
 const SideBar = createFactory(require("devtools/client/webconsole/components/SideBar"));
 const ReverseSearchInput = createFactory(require("devtools/client/webconsole/components/ReverseSearchInput"));
--- a/devtools/client/webconsole/components/ConsoleOutput.js
+++ b/devtools/client/webconsole/components/ConsoleOutput.js
@@ -1,30 +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 { Component, createFactory } = require("devtools/client/shared/vendor/react");
+const { Component, createElement } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
 const {initialize} = require("devtools/client/webconsole/actions/ui");
-const {sortBy} = require("devtools/client/shared/vendor/lodash");
 
 const {
   getAllMessagesById,
   getAllMessagesUiById,
   getAllMessagesTableDataById,
   getAllNetworkMessagesUpdateById,
   getVisibleMessages,
   getPausedExecutionPoint,
   getAllRepeatById,
 } = require("devtools/client/webconsole/selectors/messages");
-const MessageContainer = createFactory(require("devtools/client/webconsole/components/MessageContainer").MessageContainer);
+
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "sortBy", "devtools/client/shared/vendor/lodash", true);
+loader.lazyRequireGetter(this, "MessageContainer", "devtools/client/webconsole/components/MessageContainer", true);
+
 const {
   MESSAGE_TYPE,
 } = require("devtools/client/webconsole/constants");
 const {
   getInitialMessageCountForViewport,
 } = require("devtools/client/webconsole/utils/messages.js");
 
 function getClosestMessage(visibleMessages, messages, executionPoint) {
@@ -163,32 +165,33 @@ class ConsoleOutput extends Component {
         visibleMessages = visibleMessages.slice(
           visibleMessages.length - numberMessagesFitViewport);
       }
     }
 
     const pausedMessage = getClosestMessage(
       visibleMessages, messages, pausedExecutionPoint);
 
-    const messageNodes = visibleMessages.map((messageId) => MessageContainer({
-      dispatch,
-      key: messageId,
-      messageId,
-      serviceContainer,
-      open: messagesUi.includes(messageId),
-      tableData: messagesTableData.get(messageId),
-      timestampsVisible,
-      repeat: messagesRepeat[messageId],
-      networkMessageUpdate: networkMessagesUpdate[messageId],
-      networkMessageActiveTabId,
-      pausedExecutionPoint,
-      getMessage: () => messages.get(messageId),
-      isPaused: !!pausedMessage && pausedMessage.id == messageId,
-      maybeScrollToBottom: this.maybeScrollToBottom,
-    }));
+    const messageNodes = visibleMessages.map((messageId) =>
+      createElement(MessageContainer, {
+        dispatch,
+        key: messageId,
+        messageId,
+        serviceContainer,
+        open: messagesUi.includes(messageId),
+        tableData: messagesTableData.get(messageId),
+        timestampsVisible,
+        repeat: messagesRepeat[messageId],
+        networkMessageUpdate: networkMessagesUpdate[messageId],
+        networkMessageActiveTabId,
+        pausedExecutionPoint,
+        getMessage: () => messages.get(messageId),
+        isPaused: !!pausedMessage && pausedMessage.id == messageId,
+        maybeScrollToBottom: this.maybeScrollToBottom,
+      }));
 
     return (
       dom.div({
         className: "webconsole-output",
         onContextMenu: this.onContextMenu,
         ref: node => {
           this.outputNode = node;
         },
--- a/devtools/client/webconsole/components/ConsoleTable.js
+++ b/devtools/client/webconsole/components/ConsoleTable.js
@@ -1,22 +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 { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const ObjectClient = require("devtools/shared/client/object-client");
 const actions = require("devtools/client/webconsole/actions/messages");
 const { l10n } = require("devtools/client/webconsole/utils/messages");
 const { MODE } = require("devtools/client/shared/components/reps/reps");
 const GripMessageBody = createFactory(require("devtools/client/webconsole/components/GripMessageBody"));
 
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+
 const TABLE_ROW_MAX_ITEMS = 1000;
 const TABLE_COLUMN_MAX_ITEMS = 10;
 
 class ConsoleTable extends Component {
   static get propTypes() {
     return {
       dispatch: PropTypes.func.isRequired,
       parameters: PropTypes.array.isRequired,
--- a/devtools/client/webconsole/components/FilterBar.js
+++ b/devtools/client/webconsole/components/FilterBar.js
@@ -1,31 +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 { Component } = require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { getAllFilters } = require("devtools/client/webconsole/selectors/filters");
 const { getFilteredMessagesCount } = require("devtools/client/webconsole/selectors/messages");
 const { getAllUi } = require("devtools/client/webconsole/selectors/ui");
 const actions = require("devtools/client/webconsole/actions/index");
 const { l10n } = require("devtools/client/webconsole/utils/messages");
 const { PluralForm } = require("devtools/shared/plural-form");
 const {
   DEFAULT_FILTERS,
   FILTERS,
 } = require("../constants");
 
 const FilterButton = require("devtools/client/webconsole/components/FilterButton");
 const FilterCheckbox = require("devtools/client/webconsole/components/FilterCheckbox");
 
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+
 class FilterBar extends Component {
   static get propTypes() {
     return {
       dispatch: PropTypes.func.isRequired,
       filter: PropTypes.object.isRequired,
       serviceContainer: PropTypes.shape({
         attachRefToHud: PropTypes.func.isRequired,
       }).isRequired,
--- a/devtools/client/webconsole/components/Message.js
+++ b/devtools/client/webconsole/components/Message.js
@@ -2,35 +2,29 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
 // React & Redux
-const { Component, createFactory } = require("devtools/client/shared/vendor/react");
+const { Component, createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const { l10n } =
-  require("devtools/client/webconsole/utils/messages");
-const actions =
-  require("devtools/client/webconsole/actions/index");
-const { MESSAGE_SOURCE, MESSAGE_TYPE } =
-  require("devtools/client/webconsole/constants");
-const CollapseButton =
-  require("devtools/client/webconsole/components/CollapseButton");
-const { MessageIndent } =
-  require("devtools/client/webconsole/components/MessageIndent");
-const MessageIcon =
-  require("devtools/client/webconsole/components/MessageIcon");
-const MessageRepeat =
-  require("devtools/client/webconsole/components/MessageRepeat");
+const { l10n } = require("devtools/client/webconsole/utils/messages");
+const actions = require("devtools/client/webconsole/actions/index");
+const { MESSAGE_SOURCE, MESSAGE_TYPE } = require("devtools/client/webconsole/constants");
+const { MessageIndent } = require("devtools/client/webconsole/components/MessageIndent");
+const MessageIcon = require("devtools/client/webconsole/components/MessageIcon");
 const FrameView = createFactory(require("devtools/client/shared/components/Frame"));
-const SmartTrace = createFactory(require("devtools/client/shared/components/SmartTrace"));
+
+loader.lazyRequireGetter(this, "CollapseButton", "devtools/client/webconsole/components/CollapseButton");
+loader.lazyRequireGetter(this, "MessageRepeat", "devtools/client/webconsole/components/MessageRepeat");
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "SmartTrace", "devtools/client/shared/components/SmartTrace");
 
 class Message extends Component {
   static get propTypes() {
     return {
       open: PropTypes.bool,
       collapsible: PropTypes.bool,
       collapseTitle: PropTypes.string,
       source: PropTypes.string.isRequired,
@@ -199,33 +193,33 @@ class Message extends Component {
     let attachment = null;
     if (this.props.attachment) {
       attachment = this.props.attachment;
     } else if (stacktrace && open) {
       attachment = dom.div(
         {
           className: "stacktrace devtools-monospace",
         },
-        SmartTrace({
+        createElement(SmartTrace, {
           stacktrace,
           onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger
             || serviceContainer.onViewSource,
           onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad
             || serviceContainer.onViewSource,
           onViewSource: serviceContainer.onViewSource,
           onReady: this.props.maybeScrollToBottom,
           sourceMapService: serviceContainer.sourceMapService,
         }),
       );
     }
 
     // If there is an expandable part, make it collapsible.
     let collapse = null;
     if (collapsible) {
-      collapse = CollapseButton({
+      collapse = createElement(CollapseButton, {
         open,
         title: collapseTitle,
         onClick: this.toggleMessage,
       });
     }
 
     let notesNodes;
     if (notes) {
@@ -245,18 +239,19 @@ class Message extends Component {
               ? serviceContainer.sourceMapService
               : undefined,
           }) : null
         )));
     } else {
       notesNodes = [];
     }
 
-    const repeat = this.props.repeat && this.props.repeat > 1 ?
-      MessageRepeat({repeat: this.props.repeat}) : null;
+    const repeat = this.props.repeat && this.props.repeat > 1
+      ? createElement(MessageRepeat, {repeat: this.props.repeat})
+      : null;
 
     let onFrameClick;
     if (serviceContainer && frame) {
       if (source === MESSAGE_SOURCE.CSS) {
         onFrameClick = serviceContainer.onViewSourceInStyleEditor
           || serviceContainer.onViewSource;
       } else if (/^Scratchpad\/\d+$/.test(frame.source)) {
         onFrameClick = serviceContainer.onViewSourceInScratchpad
--- a/devtools/client/webconsole/components/MessageContainer.js
+++ b/devtools/client/webconsole/components/MessageContainer.js
@@ -3,17 +3,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";
 
 // React & Redux
 const { Component } = require("devtools/client/shared/vendor/react");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
 
 const {
   MESSAGE_SOURCE,
   MESSAGE_TYPE,
 } = require("devtools/client/webconsole/constants");
 
 const componentMap = new Map([
   ["ConsoleApiCall", require("./message-types/ConsoleApiCall")],
--- a/devtools/client/webconsole/components/ReverseSearchInput.js
+++ b/devtools/client/webconsole/components/ReverseSearchInput.js
@@ -3,29 +3,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // React & Redux
 const { Component } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
-const { l10n } = require("devtools/client/webconsole/utils/messages");
-const { PluralForm } = require("devtools/shared/plural-form");
-const { KeyCodes } = require("devtools/client/shared/keycodes");
-
-const actions = require("devtools/client/webconsole/actions/index");
 const {
   getReverseSearchTotalResults,
   getReverseSearchResultPosition,
   getReverseSearchResult,
 } = require("devtools/client/webconsole/selectors/history");
 
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "actions", "devtools/client/webconsole/actions/index");
+loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/utils/messages", true);
+loader.lazyRequireGetter(this, "PluralForm", "devtools/shared/plural-form", true);
+loader.lazyRequireGetter(this, "KeyCodes", "devtools/client/shared/keycodes", true);
+
 const Services = require("Services");
 const isMacOS = Services.appinfo.OS === "Darwin";
 
 class ReverseSearchInput extends Component {
   static get propTypes() {
     return {
       dispatch: PropTypes.func.isRequired,
       hud: PropTypes.object.isRequired,
--- a/devtools/client/webconsole/components/SideBar.js
+++ b/devtools/client/webconsole/components/SideBar.js
@@ -1,24 +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 { Component, createFactory } = require("devtools/client/shared/vendor/react");
-const dom = require("devtools/client/shared/vendor/react-dom-factories");
-const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { Component, createElement } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
-const { getObjectInspector } = require("devtools/client/webconsole/utils/object-inspector");
-const actions = require("devtools/client/webconsole/actions/index");
-const SplitBox = createFactory(require("devtools/client/shared/components/splitter/SplitBox"));
-const { l10n } = require("devtools/client/webconsole/utils/messages");
 
-const reps = require("devtools/client/shared/components/reps/reps");
-const { MODE } = reps;
+loader.lazyRequireGetter(this, "dom", "devtools/client/shared/vendor/react-dom-factories");
+loader.lazyRequireGetter(this, "getObjectInspector", "devtools/client/webconsole/utils/object-inspector", true);
+loader.lazyRequireGetter(this, "actions", "devtools/client/webconsole/actions/index");
+loader.lazyRequireGetter(this, "PropTypes", "devtools/client/shared/vendor/react-prop-types");
+loader.lazyRequireGetter(this, "SplitBox", "devtools/client/shared/components/splitter/SplitBox");
+loader.lazyRequireGetter(this, "reps", "devtools/client/shared/components/reps/reps");
+loader.lazyRequireGetter(this, "l10n", "devtools/client/webconsole/utils/messages", true);
 
 class SideBar extends Component {
   static get propTypes() {
     return {
       serviceContainer: PropTypes.object,
       dispatch: PropTypes.func.isRequired,
       sidebarVisible: PropTypes.bool,
       grip: PropTypes.object,
@@ -51,17 +50,17 @@ class SideBar extends Component {
 
     const {
       grip,
       serviceContainer,
     } = this.props;
 
     const objectInspector = getObjectInspector(grip, serviceContainer, {
       autoExpandDepth: 1,
-      mode: MODE.SHORT,
+      mode: reps.MODE.SHORT,
       autoFocusRoot: true,
     });
 
     const endPanel = dom.aside({
       className: "sidebar-wrapper",
     },
       dom.header({
         className: "devtools-toolbar webconsole-sidebar-toolbar",
@@ -72,17 +71,17 @@ class SideBar extends Component {
           onClick: this.onClickSidebarClose,
         })
       ),
       dom.aside({
         className: "sidebar-contents",
       }, objectInspector)
     );
 
-    return SplitBox({
+    return createElement(SplitBox, {
       className: "sidebar",
       endPanel,
       endPanelControl: true,
       initialSize: "200px",
       minSize: "100px",
       vert: true,
     });
   }
--- a/devtools/client/webconsole/reducers/messages.js
+++ b/devtools/client/webconsole/reducers/messages.js
@@ -12,19 +12,20 @@ const {
 
 const constants = require("devtools/client/webconsole/constants");
 const {
   DEFAULT_FILTERS,
   FILTERS,
   MESSAGE_TYPE,
   MESSAGE_SOURCE,
 } = constants;
-const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
-const { getUnicodeUrlPath } = require("devtools/client/shared/unicode-url");
-const { getSourceNames } = require("devtools/client/shared/source-utils");
+
+loader.lazyRequireGetter(this, "getGripPreviewItems", "devtools/client/shared/components/reps/reps", true);
+loader.lazyRequireGetter(this, "getUnicodeUrlPath", "devtools/client/shared/unicode-url", true);
+loader.lazyRequireGetter(this, "getSourceNames", "devtools/client/shared/source-utils", true);
 
 const {
   UPDATE_REQUEST,
 } = require("devtools/client/netmonitor/src/constants");
 
 const {
   processNetworkUpdates,
 } = require("devtools/client/netmonitor/src/utils/request-utils");
--- a/devtools/client/webconsole/reducers/notifications.js
+++ b/devtools/client/webconsole/reducers/notifications.js
@@ -5,20 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {
   APPEND_NOTIFICATION,
   REMOVE_NOTIFICATION,
 } = require("devtools/client/webconsole/constants");
 
-const {
-  appendNotification,
-  removeNotificationWithValue,
-} = require("devtools/client/shared/components/NotificationBox");
+loader.lazyRequireGetter(this, "appendNotification", "devtools/client/shared/components/NotificationBox", true);
+loader.lazyRequireGetter(this, "removeNotificationWithValue", "devtools/client/shared/components/NotificationBox", true);
 
 /**
  * Create default initial state for this reducer. The state is composed
  * from list of notifications.
  */
 function getInitialState() {
   return {
     notifications: undefined,
--- a/devtools/client/webconsole/utils/object-inspector.js
+++ b/devtools/client/webconsole/utils/object-inspector.js
@@ -1,21 +1,21 @@
 /* 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 { createFactory } = require("devtools/client/shared/vendor/react");
+const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 
 const reps = require("devtools/client/shared/components/reps/reps");
 const { REPS, MODE, objectInspector } = reps;
 const ObjectInspector = createFactory(objectInspector.ObjectInspector);
 const { Grip } = REPS;
-const SmartTrace = createFactory(require("devtools/client/shared/components/SmartTrace"));
+loader.lazyRequireGetter(this, "SmartTrace", "devtools/client/shared/components/SmartTrace");
 
 /**
  * Create and return an ObjectInspector for the given grip.
  *
  * @param {Object} grip
  *        The object grip to create an ObjectInspector for.
  * @param {Object} serviceContainer
  *        Object containing various utility functions
@@ -48,17 +48,17 @@ function getObjectInspector(grip, servic
 
   const objectInspectorProps = {
     autoExpandDepth: 0,
     mode: MODE.LONG,
     roots,
     onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger,
     recordTelemetryEvent: serviceContainer.recordTelemetryEvent,
     openLink: serviceContainer.openLink,
-    renderStacktrace: stacktrace => SmartTrace({
+    renderStacktrace: stacktrace => createElement(SmartTrace, {
       stacktrace,
       onViewSourceInDebugger: serviceContainer
         ? serviceContainer.onViewSourceInDebugger || serviceContainer.onViewSource
         : null,
       onViewSourceInScratchpad: serviceContainer
         ? serviceContainer.onViewSourceInScratchpad || serviceContainer.onViewSource
         : null,
       onViewSource: serviceContainer.onViewSource,