Bug 1590093 - Lazy load console components. r=Honza a=pascalc
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Tue, 29 Oct 2019 10:46:51 +0000
changeset 559873 42799e05eaeb8fd9f5694e420bc1d0dbd03901f7
parent 559872 50b8dafa68e26fd8a0ea9e592b74bfb7b8cf243a
child 559874 fea34d94ec4fa5e757d114b546010d285375e7a5
push id12250
push userdvarga@mozilla.com
push dateMon, 04 Nov 2019 11:28:25 +0000
treeherdermozilla-beta@5537d9a9bad3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza, pascalc
bugs1590093
milestone71.0
Bug 1590093 - Lazy load console components. r=Honza a=pascalc We try to lazy load all the things we know we might not need directly when opening the console. Differential Revision: https://phabricator.services.mozilla.com/D50800
devtools/client/shared/components/menu/MenuButton.js
devtools/client/webconsole/components/App.js
devtools/client/webconsole/components/FilterBar/ConsoleSettings.js
devtools/client/webconsole/components/SideBar.js
--- a/devtools/client/shared/components/menu/MenuButton.js
+++ b/devtools/client/shared/components/menu/MenuButton.js
@@ -11,25 +11,35 @@ const Services = require("Services");
 const flags = require("devtools/shared/flags");
 const {
   createRef,
   PureComponent,
 } = 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 { button } = dom;
