Bug 1352699 - Remove cyclic dependency in devtools loader r?honza draft
authorRicky Chien <ricky060709@gmail.com>
Sun, 09 Apr 2017 16:51:41 +0800
changeset 559415 5a94af33a637e84b3990dad124c7c6cd77303ab0
parent 559414 e7d95e26592e064378812c383aaf57b3864aa06c
child 559416 089344cce53baf80da0639bdba6272c53e7640a0
child 559443 b309b789dddbf91c6e11df4bfaf13b124140a1d7
push id53080
push userbmo:rchien@mozilla.com
push dateMon, 10 Apr 2017 03:51:23 +0000
reviewershonza
bugs1352699
milestone55.0a1
Bug 1352699 - Remove cyclic dependency in devtools loader r?honza MozReview-Commit-ID: 3tzqmyOGM7M
devtools/client/netmonitor/index.html
devtools/client/netmonitor/index.js
devtools/client/netmonitor/src/netmonitor-controller.js
devtools/client/netmonitor/src/utils/create-store.js
--- a/devtools/client/netmonitor/index.html
+++ b/devtools/client/netmonitor/index.html
@@ -19,34 +19,36 @@
         baseURI: "resource://devtools/client/netmonitor/",
         window,
       }).require;
 
       const EventEmitter = require("devtools/shared/event-emitter");
       const { createFactory } = require("devtools/client/shared/vendor/react");
       const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
       const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
+      const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
       const { configureStore } = require("./src/utils/create-store");
       const store = window.gStore = configureStore();
+      const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
       const { NetMonitorController } = require("./src/netmonitor-controller");
 
       // Inject EventEmitter into global window.
       EventEmitter.decorate(window);
 
       window.Netmonitor = {
         bootstrap({ toolbox }) {
           this.mount = document.querySelector("#mount");
           const App = createFactory(require("./src/components/app"));
           render(Provider({ store }, App()), this.mount);
           return NetMonitorController.startupNetMonitor({
             tabConnection: {
               tabTarget: toolbox.target,
             },
             toolbox,
-          });
+          }, actions);
         },
 
         destroy() {
           unmountComponentAtNode(this.mount);
           return NetMonitorController.shutdownNetMonitor();
         }
       };
     </script>
--- a/devtools/client/netmonitor/index.js
+++ b/devtools/client/netmonitor/index.js
@@ -6,16 +6,17 @@
 
 /**
  * This script is the entry point of devtools-launchpad. Make netmonitor possible
  * to run on standalone browser tab without chrome privilege.
  * See README.md for more information.
  */
 const React = require("react");
 const ReactDOM = require("react-dom");
+const { bindActionCreators } = require("redux");
 const { bootstrap, renderRoot } = require("devtools-launchpad");
 const { EventEmitter } = require("devtools-modules");
 const { Services: { appinfo, pref }} = require("devtools-modules");
 const { configureStore } = require("./src/utils/create-store");
 
 require("./src/assets/styles/netmonitor.css");
 
 EventEmitter.decorate(window);
