/* 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/. */ /* eslint-disable no-console */ const fs = require("fs"); const { mkdir } = require("shelljs"); const path = require("path"); const { pathToFileURL } = require("url"); const chalk = require("chalk"); const DEFAULT_OPTIONS = { // Glob leading from CWD to the parent of the intended prerendered directory. // Starting in newtab/bin/ and we want to write to newtab/prerendered/ so we // go up one level. addonPath: "..", // depends on the registration in browser/components/newtab/jar.mn baseUrl: "resource://activity-stream/", }; /** * templateHTML - Generates HTML for activity stream, given some options and * prerendered HTML if necessary. * * @param {obj} options * {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? * @return {str} An HTML document as a string */ function templateHTML(options) { const debugString = options.debug ? "-dev" : ""; // This list must match any similar ones in AboutNewTabChild.sys.mjs const scripts = [ "chrome://browser/content/contentSearchUI.js", "chrome://browser/content/contentSearchHandoffUI.js", "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 => ` `) .join("\n")}`; // The markup below needs to be formatted by Prettier. But any diff after // running this script should be caught by try-runnner.js return `
${options.noscripts ? "" : scriptRender} `.trimLeft(); } /** * writeFiles - Writes to the desired files the result of a template given * various prerendered data and options. * * @param {string} destPath Path to write the files to * @param {Map} filesMap Mapping of a string file name to templater * @param {Object} options Various options for the templater */ function writeFiles(destPath, filesMap, options) { for (const [file, templater] of filesMap) { fs.writeFileSync(path.join(destPath, file), templater({ options })); console.log(chalk.green(`✓ ${file}`)); } } const STATIC_FILES = new Map([ ["activity-stream.html", ({ options }) => templateHTML(options)], [ "activity-stream-debug.html", ({ options }) => templateHTML(Object.assign({}, options, { debug: true })), ], [ "activity-stream-noscripts.html", ({ options }) => templateHTML(Object.assign({}, options, { noscripts: true })), ], ]); /** * main - Parses command line arguments, generates html and js with templates, * and writes files to their specified locations. */ async function main() { const { default: meow } = await import("meow"); const fileUrl = pathToFileURL(__filename); const cli = meow( ` Usage $ node ./bin/render-activity-stream-html.js [options] Options -a PATH, --addon-path PATH Path to the parent of the target directory. default: "${DEFAULT_OPTIONS.addonPath}" -b URL, --base-url URL Base URL for assets. default: "${DEFAULT_OPTIONS.baseUrl}" --help Show this help message. `, { description: false, // `pkg` is a tiny optimization. It prevents meow from looking for a package // that doesn't technically exist. meow searches for a package and changes // the process name to the package name. It resolves to the newtab // package.json, which would give a confusing name and be wasteful. pkg: { name: "render-activity-stream-html", version: "0.0.0", }, // `importMeta` is required by meow 10+. It was added to support ESM, but // meow now requires it, and no longer supports CJS style imports. But it // only uses import.meta.url, which can be polyfilled like this: importMeta: { url: fileUrl }, flags: { addonPath: { type: "string", alias: "a", default: DEFAULT_OPTIONS.addonPath, }, baseUrl: { type: "string", alias: "b", default: DEFAULT_OPTIONS.baseUrl, }, }, } ); const options = Object.assign({ debug: false }, cli.flags || {}); const addonPath = path.resolve(__dirname, options.addonPath); const prerenderedPath = path.join(addonPath, "prerendered"); console.log(`Writing prerendered files to ${prerenderedPath}:`); mkdir("-p", prerenderedPath); writeFiles(prerenderedPath, STATIC_FILES, options); } main();