Bug 1614502 - Expose utility functions for rendering Activity Stream. r=Mardak
authorMike Conley <mconley@mozilla.com>
Fri, 17 Apr 2020 15:31:11 +0000
changeset 524610 7ec776d31a2c6e0ffc1e5ee311d63993317ea7ca
parent 524609 8bf3fe111c408ee42d8bc8f9967ff68ce515c150
child 524611 626dd2a045af6cd510ef04e67d027909509547f1
push id37324
push usershindli@mozilla.com
push dateFri, 17 Apr 2020 21:46:50 +0000
treeherdermozilla-central@853b0e791775 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMardak
bugs1614502
milestone77.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 1614502 - Expose utility functions for rendering Activity Stream. r=Mardak These will be used by a later patch inside of a ChromeWorker using ReactDOMServer. Differential Revision: https://phabricator.services.mozilla.com/D68093
browser/components/newtab/AboutNewTabService.jsm
browser/components/newtab/bin/render-activity-stream-html.js
browser/components/newtab/content-src/activity-stream.jsx
browser/components/newtab/content-src/lib/init-store.js
browser/components/newtab/data/content/activity-stream.bundle.js
browser/components/newtab/data/content/newtab-render.js
browser/components/newtab/jar.mn
browser/components/newtab/prerendered/activity-stream-debug.html
browser/components/newtab/prerendered/activity-stream.html
browser/components/newtab/webpack.system-addon.config.js
--- a/browser/components/newtab/AboutNewTabService.jsm
+++ b/browser/components/newtab/AboutNewTabService.jsm
@@ -354,16 +354,17 @@ class AboutNewTabChildService extends Ba
             "chrome://browser/content/contentTheme.js",
             `${BASE_URL}vendor/react${debugString}.js`,
             `${BASE_URL}vendor/react-dom${debugString}.js`,
             `${BASE_URL}vendor/prop-types.js`,
             `${BASE_URL}vendor/react-transition-group.js`,
             `${BASE_URL}vendor/redux.js`,
             `${BASE_URL}vendor/react-redux.js`,
             `${BASE_URL}data/content/activity-stream.bundle.js`,
+            `${BASE_URL}data/content/newtab-render.js`,
           ];
 
           for (let script of scripts) {
             Services.scriptloader.loadSubScript(script, win); // Synchronous call
           }
         };
         win.addEventListener("DOMContentLoaded", onLoaded, { once: true });
         break;