-const {
-  HTMLTooltip,
-} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
-const { focusableSelector } = require("devtools/client/shared/focus");
 
 const isMacOS = Services.appinfo.OS === "Darwin";
 
 loader.lazyRequireGetter(
   this,
+  "HTMLTooltip",
+  "devtools/client/shared/widgets/tooltip/HTMLTooltip",
+  true
+);
+
+loader.lazyRequireGetter(
+  this,
+  "focusableSelector",
+  "devtools/client/shared/focus",
+  true
+);
+
+loader.lazyRequireGetter(
+  this,
   "createPortal",
   "devtools/client/shared/vendor/react-dom",
   true
 );
 
 // Return a copy of |obj| minus |fields|.
 const omit = (obj, fields) => {
   const objCopy = { ...obj };
--- a/devtools/client/webconsole/components/App.js
+++ b/devtools/client/webconsole/components/App.js
@@ -17,56 +17,76 @@ const dom = require("devtools/client/sha
 const {
   connect,
 } = require("devtools/client/shared/redux/visibility-handler-connect");
 
 const actions = require("devtools/client/webconsole/actions/index");
 const {
   FILTERBAR_DISPLAY_MODES,
 } = require("devtools/client/webconsole/constants");
+
+// We directly require Components that we know are going to be used right away
 const ConsoleOutput = createFactory(
   require("devtools/client/webconsole/components/Output/ConsoleOutput")
 );
 const FilterBar = createFactory(
   require("devtools/client/webconsole/components/FilterBar/FilterBar")
 );
-const SideBar = createFactory(
-  require("devtools/client/webconsole/components/SideBar")
-);
 const ReverseSearchInput = createFactory(
   require("devtools/client/webconsole/components/Input/ReverseSearchInput")
 );
-const EditorToolbar = createFactory(
-  require("devtools/client/webconsole/components/Input/EditorToolbar")
-);
 const JSTerm = createFactory(
   require("devtools/client/webconsole/components/Input/JSTerm")
 );
 const ConfirmDialog = createFactory(
   require("devtools/client/webconsole/components/Input/ConfirmDialog")
 );
-const NotificationBox = createFactory(
-  require("devtools/client/shared/components/NotificationBox").NotificationBox
+
+// And lazy load the ones that may not be used.
+loader.lazyGetter(this, "SideBar", () =>
+  createFactory(require("devtools/client/webconsole/components/SideBar"))
+);
+
+loader.lazyGetter(this, "EditorToolbar", () =>
+  createFactory(
+    require("devtools/client/webconsole/components/Input/EditorToolbar")
+  )
+);
+
+loader.lazyGetter(this, "NotificationBox", () =>
+  createFactory(
+    require("devtools/client/shared/components/NotificationBox").NotificationBox
+  )
 );
-const GridElementWidthResizer = createFactory(
-  require("devtools/client/shared/components/splitter/GridElementWidthResizer")
+loader.lazyRequireGetter(
+  this,
+  "getNotificationWithValue",
+  "devtools/client/shared/components/NotificationBox",
+  true
+);
+loader.lazyRequireGetter(
+  this,
+  "PriorityLevels",
+  "devtools/client/shared/components/NotificationBox",
+  true
+);
+
+loader.lazyGetter(this, "GridElementWidthResizer", () =>
+  createFactory(
+    require("devtools/client/shared/components/splitter/GridElementWidthResizer")
+  )
 );
 
 const l10n = require("devtools/client/webconsole/utils/l10n");
 const { Utils: WebConsoleUtils } = require("devtools/client/webconsole/utils");
 
 const SELF_XSS_OK = l10n.getStr("selfxss.okstring");
 const SELF_XSS_MSG = l10n.getFormatStr("selfxss.msg", [SELF_XSS_OK]);
 
 const {
-  getNotificationWithValue,
-  PriorityLevels,
-} = require("devtools/client/shared/components/NotificationBox");
-
-const {
   getAllNotifications,
 } = require("devtools/client/webconsole/selectors/notifications");
 const { div } = dom;
 const isMacOS = Services.appinfo.OS === "Darwin";
 
 /**
  * Console root Application component.
  */
@@ -320,34 +340,38 @@ class App extends Component {
       setInputValue: serviceContainer.setInputValue,
       focusInput: serviceContainer.focusInput,
       initialValue: reverseSearchInitialValue,
     });
   }
 
   renderSideBar() {
     const { serviceContainer, sidebarVisible } = this.props;
-    return SideBar({
-      key: "sidebar",
-      serviceContainer,
-      visible: sidebarVisible,
-    });
+    return sidebarVisible
+      ? SideBar({
+          key: "sidebar",
+          serviceContainer,
+          visible: sidebarVisible,
+        })
+      : null;
   }
 
   renderNotificationBox() {
     const { notifications, editorMode } = this.props;
 
-    return NotificationBox({
-      id: "webconsole-notificationbox",
-      key: "notification-box",
-      displayBorderTop: !editorMode,
-      displayBorderBottom: editorMode,
-      wrapping: true,
-      notifications,
-    });
+    return notifications && notifications.size > 0
+      ? NotificationBox({
+          id: "webconsole-notificationbox",
+          key: "notification-box",
+          displayBorderTop: !editorMode,
+          displayBorderBottom: editorMode,
+          wrapping: true,
+          notifications,
+        })
+      : null;
   }
 
   renderConfirmDialog() {
     const { webConsoleUI, serviceContainer } = this.props;
 
     return ConfirmDialog({
       webConsoleUI,
       serviceContainer,
@@ -395,24 +419,26 @@ class App extends Component {
       filterBar,
       editorToolbar,
       dom.div(
         { className: "flexible-output-input", key: "in-out-container" },
         consoleOutput,
         notificationBox,
         jsterm
       ),
-      GridElementWidthResizer({
-        key: "editor-resizer",
-        enabled: editorMode,
-        position: "end",
-        className: "editor-resizer",
-        getControlledElementNode: () => webConsoleUI.jsterm.node,
-        onResizeEnd: width => dispatch(actions.setEditorWidth(width)),
-      }),
+      editorMode
+        ? GridElementWidthResizer({
+            key: "editor-resizer",
+            enabled: editorMode,
+            position: "end",
+            className: "editor-resizer",
+            getControlledElementNode: () => webConsoleUI.jsterm.node,
+            onResizeEnd: width => dispatch(actions.setEditorWidth(width)),
+          })
+        : null,
       reverseSearch,
       sidebar,
       confirmDialog,
     ]);
   }
 }
 
 const mapStateToProps = state => ({
--- a/devtools/client/webconsole/components/FilterBar/ConsoleSettings.js
+++ b/devtools/client/webconsole/components/FilterBar/ConsoleSettings.js
@@ -11,22 +11,28 @@ const PropTypes = require("devtools/clie
 
 const actions = require("devtools/client/webconsole/actions/index");
 const { l10n } = require("devtools/client/webconsole/utils/messages");
 
 // Additional Components
 const MenuButton = createFactory(
   require("devtools/client/shared/components/menu/MenuButton")
 );
-const MenuItem = createFactory(
-  require("devtools/client/shared/components/menu/MenuItem")
-);
-const MenuList = createFactory(
-  require("devtools/client/shared/components/menu/MenuList")
-);
+
+loader.lazyGetter(this, "MenuItem", function() {
+  return createFactory(
+    require("devtools/client/shared/components/menu/MenuItem")
+  );
+});
+
+loader.lazyGetter(this, "MenuList", function() {
+  return createFactory(
+    require("devtools/client/shared/components/menu/MenuList")
+  );
+});
 
 class ConsoleSettings extends Component {
   static get propTypes() {
     return {
       compactToolbar: PropTypes.bool.isRequired,
       dispatch: PropTypes.func.isRequired,
       groupWarnings: PropTypes.bool.isRequired,
       hideCompactToolbarCheckbox: PropTypes.bool.isRequired,
@@ -131,14 +137,16 @@ class ConsoleSettings extends Component 
 
     return MenuButton(
       {
         menuId: "webconsole-console-settings-menu-button",
         doc: toolbox ? toolbox.doc : doc,
         className: "devtools-button webconsole-console-settings-menu-button",
         title: l10n.getStr("webconsole.console.settings.menu.button.tooltip"),
       },
-      this.renderMenuItems()
+      // We pass the children in a function so we don't require the MenuItem and MenuList
+      // components until we need to display them (i.e. when the button is clicked).
+      () => this.renderMenuItems()
     );
   }
 }
 
 module.exports = ConsoleSettings;
--- a/devtools/client/webconsole/components/SideBar.js
+++ b/devtools/client/webconsole/components/SideBar.js
@@ -45,42 +45,36 @@ loader.lazyRequireGetter(
   true
 );
 
 class SideBar extends Component {
   static get propTypes() {
     return {
       serviceContainer: PropTypes.object,
       dispatch: PropTypes.func.isRequired,
-      visible: PropTypes.bool,
       grip: PropTypes.object,
       onResized: PropTypes.func,
     };
   }
 
   constructor(props) {
     super(props);
     this.onClickSidebarClose = this.onClickSidebarClose.bind(this);
   }
 
   shouldComponentUpdate(nextProps) {
-    const { grip, visible } = nextProps;
-
-    return visible !== this.props.visible || grip !== this.props.grip;
+    const { grip } = nextProps;
+    return grip !== this.props.grip;
   }
 
   onClickSidebarClose() {
     this.props.dispatch(actions.sidebarClose());
   }
 
   render() {
-    if (!this.props.visible) {
-      return null;
-    }
-
     const { grip, serviceContainer } = this.props;
 
     const objectInspector = getObjectInspector(grip, serviceContainer, {
       autoExpandDepth: 1,
       mode: reps.MODE.SHORT,
       autoFocusRoot: true,
     });