@@ -33,16 +34,17 @@ pref("devtools.netmonitor.har.includeRes
 pref("devtools.netmonitor.har.compress", false);
 pref("devtools.netmonitor.har.forceExport", false);
 pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
 pref("devtools.netmonitor.har.enableAutoExportToFile", false);
 pref("devtools.webconsole.persistlog", false);
 
 const App = require("./src/components/app");
 const store = window.gStore = configureStore();
+const actions = bindActionCreators(require("./src/actions"), store.dispatch);
 const { NetMonitorController } = require("./src/netmonitor-controller");
 
 /**
  * Stylesheet links in devtools xhtml files are using chrome or resource URLs.
  * Rewrite the href attribute to remove the protocol. web-server.js contains redirects
  * to map CSS urls to the proper file. Supports urls using:
  *   - devtools/client/
  *   - devtools/content/
@@ -64,10 +66,10 @@ window.addEventListener("DOMContentLoade
   }
 });
 
 bootstrap(React, ReactDOM).then(connection => {
   if (!connection) {
     return;
   }
   renderRoot(React, ReactDOM, App, store);
-  NetMonitorController.startupNetMonitor(connection);
+  NetMonitorController.startupNetMonitor(connection, actions);
 });
--- a/devtools/client/netmonitor/src/netmonitor-controller.js
+++ b/devtools/client/netmonitor/src/netmonitor-controller.js
@@ -2,46 +2,46 @@
  * 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 { TimelineFront } = require("devtools/shared/fronts/timeline");
 const { CurlUtils } = require("devtools/client/shared/curl");
 const { ACTIVITY_TYPE, EVENTS } = require("./constants");
-const Actions = require("./actions/index");
+const {
+  getRequestById,
+  getDisplayedRequestById,
+} = require("./selectors/index");
 const {
   fetchHeaders,
   formDataURI,
 } = require("./utils/request-utils");
 const {
   getLongString,
   getWebConsoleClient,
   onFirefoxConnect,
   onFirefoxDisconnect,
 } = require("./utils/client");
-const {
-  getRequestById,
-  getDisplayedRequestById,
-} = require("./selectors/index");
 
 /**
  * Object defining the network monitor controller components.
  */
 var NetMonitorController = {
   /**
    * Initializes the view and connects the monitor client.
    *
    * @param {Object} connection connection data wrapper
    * @return {Object} A promise that is resolved when the monitor finishes startup.
    */
-  startupNetMonitor(connection) {
+  startupNetMonitor(connection, actions) {
     if (this._startup) {
       return this._startup;
     }
+    this.actions = actions;
     this._startup = new Promise(async (resolve) => {
       await this.connect(connection);
       resolve();
     });
     return this._startup;
   },
 
   /**
@@ -50,17 +50,17 @@ var NetMonitorController = {
    * @return object
    *         A promise that is resolved when the monitor finishes shutdown.
    */
   shutdownNetMonitor() {
     if (this._shutdown) {
       return this._shutdown;
     }
     this._shutdown = new Promise(async (resolve) => {
-      window.gStore.dispatch(Actions.batchReset());
+      this.actions.batchReset();
       onFirefoxDisconnect(this._target);
       this._target.off("close", this._onTabDetached);
       this.NetworkEventsHandler.disconnect();
       await this.disconnect();
       resolve();
     });
 
     return this._shutdown;
@@ -100,17 +100,17 @@ var NetMonitorController = {
       };
       await connectTimeline();
 
       onFirefoxConnect(this._target);
       this._target.on("close", this._onTabDetached);
 
       this.webConsoleClient = getWebConsoleClient();
       this.NetworkEventsHandler = new NetworkEventsHandler();
-      this.NetworkEventsHandler.connect();
+      this.NetworkEventsHandler.connect(this.actions);
 
       window.emit(EVENTS.CONNECTED);
 
       resolve();
       this._connected = true;
     });
     return this._connection;
   },
@@ -255,25 +255,25 @@ var NetMonitorController = {
     // Look for the request in the existing ones or wait for it to appear, if
     // the network monitor is still loading.
     return new Promise((resolve) => {
       let request = null;
       let inspector = () => {
         request = getDisplayedRequestById(window.gStore.getState(), requestId);
         if (!request) {
           // Reset filters so that the request is visible.
-          window.gStore.dispatch(Actions.toggleRequestFilterType("all"));
+          this.actions.toggleRequestFilterType("all");
           request = getDisplayedRequestById(window.gStore.getState(), requestId);
         }
 
         // If the request was found, select it. Otherwise this function will be
         // called again once new requests arrive.
         if (request) {
           window.off(EVENTS.REQUEST_ADDED, inspector);
-          window.gStore.dispatch(Actions.selectRequest(request.id));
+          this.actions.selectRequest(request.id);
           resolve();
         }
       };
 
       inspector();
       if (!request) {
         window.on(EVENTS.REQUEST_ADDED, inspector);
       }
@@ -397,31 +397,32 @@ NetworkEventsHandler.prototype = {
 
   get timelineFront() {
     return NetMonitorController.timelineFront;
   },
 
   /**
    * Connect to the current target client.
    */
-  connect: function () {
+  connect(actions) {
+    this.actions = actions;
     this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
     this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
 
     if (this.timelineFront) {
       this.timelineFront.on("doc-loading", this._onDocLoadingMarker);
     }
 
     this._displayCachedEvents();
   },
 
   /**
    * Disconnect from the client.
    */
-  disconnect: function () {
+  disconnect() {
     if (!this.client) {
       return;
     }
     this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
     this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
 
     if (this.timelineFront) {
       this.timelineFront.off("doc-loading", this._onDocLoadingMarker);
@@ -448,17 +449,17 @@ NetworkEventsHandler.prototype = {
   },
 
   /**
    * The "DOMContentLoaded" and "Load" events sent by the timeline actor.
    * @param object marker
    */
   _onDocLoadingMarker: function (marker) {
     window.emit(EVENTS.TIMELINE_EVENT, marker);
-    window.gStore.dispatch(Actions.addTimingMarker(marker));
+    this.actions.addTimingMarker(marker);
   },
 
   /**
    * The "networkEvent" message type handler.
    *
    * @param string type
    *        Message type.
    * @param object networkInfo
@@ -479,82 +480,81 @@ NetworkEventsHandler.prototype = {
     );
     window.emit(EVENTS.NETWORK_EVENT, actor);
   },
 
   addRequest(id, data) {
     let { method, url, isXHR, cause, startedDateTime, fromCache,
           fromServiceWorker } = data;
 
-    window.gStore.dispatch(Actions.addRequest(
+    this.actions.addRequest(
       id,
       {
         // Convert the received date/time string to a unix timestamp.
         startedMillis: Date.parse(startedDateTime),
         method,
         url,
         isXHR,
         cause,
         fromCache,
         fromServiceWorker,
       },
       true
-    ))
+    )
     .then(() => window.emit(EVENTS.REQUEST_ADDED, id));
   },
 
   async updateRequest(id, data) {
-    const action = Actions.updateRequest(id, data, true);
-    await window.gStore.dispatch(action);
+    await this.actions.updateRequest(id, data, true);
     let {
       responseContent,
       responseCookies,
       responseHeaders,
       requestCookies,
       requestHeaders,
       requestPostData,
-    } = action.data;
-    let request = getRequestById(window.gStore.getState(), action.id);
+    } = data;
+    let request = getRequestById(window.gStore.getState(), id);
 
     if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
       let headers = await fetchHeaders(requestHeaders, getLongString);
       if (headers) {
-        await window.gStore.dispatch(Actions.updateRequest(
-          action.id,
+        await this.actions.updateRequest(
+          id,
           { requestHeaders: headers },
           true,
-        ));
+        );
       }
     }
 
     if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
       let headers = await fetchHeaders(responseHeaders, getLongString);
       if (headers) {
-        await window.gStore.dispatch(Actions.updateRequest(
-          action.id,
+        await this.actions.updateRequest(
+          id,
           { responseHeaders: headers },
           true,
-        ));
+        );
       }
     }
 
     if (request && responseContent && responseContent.content) {
       let { mimeType } = request;
       let { text, encoding } = responseContent.content;
       let response = await getLongString(text);
       let payload = {};
 
       if (mimeType.includes("image/")) {
         payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
       }
 
       responseContent.content.text = response;
       payload.responseContent = responseContent;
 
-      await window.gStore.dispatch(Actions.updateRequest(action.id, payload, true));
+      await this.actions.updateRequest(id, payload, true);
 
       if (mimeType.includes("image/")) {
         window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
       }
     }
 
     // Search the POST data upload stream for request headers and add
     // them as a separate property, different from the classic headers.
@@ -565,17 +565,17 @@ NetworkEventsHandler.prototype = {
       const headersSize = headers.reduce((acc, { name, value }) => {
         return acc + name.length + value.length + 2;
       }, 0);
       let payload = {};
       requestPostData.postData.text = postData;
       payload.requestPostData = Object.assign({}, requestPostData);
       payload.requestHeadersFromUploadStream = { headers, headersSize };
 
-      await window.gStore.dispatch(Actions.updateRequest(action.id, payload, true));
+      await this.actions.updateRequest(id, payload, true);
     }
 
     // Fetch request and response cookies long value.
     // Actor does not provide full sized cookie value when the value is too long
     // To display values correctly, we need fetch them in each request.
     if (requestCookies) {
       let reqCookies = [];
       // request store cookies in requestCookies or requestCookies.cookies
@@ -584,20 +584,17 @@ NetworkEventsHandler.prototype = {
       // make sure cookies is iterable
       if (typeof cookies[Symbol.iterator] === "function") {
         for (let cookie of cookies) {
           reqCookies.push(Object.assign({}, cookie, {
             value: await getLongString(cookie.value),
           }));
         }
         if (reqCookies.length) {
-          await window.gStore.dispatch(Actions.updateRequest(
-            action.id,
-            { requestCookies: reqCookies },
-            true));
+          await this.actions.updateRequest(id, { requestCookies: reqCookies }, true);
         }
       }
     }
 
     if (responseCookies) {
       let resCookies = [];
       // response store cookies in responseCookies or responseCookies.cookies
       let cookies = responseCookies.cookies ?
@@ -605,20 +602,17 @@ NetworkEventsHandler.prototype = {
       // make sure cookies is iterable
       if (typeof cookies[Symbol.iterator] === "function") {
         for (let cookie of cookies) {
           resCookies.push(Object.assign({}, cookie, {
             value: await getLongString(cookie.value),
           }));
         }
         if (resCookies.length) {
-          await window.gStore.dispatch(Actions.updateRequest(
-            action.id,
-            { responseCookies: resCookies },
-            true));
+          await this.actions.updateRequest(id, { responseCookies: resCookies }, true);
         }
       }
     }
   },
 
   /**
    * The "networkEventUpdate" message type handler.
    *
--- a/devtools/client/netmonitor/src/utils/create-store.js
+++ b/devtools/client/netmonitor/src/utils/create-store.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 { createStore, applyMiddleware } = require("devtools/client/shared/vendor/redux");
+const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
 const batching = require("../middleware/batching");
 const prefs = require("../middleware/prefs");
 const thunk = require("../middleware/thunk");
 const rootReducer = require("../reducers/index");
 const { FilterTypes, Filters } = require("../reducers/filters");
 const { Requests } = require("../reducers/requests");
 const { Sort } = require("../reducers/sort");
 const { TimingMarkers } = require("../reducers/timing-markers");