Bug 1396784 - Lazy load Layout view when opening the inspector. r=gl draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 13 Sep 2017 10:56:18 +0200
changeset 663741 9755173f112123b1e8f0b55f3a737c5daf5299a0
parent 662089 a5f163da8a9be5d2e86138c57d59be69723b5457
child 663742 740b7212641e8163c53d3b09aa54bd4fa9697e27
child 664372 eab625a06c129cde289930e3a642084f838a739b
push id79517
push userbmo:poirot.alex@gmail.com
push dateWed, 13 Sep 2017 10:08:54 +0000
reviewersgl
bugs1396784
milestone57.0a1
Bug 1396784 - Lazy load Layout view when opening the inspector. r=gl MozReview-Commit-ID: I5PiZbfy2J2
devtools/client/inspector/inspector.js
devtools/client/inspector/layout/layout.js
devtools/client/inspector/test/shared-head.js
devtools/client/shared/components/tabs/tabs.js
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -626,18 +626,38 @@ Inspector.prototype = {
       "computedview",
       INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
       defaultTab == "computedview");
 
     // Grid and layout panels aren't lazy-loaded as their module end up
     // calling inspector.addSidebarTab
     this.gridInspector = new GridInspector(this, this.panelWin);
 
-    const LayoutView = this.browserRequire("devtools/client/inspector/layout/layout");
-    this.layoutview = new LayoutView(this, this.panelWin);
+    // Inject a lazy loaded react tab by exposing a fake React object
+    // with a lazy defined Tab thanks to `panel` being a function
+    let layoutId = "layoutview";
+    let layoutTitle = INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2");
+    this.sidebar.addTab(
+      layoutId,
+      layoutTitle,
+      {
+        props: {
+          id: layoutId,
+          title: layoutTitle
+        },
+        panel: () => {
+          if (!this.layoutview) {
+            const LayoutView =
+              this.browserRequire("devtools/client/inspector/layout/layout");
+            this.layoutview = new LayoutView(this, this.panelWin);
+          }
+          return this.layoutview.provider;
+        }
+      },
+      defaultTab == layoutId);
 
     if (this.target.form.animationsActor) {
       this.sidebar.addFrameTab(
         "animationinspector",
         INSPECTOR_L10N.getStr("inspector.sidebar.animationInspectorTitle"),
         "chrome://devtools/content/animationinspector/animation-inspector.xhtml",
         defaultTab == "animationinspector");
     }
--- a/devtools/client/inspector/layout/layout.js
+++ b/devtools/client/inspector/layout/layout.js
@@ -96,24 +96,18 @@ LayoutView.prototype = {
       store: this.store,
       title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
       // @remove after release 56 (See Bug 1355747)
       badge: Services.prefs.getIntPref(PROMOTE_COUNT_PREF) > 0 ?
         INSPECTOR_L10N.getStr("inspector.sidebar.newBadge") : null,
       showBadge: () => Services.prefs.getIntPref(PROMOTE_COUNT_PREF) > 0,
     }, app);
 
-    let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
-
-    this.inspector.addSidebarTab(
-      "layoutview",
-      INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
-      provider,
-      defaultTab == "layoutview"
-    );
+    // Expose the provider to let inspector.js use it in setupSidebar.
+    this.provider = provider;
   },
 
   /**
    * Destruction function called when the inspector is destroyed. Cleans up references.
    */
   destroy() {
     this.document = null;
     this.inspector = null;
--- a/devtools/client/inspector/test/shared-head.js
+++ b/devtools/client/inspector/test/shared-head.js
@@ -48,24 +48,26 @@ var openInspector = Task.async(function*
  * @return a promise that resolves when the inspector is ready and the tab is
  * visible and ready
  */
 var openInspectorSidebarTab = Task.async(function* (id) {
   let {toolbox, inspector, testActor} = yield openInspector();
 
   info("Selecting the " + id + " sidebar");
 
+  let onSidebarSelect = inspector.sidebar.once("select");
   if (id === "computedview" || id === "layoutview") {
     // The layout and computed views should wait until the box-model widget is ready.
     let onBoxModelViewReady = inspector.once("boxmodel-view-updated");
     inspector.sidebar.select(id);
     yield onBoxModelViewReady;
   } else {
     inspector.sidebar.select(id);
   }
+  yield onSidebarSelect;
 
   return {
     toolbox,
     inspector,
     testActor
   };
 });
 
--- a/devtools/client/shared/components/tabs/tabs.js
+++ b/devtools/client/shared/components/tabs/tabs.js
@@ -329,26 +329,33 @@ define(function (require, exports, modul
           // content of non-selected tab. It's faster (not sure why)
           // than display:none and visibility:collapse.
           let style = {
             visibility: selected ? "visible" : "hidden",
             height: selected ? "100%" : "0",
             width: selected ? "100%" : "0",
           };
 
+          // Allows lazy loading panels by creating them only if they are selected,
+          // then store a copy of the lazy created panel in `tab.panel`.
+          if (typeof tab.panel == "function" && selected) {
+            tab.panel = tab.panel(tab);
+          }
+          let panel = tab.panel || tab;
+
           return (
             DOM.div({
               id: id ? id + "-panel" : "panel-" + index,
               key: index,
               style: style,
               className: selected ? "tab-panel-box" : "tab-panel-box hidden",
               role: "tabpanel",
               "aria-labelledby": id ? id + "-tab" : "tab-" + index,
             },
-              (selected || this.state.created[index]) ? tab : null
+              (selected || this.state.created[index]) ? panel : null
             )
           );
         });
 
       return (
         DOM.div({className: "panels"},
           panels
         )