--- a/browser/components/newtab/bin/render-activity-stream-html.js
+++ b/browser/components/newtab/bin/render-activity-stream-html.js
@@ -33,16 +33,17 @@ function templateHTML(options) {
     "chrome://browser/content/contentTheme.js",
     `${options.baseUrl}vendor/react${debugString}.js`,
     `${options.baseUrl}vendor/react-dom${debugString}.js`,
     `${options.baseUrl}vendor/prop-types.js`,
     `${options.baseUrl}vendor/redux.js`,
     `${options.baseUrl}vendor/react-redux.js`,
     `${options.baseUrl}vendor/react-transition-group.js`,
     `${options.baseUrl}data/content/activity-stream.bundle.js`,
+    `${options.baseUrl}data/content/newtab-render.js`,
   ];
 
   // Add spacing and script tags
   const scriptRender = `\n${scripts
     .map(script => `    <script src="${script}"></script>`)
     .join("\n")}`;
 
   return `
--- a/browser/components/newtab/content-src/activity-stream.jsx
+++ b/browser/components/newtab/content-src/activity-stream.jsx
@@ -6,43 +6,61 @@ import { actionCreators as ac, actionTyp
 import { Base } from "content-src/components/Base/Base";
 import { DetectUserSessionStart } from "content-src/lib/detect-user-session-start";
 import { initStore } from "content-src/lib/init-store";
 import { Provider } from "react-redux";
 import React from "react";
 import ReactDOM from "react-dom";
 import { reducers } from "common/Reducers.jsm";
 
-const store = initStore(reducers);
+export const NewTab = ({ store, isFirstrun }) => (
+  <Provider store={store}>
+    <Base isFirstrun={isFirstrun} />
+  </Provider>
+);
 
-new DetectUserSessionStart(store).sendEventOrAddListener();
+export function renderWithoutState() {
+  const store = initStore(reducers);
+  new DetectUserSessionStart(store).sendEventOrAddListener();
 
-// If this document has already gone into the background by the time we've reached
-// here, we can deprioritize requesting the initial state until the event loop
-// frees up. If, however, the visibility changes, we then send the request.
-let didRequest = false;
-let requestIdleCallbackId = 0;
-function doRequest() {
-  if (!didRequest) {
-    if (requestIdleCallbackId) {
-      cancelIdleCallback(requestIdleCallbackId);
+  // If this document has already gone into the background by the time we've reached
+  // here, we can deprioritize requesting the initial state until the event loop
+  // frees up. If, however, the visibility changes, we then send the request.
+  let didRequest = false;
+  let requestIdleCallbackId = 0;
+  function doRequest() {
+    if (!didRequest) {
+      if (requestIdleCallbackId) {
+        cancelIdleCallback(requestIdleCallbackId);
+      }
+      didRequest = true;
+      store.dispatch(ac.AlsoToMain({ type: at.NEW_TAB_STATE_REQUEST }));
     }
-    didRequest = true;
-    store.dispatch(ac.AlsoToMain({ type: at.NEW_TAB_STATE_REQUEST }));
+  }
+
+  if (document.hidden) {
+    requestIdleCallbackId = requestIdleCallback(doRequest);
+    addEventListener("visibilitychange", doRequest, { once: true });
+  } else {
+    doRequest();
   }
+
+  ReactDOM.hydrate(
+    <NewTab
+      store={store}
+      isFirstrun={global.document.location.href === "about:welcome"}
+    />,
+    document.getElementById("root")
+  );
 }
 
-if (document.hidden) {
-  requestIdleCallbackId = requestIdleCallback(doRequest);
-  addEventListener("visibilitychange", doRequest, { once: true });
-} else {
-  doRequest();
-}
+export function renderCache(initialState) {
+  const store = initStore(reducers, initialState);
+  new DetectUserSessionStart(store).sendEventOrAddListener();
 
-ReactDOM.hydrate(
-  <Provider store={store}>
-    <Base
+  ReactDOM.hydrate(
+    <NewTab
+      store={store}
       isFirstrun={global.document.location.href === "about:welcome"}
-      strings={global.gActivityStreamStrings}
-    />
-  </Provider>,
-  document.getElementById("root")
-);
+    />,
+    document.getElementById("root")
+  );
+}
--- a/browser/components/newtab/content-src/lib/init-store.js
+++ b/browser/components/newtab/content-src/lib/init-store.js
@@ -130,19 +130,20 @@ export const queueEarlyMessageMiddleware
 
 /**
  * initStore - Create a store and listen for incoming actions
  *
  * @param  {object} reducers An object containing Redux reducers
  * @param  {object} intialState (optional) The initial state of the store, if desired
  * @return {object}          A redux store
  */
-export function initStore(reducers) {
+export function initStore(reducers, initialState) {
   const store = createStore(
     mergeStateReducer(combineReducers(reducers)),
+    initialState,
     global.RPMAddMessageListener &&
       applyMiddleware(
         rehydrationMiddleware,
         queueEarlyMessageMiddleware,
         messageMiddleware
       )
   );
 
--- a/browser/components/newtab/data/content/activity-stream.bundle.js
+++ b/browser/components/newtab/data/content/activity-stream.bundle.js
@@ -1,9 +1,10 @@
 /*! THIS FILE IS AUTO-GENERATED: webpack.system-addon.config.js */
+var NewtabRenderUtils =
 /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
 /******/
 /******/ 		// Check if module is in cache
@@ -86,17 +87,20 @@
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NewTab", function() { return NewTab; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderWithoutState", function() { return renderWithoutState; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderCache", function() { return renderCache; });
+/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
 /* harmony import */ var content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(73);
 /* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(23);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__);
 /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(12);
@@ -108,52 +112,68 @@
 
 
 
 
 
 
 
 
-const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__["reducers"]);
-new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__["DetectUserSessionStart"](store).sendEventOrAddListener(); // If this document has already gone into the background by the time we've reached
-// here, we can deprioritize requesting the initial state until the event loop
-// frees up. If, however, the visibility changes, we then send the request.
-
-let didRequest = false;
-let requestIdleCallbackId = 0;
-
-function doRequest() {
-  if (!didRequest) {
-    if (requestIdleCallbackId) {
-      cancelIdleCallback(requestIdleCallbackId);
-    }
-
-    didRequest = true;
-    store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
-      type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
-    }));
-  }
-}
-
-if (document.hidden) {
-  requestIdleCallbackId = requestIdleCallback(doRequest);
-  addEventListener("visibilitychange", doRequest, {
-    once: true
-  });
-} else {
-  doRequest();
-}
-
-react_dom__WEBPACK_IMPORTED_MODULE_6___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(react_redux__WEBPACK_IMPORTED_MODULE_4__["Provider"], {
+const NewTab = ({
+  store,
+  isFirstrun
+}) => react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(react_redux__WEBPACK_IMPORTED_MODULE_4__["Provider"], {
   store: store
 }, react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_1__["Base"], {
-  isFirstrun: global.document.location.href === "about:welcome",
-  strings: global.gActivityStreamStrings
-})), document.getElementById("root"));
+  isFirstrun: isFirstrun
+}));
+function renderWithoutState() {
+  const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__["reducers"]);
+  new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__["DetectUserSessionStart"](store).sendEventOrAddListener(); // If this document has already gone into the background by the time we've reached
+  // here, we can deprioritize requesting the initial state until the event loop
+  // frees up. If, however, the visibility changes, we then send the request.
+
+  let didRequest = false;
+  let requestIdleCallbackId = 0;
+
+  function doRequest() {
+    if (!didRequest) {
+      if (requestIdleCallbackId) {
+        cancelIdleCallback(requestIdleCallbackId);
+      }
+
+      didRequest = true;
+      store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+        type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
+      }));
+    }
+  }
+
+  if (document.hidden) {
+    requestIdleCallbackId = requestIdleCallback(doRequest);
+    addEventListener("visibilitychange", doRequest, {
+      once: true
+    });
+  } else {
+    doRequest();
+  }
+
+  react_dom__WEBPACK_IMPORTED_MODULE_6___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(NewTab, {
+    store: store,
+    isFirstrun: global.document.location.href === "about:welcome"
+  }), document.getElementById("root"));
+}
+function renderCache(initialState) {
+  const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__["reducers"], initialState);
+  new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__["DetectUserSessionStart"](store).sendEventOrAddListener();
+  react_dom__WEBPACK_IMPORTED_MODULE_6___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(NewTab, {
+    store: store,
+    isFirstrun: global.document.location.href === "about:welcome"
+  }), document.getElementById("root"));
+}
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports) {
 
 var g;
 
@@ -2787,18 +2807,18 @@ const queueEarlyMessageMiddleware = ({
 /**
  * initStore - Create a store and listen for incoming actions
  *
  * @param  {object} reducers An object containing Redux reducers
  * @param  {object} intialState (optional) The initial state of the store, if desired
  * @return {object}          A redux store
  */
 
-function initStore(reducers) {
-  const store = Object(redux__WEBPACK_IMPORTED_MODULE_1__["createStore"])(mergeStateReducer(Object(redux__WEBPACK_IMPORTED_MODULE_1__["combineReducers"])(reducers)), global.RPMAddMessageListener && Object(redux__WEBPACK_IMPORTED_MODULE_1__["applyMiddleware"])(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware));
+function initStore(reducers, initialState) {
+  const store = Object(redux__WEBPACK_IMPORTED_MODULE_1__["createStore"])(mergeStateReducer(Object(redux__WEBPACK_IMPORTED_MODULE_1__["combineReducers"])(reducers)), initialState, global.RPMAddMessageListener && Object(redux__WEBPACK_IMPORTED_MODULE_1__["applyMiddleware"])(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware));
 
   if (global.RPMAddMessageListener) {
     global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, msg => {
       try {
         store.dispatch(msg.data);
       } catch (ex) {
         console.error("Content msg:", msg, "Dispatch error: ", ex); // eslint-disable-line no-console
 
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/data/content/newtab-render.js
@@ -0,0 +1,7 @@
+/* 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";
+
+// exported by activity-stream.bundle.js
+window.NewtabRenderUtils.renderWithoutState();
--- a/browser/components/newtab/jar.mn
+++ b/browser/components/newtab/jar.mn
@@ -18,16 +18,17 @@ browser.jar:
 #endif
   res/activity-stream/vendor/prop-types.js (./vendor/prop-types.js)
   res/activity-stream/vendor/react-transition-group.js (./vendor/react-transition-group.js)
   res/activity-stream/vendor/redux.js (./vendor/redux.js)
   res/activity-stream/vendor/react-redux.js (./vendor/react-redux.js)
   res/activity-stream/data/content/assets/ (./data/content/assets/*)
   res/activity-stream/data/content/tippytop/ (./data/content/tippytop/*)
   res/activity-stream/data/content/activity-stream.bundle.js (./data/content/activity-stream.bundle.js)
+  res/activity-stream/data/content/newtab-render.js (./data/content/newtab-render.js)
 #ifdef XP_MACOSX
   res/activity-stream/css/activity-stream.css (./css/activity-stream-mac.css)
 #elifdef XP_WIN
   res/activity-stream/css/activity-stream.css (./css/activity-stream-windows.css)
 #else
   res/activity-stream/css/activity-stream.css (./css/activity-stream-linux.css)
 #endif
   res/activity-stream/prerendered/activity-stream.html (./prerendered/activity-stream.html)
--- a/browser/components/newtab/prerendered/activity-stream-debug.html
+++ b/browser/components/newtab/prerendered/activity-stream-debug.html
@@ -24,10 +24,11 @@
     <script src="chrome://browser/content/contentTheme.js"></script>
     <script src="resource://activity-stream/vendor/react-dev.js"></script>
     <script src="resource://activity-stream/vendor/react-dom-dev.js"></script>
     <script src="resource://activity-stream/vendor/prop-types.js"></script>
     <script src="resource://activity-stream/vendor/redux.js"></script>
     <script src="resource://activity-stream/vendor/react-redux.js"></script>
     <script src="resource://activity-stream/vendor/react-transition-group.js"></script>
     <script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
+    <script src="resource://activity-stream/data/content/newtab-render.js"></script>
   </body>
 </html>
--- a/browser/components/newtab/prerendered/activity-stream.html
+++ b/browser/components/newtab/prerendered/activity-stream.html
@@ -24,10 +24,11 @@
     <script src="chrome://browser/content/contentTheme.js"></script>
     <script src="resource://activity-stream/vendor/react.js"></script>
     <script src="resource://activity-stream/vendor/react-dom.js"></script>
     <script src="resource://activity-stream/vendor/prop-types.js"></script>
     <script src="resource://activity-stream/vendor/redux.js"></script>
     <script src="resource://activity-stream/vendor/react-redux.js"></script>
     <script src="resource://activity-stream/vendor/react-transition-group.js"></script>
     <script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
+    <script src="resource://activity-stream/data/content/newtab-render.js"></script>
   </body>
 </html>
--- a/browser/components/newtab/webpack.system-addon.config.js
+++ b/browser/components/newtab/webpack.system-addon.config.js
@@ -10,16 +10,17 @@ const absolute = relPath => path.join(__
 const resourcePathRegEx = /^resource:\/\/activity-stream\//;
 
 module.exports = (env = {}) => ({
   mode: "none",
   entry: absolute("content-src/activity-stream.jsx"),
   output: {
     path: absolute("data/content"),
     filename: "activity-stream.bundle.js",
+    library: "NewtabRenderUtils",
   },
   // TODO: switch to eval-source-map for faster builds. Requires CSP changes
   devtool: env.development ? "inline-source-map" : false,
   plugins: [
     new webpack.BannerPlugin(
       `THIS FILE IS AUTO-GENERATED: ${path.basename(__filename)}`
     ),
     new webpack.optimize.ModuleConcatenationPlugin(),