diff --git a/.eslintignore b/.eslintignore index 02e51ca7655a..d0c56441c9d1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -57,7 +57,6 @@ browser/components/pocket/content/panels/js/vendor/** # Ignore newtab files # Kept in sync with browser/components/newtab/.eslintignore -browser/components/newtab/bin/prerender.js browser/components/newtab/data/ browser/components/newtab/logs/ browser/components/newtab/prerendered/ diff --git a/browser/components/newtab/.eslintignore b/browser/components/newtab/.eslintignore index 7c128b30ba53..f7f27c26afe9 100644 --- a/browser/components/newtab/.eslintignore +++ b/browser/components/newtab/.eslintignore @@ -1,5 +1,4 @@ -bin/prerender.js -data/ -logs/ -prerendered/ +data/ +logs/ +prerendered/ vendor/ diff --git a/browser/components/newtab/.mcignore b/browser/components/newtab/.mcignore index 0241ed5b4f6e..0cd29c0b3f2b 100644 --- a/browser/components/newtab/.mcignore +++ b/browser/components/newtab/.mcignore @@ -7,8 +7,6 @@ npm-debug.log .gitignore /.git/ -/bin/prerender.js -/bin/prerender.js.map /data/locales.json /dist/ /logs/ diff --git a/browser/components/newtab/AboutNewTabService.jsm b/browser/components/newtab/AboutNewTabService.jsm index 015954112cc9..5a3638dfd1a3 100644 --- a/browser/components/newtab/AboutNewTabService.jsm +++ b/browser/components/newtab/AboutNewTabService.jsm @@ -31,14 +31,12 @@ const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEG const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA; const PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess"; -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, TOPIC_APP_QUIT); Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE); Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this); - Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this); if (!IS_RELEASE_OR_BETA) { Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this); } @@ -90,7 +88,6 @@ AboutNewTabService.prototype = { _newTabURL: ABOUT_URL, _activityStreamEnabled: false, - _activityStreamPrerender: false, _activityStreamPath: "", _activityStreamDebug: false, _privilegedAboutContentProcess: false, @@ -110,9 +107,6 @@ AboutNewTabService.prototype = { this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS); this.updatePrerenderedPath(); this.notifyChange(); - } else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) { - this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED); - this.notifyChange(); } else if (!IS_RELEASE_OR_BETA && data === PREF_ACTIVITY_STREAM_DEBUG) { this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false); this.updatePrerenderedPath(); @@ -158,10 +152,6 @@ AboutNewTabService.prototype = { `${BASE_URL}data/content/activity-stream.bundle.js`, ]; - if (this._activityStreamPrerender) { - scripts.unshift(`${BASE_URL}prerendered/static/activity-stream-initial-state.js`); - } - for (let script of scripts) { Services.scriptloader.loadSubScript(script, win); // Synchronous call } @@ -217,7 +207,6 @@ AboutNewTabService.prototype = { this._activityStreamEnabled = false; } this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS); - 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); } @@ -245,13 +234,11 @@ AboutNewTabService.prototype = { get defaultURL() { // Generate the desired activity stream resource depending on state, e.g., // resource://activity-stream/prerendered/ar/activity-stream.html - // resource://activity-stream/prerendered/en-US/activity-stream-prerendered.html // resource://activity-stream/prerendered/static/activity-stream-debug.html return [ "resource://activity-stream/prerendered/", this._activityStreamPath, "activity-stream", - this._activityStreamPrerender ? "-prerendered" : "", // Debug version loads dev scripts but noscripts separately loads scripts this._activityStreamDebug && !this._privilegedAboutContentProcess ? "-debug" : "", this._privilegedAboutContentProcess ? "-noscripts" : "", @@ -262,15 +249,10 @@ AboutNewTabService.prototype = { /* * Returns the about:welcome URL * - * This is calculated in the same way the default URL is, except that we don't - * allow prerendering. + * This is calculated in the same way the default URL is. */ get welcomeURL() { - const prerenderEnabled = this._activityStreamPrerender; - this._activityStreamPrerender = false; - const url = this.defaultURL; - this._activityStreamPrerender = prerenderEnabled; - return url; + return this.defaultURL; }, get newTabURL() { @@ -301,10 +283,6 @@ AboutNewTabService.prototype = { return this._activityStreamEnabled; }, - get activityStreamPrerender() { - return this._activityStreamPrerender; - }, - get activityStreamDebug() { return this._activityStreamDebug; }, @@ -352,7 +330,6 @@ AboutNewTabService.prototype = { Services.obs.removeObserver(this, TOPIC_APP_QUIT); Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE); Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this); - Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this); if (!IS_RELEASE_OR_BETA) { Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this); } diff --git a/browser/components/newtab/bin/render-activity-stream-html.js b/browser/components/newtab/bin/render-activity-stream-html.js index 54b1521e2434..510485dada8b 100644 --- a/browser/components/newtab/bin/render-activity-stream-html.js +++ b/browser/components/newtab/bin/render-activity-stream-html.js @@ -3,9 +3,6 @@ const fs = require("fs"); const {mkdir} = require("shelljs"); const path = require("path"); -// Note: this file is generated by webpack from content-src/activity-stream-prerender.jsx -const {prerender} = require("./prerender"); - const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales"); // Note: DEFAULT_OPTIONS.baseUrl should match BASE_URL in aboutNewTabService.js @@ -64,11 +61,9 @@ function getTextDirection(locale) { * {str} options.baseUrl The base URL for all local assets * {bool} options.debug Should we use dev versions of JS libraries? * {bool} options.noscripts Should we include scripts in the prerendered files? - * @param {str} html The prerendered HTML created with React.renderToString (optional) * @return {str} An HTML document as a string */ -function templateHTML(options, html) { - const isPrerendered = !!html; +function templateHTML(options) { const debugString = options.debug ? "-dev" : ""; const scripts = [ "chrome://browser/content/contentSearchUI.js", @@ -82,9 +77,6 @@ function templateHTML(options, html) { `${options.baseUrl}prerendered/${options.locale}/activity-stream-strings.js`, `${options.baseUrl}data/content/activity-stream.bundle.js`, ]; - if (isPrerendered) { - scripts.unshift(`${options.baseUrl}prerendered/static/activity-stream-initial-state.js`); - } // Add spacing and script tags const scriptRender = `\n${scripts.map(script => ` `).join("\n")}`; @@ -101,7 +93,7 @@ function templateHTML(options, html) { -
${isPrerendered ? html : ""}
+
${options.noscripts ? "" : scriptRender} @@ -135,25 +127,20 @@ window.${name} = ${JSON.stringify(state, null, 2)}; * @param {string} name Something to identify in the console * @param {string} destPath Path to write the files to * @param {Map} filesMap Mapping of a string file name to templater - * @param {Object} prerenderData Contains the html and state * @param {Object} options Various options for the templater */ -function writeFiles(name, destPath, filesMap, {html, state}, options) { +function writeFiles(name, destPath, filesMap, options) { for (const [file, templater] of filesMap) { - fs.writeFileSync(path.join(destPath, file), templater({html, options, state})); + fs.writeFileSync(path.join(destPath, file), templater({options})); } console.log("\x1b[32m", `✓ ${name}`, "\x1b[0m"); } const STATIC_FILES = new Map([ ["activity-stream-debug.html", ({options}) => templateHTML(options)], - ["activity-stream-initial-state.js", ({state}) => templateJs("gActivityStreamPrerenderedState", "static", state)], - ["activity-stream-prerendered-debug.html", ({html, options}) => templateHTML(options, html)], ]); const LOCALIZED_FILES = new Map([ - ["activity-stream-prerendered.html", ({html, options}) => templateHTML(options, html)], - ["activity-stream-prerendered-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)], ["activity-stream-strings.js", ({options: {locale, strings}}) => templateJs("gActivityStreamStrings", locale, strings)], ["activity-stream.html", ({options}) => templateHTML(options)], ["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))], @@ -200,7 +187,6 @@ function main() { // eslint-disable-line max-statements continue; } - const prerenderData = prerender(locale, strings); const options = Object.assign({}, baseOptions, { direction: getTextDirection(locale), locale, @@ -210,13 +196,13 @@ function main() { // eslint-disable-line max-statements // Put locale-specific files in their own directory const localePath = path.join(prerenderedPath, "locales", locale); mkdir("-p", localePath); - writeFiles(locale, localePath, LOCALIZED_FILES, prerenderData, options); + writeFiles(locale, localePath, LOCALIZED_FILES, options); // Only write static files once for the default locale if (locale === DEFAULT_LOCALE) { const staticPath = path.join(prerenderedPath, "static"); mkdir("-p", staticPath); - writeFiles(`${locale} (static)`, staticPath, STATIC_FILES, prerenderData, + writeFiles(`${locale} (static)`, staticPath, STATIC_FILES, Object.assign({}, options, {debug: true})); // Save the default strings to compare against other locales' strings diff --git a/browser/components/newtab/common/Actions.jsm b/browser/components/newtab/common/Actions.jsm index 8052416fdba4..d333ae9090aa 100644 --- a/browser/components/newtab/common/Actions.jsm +++ b/browser/components/newtab/common/Actions.jsm @@ -72,7 +72,6 @@ for (const type of [ "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", - "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", diff --git a/browser/components/newtab/common/PerfService.jsm b/browser/components/newtab/common/PerfService.jsm index 43f82db29320..5af45d8f3248 100644 --- a/browser/components/newtab/common/PerfService.jsm +++ b/browser/components/newtab/common/PerfService.jsm @@ -15,17 +15,10 @@ if (typeof Services !== "undefined") { // Borrow the high-resolution timer from the hidden window.... // eslint-disable-next-line block-scoped-var usablePerfObj = Services.appShell.hiddenDOMWindow.performance; -} else if (typeof performance !== "undefined") { +} else { // we must be running in content space // eslint-disable-next-line no-undef usablePerfObj = performance; -} else { - // This is a dummy object so this file doesn't crash in the node prerendering - // task. - usablePerfObj = { - now() {}, - mark() {}, - }; } function _PerfService(options) { diff --git a/browser/components/newtab/common/PrerenderData.jsm b/browser/components/newtab/common/PrerenderData.jsm deleted file mode 100644 index d6309f335667..000000000000 --- a/browser/components/newtab/common/PrerenderData.jsm +++ /dev/null @@ -1,126 +0,0 @@ -class _PrerenderData { - constructor(options) { - this.initialPrefs = options.initialPrefs; - this.initialSections = options.initialSections; - this._setValidation(options.validation); - } - - get validation() { - return this._validation; - } - - set validation(value) { - this._setValidation(value); - } - - get invalidatingPrefs() { - return this._invalidatingPrefs; - } - - // This is needed so we can use it in the constructor - _setValidation(value = []) { - this._validation = value; - this._invalidatingPrefs = value.reduce((result, next) => { - if (typeof next === "string") { - result.push(next); - return result; - } else if (next && next.oneOf) { - return result.concat(next.oneOf); - } else if (next && next.indexedDB) { - return result.concat(next.indexedDB); - } else if (next && next.jsonPrefs) { - return result.concat(next.jsonPrefs); - } - throw new Error("Your validation configuration is not properly configured"); - }, []); - } - - _isPrefEnabled(prefObj) { - try { - let data = JSON.parse(prefObj); - return (data && data.enabled) ? true : false; // eslint-disable-line no-unneeded-ternary - } catch (e) { - return false; - } - } - - arePrefsValid(getPref, indexedDBPrefs) { - for (const prefs of this.validation) { - // {oneOf: ["foo", "bar"]} - if (prefs && prefs.oneOf && !prefs.oneOf.some(name => getPref(name) === this.initialPrefs[name])) { - return false; - - // {indexedDB: ["foo", "bar"]} - } else if (indexedDBPrefs && prefs && prefs.indexedDB) { - const anyModifiedPrefs = prefs.indexedDB.some(prefName => indexedDBPrefs.some(pref => pref && pref[prefName])); - if (anyModifiedPrefs) { - return false; - } - // {jsonPrefs: ["foo", "bar"]} - } else if (prefs && prefs.jsonPrefs) { - const isPrefModified = - prefs.jsonPrefs.some(name => this._isPrefEnabled(getPref(name)) !== this.initialPrefs[name].enabled); - if (isPrefModified) { - return false; - } - // "foo" - } else if (getPref(prefs) !== this.initialPrefs[prefs]) { - return false; - } - } - return true; - } -} - -this.PrerenderData = new _PrerenderData({ - initialPrefs: { - "feeds.topsites": true, - "showSearch": true, - "topSitesRows": 1, - "feeds.section.topstories": true, - "feeds.section.highlights": true, - "sectionOrder": "topsites,topstories,highlights", - "collapsed": false, - "discoverystream.config": {"enabled": false}, - }, - // Prefs listed as invalidating will prevent the prerendered version - // of AS from being used if their value is something other than what is listed - // here. This is required because some preferences cause the page layout to be - // too different for the prerendered version to be used. Unfortunately, this - // will result in users who have modified some of their preferences not being - // able to get the benefits of prerendering. - validation: [ - "feeds.topsites", - "showSearch", - "topSitesRows", - "sectionOrder", - // This means if either of these are set to their default values, - // prerendering can be used. - {oneOf: ["feeds.section.topstories", "feeds.section.highlights"]}, - // If any component has the following preference set to `true` it will - // invalidate the prerendered version. - {indexedDB: ["collapsed"]}, - // For below prefs, parse value to check enabled property. If enabled property - // differs from initial prefs enabled value, prerendering cannot be used - {jsonPrefs: ["discoverystream.config"]}, - ], - initialSections: [ - { - enabled: true, - icon: "pocket", - id: "topstories", - order: 1, - title: {id: "header_recommended_by", values: {provider: "Pocket"}}, - }, - { - enabled: true, - id: "highlights", - icon: "highlights", - order: 2, - title: {id: "header_highlights"}, - }, - ], -}); - -this._PrerenderData = _PrerenderData; -const EXPORTED_SYMBOLS = ["PrerenderData", "_PrerenderData"]; diff --git a/browser/components/newtab/content-src/activity-stream-prerender.jsx b/browser/components/newtab/content-src/activity-stream-prerender.jsx deleted file mode 100644 index b1464bad5a52..000000000000 --- a/browser/components/newtab/content-src/activity-stream-prerender.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import {INITIAL_STATE, reducers} from "common/Reducers.jsm"; -import {actionTypes as at} from "common/Actions.jsm"; -import {Base} from "content-src/components/Base/Base"; -import {initStore} from "content-src/lib/init-store"; -import {PrerenderData} from "common/PrerenderData.jsm"; -import {Provider} from "react-redux"; -import React from "react"; -import ReactDOMServer from "react-dom/server"; - -/** - * prerenderStore - Generate a store with the initial state required for a prerendered page - * - * @return {obj} A store - */ -export function prerenderStore() { - const store = initStore(reducers, INITIAL_STATE); - store.dispatch({type: at.PREFS_INITIAL_VALUES, data: PrerenderData.initialPrefs}); - PrerenderData.initialSections.forEach(data => store.dispatch({type: at.SECTION_REGISTER, data})); - return store; -} - -export function prerender(locale, strings, - renderToString = ReactDOMServer.renderToString) { - const store = prerenderStore(); - - const html = renderToString( - - - ); - - // If this happens, it means pre-rendering is effectively disabled, so we - // need to sound the alarms: - if (!html || !html.length) { - throw new Error("no HTML returned"); - } - - return { - html, - state: store.getState(), - store, - }; -} diff --git a/browser/components/newtab/content-src/activity-stream.jsx b/browser/components/newtab/content-src/activity-stream.jsx index 4159c0428258..b66c5c9b6eb3 100644 --- a/browser/components/newtab/content-src/activity-stream.jsx +++ b/browser/components/newtab/content-src/activity-stream.jsx @@ -7,21 +7,15 @@ import React from "react"; import ReactDOM from "react-dom"; import {reducers} from "common/Reducers.jsm"; -const store = initStore(reducers, global.gActivityStreamPrerenderedState); +const store = initStore(reducers); new DetectUserSessionStart(store).sendEventOrAddListener(); -// If we are starting in a prerendered state, we must wait until the first render -// to request state rehydration (see Base.jsx). If we are NOT in a prerendered state, -// we can request it immedately. -if (!global.gActivityStreamPrerenderedState) { - store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST})); -} +store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST})); ReactDOM.hydrate( , document.getElementById("root")); diff --git a/browser/components/newtab/content-src/asrouter/asrouter-content.jsx b/browser/components/newtab/content-src/asrouter/asrouter-content.jsx index f24f6f11cffb..d68fc09847a0 100644 --- a/browser/components/newtab/content-src/asrouter/asrouter-content.jsx +++ b/browser/components/newtab/content-src/asrouter/asrouter-content.jsx @@ -1,7 +1,7 @@ import {addLocaleData, IntlProvider} from "react-intl"; import {actionCreators as ac} from "common/Actions.jsm"; import {OUTGOING_MESSAGE_NAME as AS_GENERAL_OUTGOING_MESSAGE_NAME} from "content-src/lib/init-store"; -import {generateMessages} from "./rich-text-strings"; +import {generateBundles} from "./rich-text-strings"; import {ImpressionsWrapper} from "./components/ImpressionsWrapper/ImpressionsWrapper"; import {LocalizationProvider} from "fluent-react"; import {NEWTAB_DARK_THEME} from "content-src/lib/constants"; @@ -257,7 +257,7 @@ export class ASRouterUISurface extends React.PureComponent { shouldSendImpressionOnUpdate={shouldSendImpressionOnUpdate} // This helps with testing document={this.props.document}> - + + -
-
+