Bug 1405693 - Use dev build of React for Activity Stream if browser.newtabpage.activity-stream.debug is true
MozReview-Commit-ID: 13aqAEVUMNs
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1265,16 +1265,19 @@ pref("browser.newtabpage.columns", 5);
// directory tiles download URL
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
// activates Activity Stream
pref("browser.newtabpage.activity-stream.enabled", true);
pref("browser.newtabpage.activity-stream.prerender", true);
pref("browser.newtabpage.activity-stream.aboutHome.enabled", true);
+#ifndef RELEASE_OR_BETA
+pref("browser.newtabpage.activity-stream.debug", false);
+#endif
pref("browser.library.activity-stream.enabled", true);
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);
// Startup Crash Tracking
// number of startup crashes that can occur before starting into safe mode automatically
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/aboutNewTabService.js
@@ -5,38 +5,55 @@
*/
"use strict";
const {utils: Cu, interfaces: Ci} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
+
XPCOMUtils.defineLazyModuleGetter(this, "AboutNewTab",
"resource:///modules/AboutNewTab.jsm");
const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
-const ACTIVITY_STREAM_URL = "resource://activity-stream/data/content/activity-stream.html";
-
-const ACTIVITY_STREAM_PRERENDER_URL = "resource://activity-stream/data/content/activity-stream-prerendered.html";
+// Debug versions are only available in Nightly
+const ACTIVITY_STREAM_URLS = {
+ "": "resource://activity-stream/data/content/activity-stream.html",
+ "debug": "resource://activity-stream/data/content/activity-stream-debug.html",
+ "prerender": "resource://activity-stream/data/content/activity-stream-prerendered.html",
+ "prerenderdebug": "resource://activity-stream/data/content/activity-stream-prerendered-debug.html",
+};
const ABOUT_URL = "about:newtab";
const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
+const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
+
// Pref that tells if activity stream is enabled
const PREF_ACTIVITY_STREAM_ENABLED = "browser.newtabpage.activity-stream.enabled";
const PREF_ACTIVITY_STREAM_PRERENDER_ENABLED = "browser.newtabpage.activity-stream.prerender";
+const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
+
function AboutNewTabService() {
Services.obs.addObserver(this, "quit-application-granted");
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_ENABLED, this);
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
+ if (!IS_RELEASE_OR_BETA) {
+ Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
+ }
+
+ // More initialization happens here
this.toggleActivityStream();
+ this.initialized = true;
+
if (IS_MAIN_PROCESS) {
AboutNewTab.init();
}
}
/*
* A service that allows for the overriding, at runtime, of the newtab page's url.
* Additionally, the service manages pref state between a activity stream, or the regular
@@ -71,16 +88,17 @@ function AboutNewTabService() {
* LOAD_NORMAL or LOAD_REPLACE flags yield unexpected behaviors, so a roundtrip
* to the redirector from browser chrome is avoided.
*/
AboutNewTabService.prototype = {
_newTabURL: ABOUT_URL,
_activityStreamEnabled: false,
_activityStreamPrerender: false,
+ _activityStreamDebug: false,
_overridden: false,
classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIAboutNewTabService,
Ci.nsIObserver
]),
_xpcom_categories: [{
@@ -92,22 +110,23 @@ AboutNewTabService.prototype = {
case "nsPref:changed":
if (data === PREF_ACTIVITY_STREAM_ENABLED) {
if (this.toggleActivityStream()) {
Services.obs.notifyObservers(null, "newtab-url-changed", ABOUT_URL);
}
} else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
Services.obs.notifyObservers(null, "newtab-url-changed", ABOUT_URL);
+ } else if (!IS_RELEASE_OR_BETA && data === PREF_ACTIVITY_STREAM_DEBUG) {
+ this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
+ Services.obs.notifyObservers(null, "newtab-url-changed", ABOUT_URL);
}
break;
case "quit-application-granted":
- Services.obs.removeObserver(this, "quit-application-granted");
- Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_ENABLED, this);
- Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
+ this.uninit();
if (IS_MAIN_PROCESS) {
AboutNewTab.uninit();
}
break;
}
},
/**
@@ -132,31 +151,36 @@ AboutNewTabService.prototype = {
return false;
}
if (stateEnabled) {
this._activityStreamEnabled = true;
} else {
this._activityStreamEnabled = false;
}
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
+ if (!IS_RELEASE_OR_BETA) {
+ this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
+ }
this._newtabURL = ABOUT_URL;
return true;
},
/*
* Returns the default URL.
*
* This URL only depends on the browser.newtabpage.activity-stream.enabled pref. Overriding
* the newtab page has no effect on the result of this function.
*
* @returns {String} the default newtab URL, activity-stream or regular depending on browser.newtabpage.activity-stream.enabled
*/
get defaultURL() {
if (this.activityStreamEnabled) {
- return this.activityStreamPrerender ? this.activityStreamPrerenderURL : this.activityStreamURL;
+ const prerender = this.activityStreamPrerender ? "prerender" : "";
+ const debug = this.activityStreamDebug ? "debug" : "";
+ return ACTIVITY_STREAM_URLS[prerender + debug];
}
return LOCAL_NEWTAB_URL;
},
get newTabURL() {
return this._newTabURL;
},
@@ -183,25 +207,34 @@ AboutNewTabService.prototype = {
get activityStreamEnabled() {
return this._activityStreamEnabled;
},
get activityStreamPrerender() {
return this._activityStreamPrerender;
},
- get activityStreamURL() {
- return ACTIVITY_STREAM_URL;
- },
-
- get activityStreamPrerenderURL() {
- return ACTIVITY_STREAM_PRERENDER_URL;
+ get activityStreamDebug() {
+ return this._activityStreamDebug;
},
resetNewTabURL() {
this._overridden = false;
this._newTabURL = ABOUT_URL;
this.toggleActivityStream(undefined, true);
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
+ },
+
+ uninit() {
+ if (!this.initialized) {
+ return;
+ }
+ Services.obs.removeObserver(this, "quit-application-granted");
+ Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_ENABLED, this);
+ Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
+ if (!IS_RELEASE_OR_BETA) {
+ Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
+ }
+ this.initialized = false;
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutNewTabService]);
--- a/browser/components/newtab/nsIAboutNewTabService.idl
+++ b/browser/components/newtab/nsIAboutNewTabService.idl
@@ -35,23 +35,18 @@ interface nsIAboutNewTabService : nsISup
readonly attribute bool activityStreamEnabled;
/**
* Returns true if the the prerendering pref for activity stream is true
*/
readonly attribute bool activityStreamPrerender;
/**
- * Returns the activity stream resource URL for the newtab page
+ * Returns true if the the debug pref for activity stream is true
*/
- readonly attribute ACString activityStreamURL;
-
- /**
- * Returns the prerendered activity stream resource URL for the newtab page
- */
- readonly attribute ACString activityStreamPrerenderURL;
+ readonly attribute bool activityStreamDebug;
/**
* Resets to the default resource and also resets the
* overridden attribute to false.
*/
void resetNewTabURL();
};
--- a/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
+++ b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
@@ -7,37 +7,43 @@
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
-const ACTIVITY_STREAM_PRERENDER_URL = aboutNewTabService.activityStreamPrerenderURL;
+const ACTIVITY_STREAM_PRERENDER_URL = "resource://activity-stream/data/content/activity-stream-prerendered.html";
+const ACTIVITY_STREAM_PRERENDER_DEBUG_URL = "resource://activity-stream/data/content/activity-stream-prerendered-debug.html";
+const ACTIVITY_STREAM_URL = "resource://activity-stream/data/content/activity-stream.html";
+const ACTIVITY_STREAM_DEBUG_URL = "resource://activity-stream/data/content/activity-stream-debug.html";
const DEFAULT_CHROME_URL = "chrome://browser/content/newtab/newTab.xhtml";
const DOWNLOADS_URL = "chrome://browser/content/downloads/contentAreaDownloadsView.xul";
const ACTIVITY_STREAM_PREF = "browser.newtabpage.activity-stream.enabled";
const ACTIVITY_STREAM_PRERENDER_PREF = "browser.newtabpage.activity-stream.prerender";
+const ACTIVITY_STREAM_DEBUG_PREF = "browser.newtabpage.activity-stream.debug";
function cleanup() {
Services.prefs.clearUserPref(ACTIVITY_STREAM_PREF);
Services.prefs.clearUserPref(ACTIVITY_STREAM_PRERENDER_PREF);
+ Services.prefs.clearUserPref(ACTIVITY_STREAM_DEBUG_PREF);
aboutNewTabService.resetNewTabURL();
}
do_register_cleanup(cleanup);
add_task(async function test_as_and_prerender_initialized() {
Assert.equal(aboutNewTabService.activityStreamEnabled, Services.prefs.getBoolPref(ACTIVITY_STREAM_PREF),
".activityStreamEnabled should be set to the correct initial value");
Assert.equal(aboutNewTabService.activityStreamPrerender, Services.prefs.getBoolPref(ACTIVITY_STREAM_PRERENDER_PREF),
".activityStreamPrerender should be set to the correct initial value");
- Services.prefs.getBoolPref(ACTIVITY_STREAM_PREF);
+ Assert.equal(aboutNewTabService.activityStreamDebug, Services.prefs.getBoolPref(ACTIVITY_STREAM_DEBUG_PREF),
+ ".activityStreamDebug should be set to the correct initial value");
});
/**
* Test the overriding of the default URL
*/
add_task(async function test_override_activity_stream_disabled() {
let notificationPromise;
Services.prefs.setBoolPref(ACTIVITY_STREAM_PREF, false);
@@ -92,27 +98,35 @@ add_task(async function test_override_ac
Assert.ok(!aboutNewTabService.activityStreamEnabled, "Activity Stream should not be enabled");
cleanup();
});
add_task(async function test_default_url() {
await setupASPrerendered();
Assert.equal(aboutNewTabService.defaultURL, ACTIVITY_STREAM_PRERENDER_URL,
- "Newtab defaultURL initially set to prerendered AS url");
+ "Newtab defaultURL initially set to prerendered AS url");
+
+ await setBoolPrefAndWaitForChange(ACTIVITY_STREAM_DEBUG_PREF, true,
+ "A notification occurs after changing the debug pref to true");
+
+ Assert.equal(aboutNewTabService.defaultURL, ACTIVITY_STREAM_PRERENDER_DEBUG_URL,
+ "Newtab defaultURL set to debug prerendered AS url after the pref has been changed");
- // Change activity-stream.prerendered to false and wait for the required event to fire
- const notificationPromise = nextChangeNotificationPromise(
- "about:newtab", "a notification occurs after changing prerender pref");
- Services.prefs.setBoolPref(ACTIVITY_STREAM_PRERENDER_PREF, false);
+ await setBoolPrefAndWaitForChange(ACTIVITY_STREAM_PRERENDER_PREF, false,
+ "A notification occurs after changing the prerender pref to false");
+
+ Assert.equal(aboutNewTabService.defaultURL, ACTIVITY_STREAM_DEBUG_URL,
+ "Newtab defaultURL set to un-prerendered AS with debug if prerender is false and debug is true");
- await notificationPromise;
+ await setBoolPrefAndWaitForChange(ACTIVITY_STREAM_DEBUG_PREF, false,
+ "A notification occurs after changing the debug pref to false");
- Assert.equal(aboutNewTabService.defaultURL, aboutNewTabService.activityStreamURL,
- "Newtab defaultURL set to un-prerendered AS url after the pref has been changed");
+ Assert.equal(aboutNewTabService.defaultURL, ACTIVITY_STREAM_URL,
+ "Newtab defaultURL set to un-prerendered AS if prerender is false and debug is false");
cleanup();
});
/**
* Tests reponse to updates to prefs
*/
add_task(async function test_updates() {
@@ -154,16 +168,29 @@ function nextChangeNotificationPromise(a
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, testMessage);
resolve();
}, "newtab-url-changed");
});
}
+function setBoolPrefAndWaitForChange(pref, value, testMessage) {
+ return new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
+ Services.obs.removeObserver(observer, aTopic);
+ Assert.equal(aData, aboutNewTabService.newTabURL, testMessage);
+ resolve();
+ }, "newtab-url-changed");
+
+ Services.prefs.setBoolPref(pref, value);
+ });
+}
+
+
function setupASPrerendered() {
if (Services.prefs.getBoolPref(ACTIVITY_STREAM_PREF) &&
Services.prefs.getBoolPref(ACTIVITY_STREAM_PRERENDER_PREF)) {
return Promise.resolve();
}
let notificationPromise;
// change newtab page to activity stream
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/activity-stream-debug.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang="" dir="ltr">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">
+ <title></title>
+ <link rel="icon" type="image/png" id="favicon" href="chrome://branding/content/icon32.png"/>
+ <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
+ <link rel="stylesheet" href="resource://activity-stream/data/content/activity-stream.css" />
+ </head>
+ <body class="activity-stream">
+ <div id="root"></div>
+ <div id="snippets-container">
+ <div id="snippets"></div>
+ </div>
+ <script>
+// Don't directly load the following scripts as part of html to let the page
+// finish loading to render the content sooner.
+for (const src of [
+ "chrome://browser/content/contentSearchUI.js",
+ "resource://activity-stream/vendor/react-dev.js",
+ "resource://activity-stream/vendor/react-dom-dev.js",
+ "resource://activity-stream/vendor/react-intl.js",
+ "resource://activity-stream/vendor/redux.js",
+ "resource://activity-stream/vendor/react-redux.js",
+ "resource://activity-stream/data/content/activity-stream.bundle.js"
+]) {
+ // These dynamically inserted scripts by default are async, but we need them
+ // to load in the desired order (i.e., bundle last).
+ const script = document.body.appendChild(document.createElement("script"));
+ script.async = false;
+ script.src = src;
+}
+ </script>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/activity-stream-prerendered-debug.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html lang="" dir="ltr">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">
+ <title></title>
+ <link rel="icon" type="image/png" id="favicon" href="chrome://branding/content/icon32.png"/>
+ <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
+ <link rel="stylesheet" href="resource://activity-stream/data/content/activity-stream.css" />
+ </head>
+ <body class="activity-stream">
+ <div id="root"><div class="outer-wrapper fixed-to-top" data-reactroot="" data-reactid="1" data-react-checksum="-1695158303"><main data-reactid="2"><div class="search-wrapper" data-reactid="3"><label for="newtab-search-text" class="search-label" data-reactid="4"><span class="sr-only" data-reactid="5"><span data-reactid="6">Search the Web</span></span></label><input type="search" id="newtab-search-text" maxlength="256" placeholder="Search the Web" title="Search the Web" data-reactid="7"/><button id="searchSubmit" class="search-button" title=" " data-reactid="8"><span class="sr-only" data-reactid="9"><span data-reactid="10"> </span></span></button></div><div class="body-wrapper" data-reactid="11"><section class="section top-sites" data-reactid="12"><div class="section-top-bar" data-reactid="13"><h3 class="section-title" data-reactid="14"><span class="icon icon-small-spacer icon-topsites" data-reactid="15"></span><span data-reactid="16"> </span></h3><span class="section-info-option" data-reactid="17"><img class="info-option-icon" title=" " aria-haspopup="true" aria-controls="info-option" aria-expanded="false" role="note" tabindex="0" data-reactid="18"/><div class="info-option" data-reactid="19"><div class="info-option-header" role="heading" data-reactid="20"><span data-reactid="21"> </span></div><p class="info-option-body" data-reactid="22"><span data-reactid="23"> </span></p><div class="info-option-manage" data-reactid="24"><button data-reactid="25"><span data-reactid="26"> </span></button></div></div></span></div><ul class="top-sites-list" data-reactid="27"><li class="top-site-outer placeholder" data-reactid="28"><a data-reactid="29"><div class="tile" aria-hidden="true" data-reactid="30"><span class="letter-fallback" data-reactid="31"></span><div class="screenshot" style="background-image:none;" data-reactid="32"></div></div><div class="title " data-reactid="33"><span dir="auto" data-reactid="34"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="35"><a data-reactid="36"><div class="tile" aria-hidden="true" data-reactid="37"><span class="letter-fallback" data-reactid="38"></span><div class="screenshot" style="background-image:none;" data-reactid="39"></div></div><div class="title " data-reactid="40"><span dir="auto" data-reactid="41"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="42"><a data-reactid="43"><div class="tile" aria-hidden="true" data-reactid="44"><span class="letter-fallback" data-reactid="45"></span><div class="screenshot" style="background-image:none;" data-reactid="46"></div></div><div class="title " data-reactid="47"><span dir="auto" data-reactid="48"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="49"><a data-reactid="50"><div class="tile" aria-hidden="true" data-reactid="51"><span class="letter-fallback" data-reactid="52"></span><div class="screenshot" style="background-image:none;" data-reactid="53"></div></div><div class="title " data-reactid="54"><span dir="auto" data-reactid="55"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="56"><a data-reactid="57"><div class="tile" aria-hidden="true" data-reactid="58"><span class="letter-fallback" data-reactid="59"></span><div class="screenshot" style="background-image:none;" data-reactid="60"></div></div><div class="title " data-reactid="61"><span dir="auto" data-reactid="62"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="63"><a data-reactid="64"><div class="tile" aria-hidden="true" data-reactid="65"><span class="letter-fallback" data-reactid="66"></span><div class="screenshot" style="background-image:none;" data-reactid="67"></div></div><div class="title " data-reactid="68"><span dir="auto" data-reactid="69"></span></div></a></li></ul><div class="edit-topsites-wrapper" data-reactid="70"><div class="edit-topsites-button" data-reactid="71"><button class="edit" title=" " data-reactid="72"><span data-reactid="73"> </span></button></div></div></section><div class="sections-list" data-reactid="74"><section class="section" data-reactid="75"><div class="section-top-bar" data-reactid="76"><h3 class="section-title" data-reactid="77"><span class="icon icon-small-spacer icon-pocket" data-reactid="78"></span><span data-reactid="79"> </span></h3></div><ul class="section-list" style="padding:0;" data-reactid="80"><li class="card-outer placeholder" data-reactid="81"><a data-reactid="82"><div class="card" data-reactid="83"><div class="card-details no-image" data-reactid="84"><div class="card-text no-context no-description no-host-name no-image" data-reactid="85"><h4 class="card-title" dir="auto" data-reactid="86"></h4><p class="card-description" dir="auto" data-reactid="87"></p></div><div class="card-context" data-reactid="88"></div></div></div></a></li><li class="card-outer placeholder" data-reactid="89"><a data-reactid="90"><div class="card" data-reactid="91"><div class="card-details no-image" data-reactid="92"><div class="card-text no-context no-description no-host-name no-image" data-reactid="93"><h4 class="card-title" dir="auto" data-reactid="94"></h4><p class="card-description" dir="auto" data-reactid="95"></p></div><div class="card-context" data-reactid="96"></div></div></div></a></li><li class="card-outer placeholder" data-reactid="97"><a data-reactid="98"><div class="card" data-reactid="99"><div class="card-details no-image" data-reactid="100"><div class="card-text no-context no-description no-host-name no-image" data-reactid="101"><h4 class="card-title" dir="auto" data-reactid="102"></h4><p class="card-description" dir="auto" data-reactid="103"></p></div><div class="card-context" data-reactid="104"></div></div></div></a></li></ul><div class="topic" data-reactid="105"><span data-reactid="106"><span data-reactid="107"> </span></span><ul data-reactid="108"></ul></div></section><section class="section" data-reactid="109"><div class="section-top-bar" data-reactid="110"><h3 class="section-title" data-reactid="111"><span class="icon icon-small-spacer icon-highlights" data-reactid="112"></span><span data-reactid="113"> </span></h3></div><ul class="section-list" style="padding:0;" data-reactid="114"><li class="card-outer placeholder" data-reactid="115"><a data-reactid="116"><div class="card" data-reactid="117"><div class="card-details no-image" data-reactid="118"><div class="card-text no-context no-description no-host-name no-image" data-reactid="119"><h4 class="card-title" dir="auto" data-reactid="120"></h4><p class="card-description" dir="auto" data-reactid="121"></p></div><div class="card-context" data-reactid="122"></div></div></div></a></li><li class="card-outer placeholder" data-reactid="123"><a data-reactid="124"><div class="card" data-reactid="125"><div class="card-details no-image" data-reactid="126"><div class="card-text no-context no-description no-host-name no-image" data-reactid="127"><h4 class="card-title" dir="auto" data-reactid="128"></h4><p class="card-description" dir="auto" data-reactid="129"></p></div><div class="card-context" data-reactid="130"></div></div></div></a></li><li class="card-outer placeholder" data-reactid="131"><a data-reactid="132"><div class="card" data-reactid="133"><div class="card-details no-image" data-reactid="134"><div class="card-text no-context no-description no-host-name no-image" data-reactid="135"><h4 class="card-title" dir="auto" data-reactid="136"></h4><p class="card-description" dir="auto" data-reactid="137"></p></div><div class="card-context" data-reactid="138"></div></div></div></a></li></ul></section></div></div><!-- react-empty: 139 --></main></div></div>
+ <div id="snippets-container">
+ <div id="snippets"></div>
+ </div>
+ <script>
+// Don't directly load the following scripts as part of html to let the page
+// finish loading to render the content sooner.
+for (const src of [
+ "resource://activity-stream/data/content/activity-stream-initial-state.js",
+ "chrome://browser/content/contentSearchUI.js",
+ "resource://activity-stream/vendor/react-dev.js",
+ "resource://activity-stream/vendor/react-dom-dev.js",
+ "resource://activity-stream/vendor/react-intl.js",
+ "resource://activity-stream/vendor/redux.js",
+ "resource://activity-stream/vendor/react-redux.js",
+ "resource://activity-stream/data/content/activity-stream.bundle.js"
+]) {
+ // These dynamically inserted scripts by default are async, but we need them
+ // to load in the desired order (i.e., bundle last).
+ const script = document.body.appendChild(document.createElement("script"));
+ script.async = false;
+ script.src = src;
+}
+ </script>
+ </body>
+</html>
--- a/browser/extensions/activity-stream/jar.mn
+++ b/browser/extensions/activity-stream/jar.mn
@@ -4,12 +4,16 @@
[features/activity-stream@mozilla.org] chrome.jar:
% resource activity-stream %content/ contentaccessible=yes
content/lib/ (./lib/*)
content/common/ (./common/*)
content/vendor/Redux.jsm (./vendor/Redux.jsm)
content/vendor/react.js (./vendor/react.js)
content/vendor/react-dom.js (./vendor/react-dom.js)
+#ifndef RELEASE_OR_BETA
+ content/vendor/react-dev.js (./vendor/react-dev.js)
+ content/vendor/react-dom-dev.js (./vendor/react-dom-dev.js)
+#endif
content/vendor/react-intl.js (./vendor/react-intl.js)
content/vendor/redux.js (./vendor/redux.js)
content/vendor/react-redux.js (./vendor/react-redux.js)
content/data/ (./data/*)