Skip to content

Commit

Permalink
report: swap locale, enable in viewer (GoogleChrome#10148)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark authored Oct 7, 2021
1 parent 8284fe1 commit eb4c1ae
Show file tree
Hide file tree
Showing 18 changed files with 434 additions and 104 deletions.
2 changes: 1 addition & 1 deletion build/build-treemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ async function run() {
{path: 'src/main.js', rollup: true},
],
assets: [
{path: 'images/**/*'},
{path: 'images/**/*', destDir: 'images'},
{path: 'debug.json'},
],
});
Expand Down
33 changes: 31 additions & 2 deletions build/build-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
*/
'use strict';

const fs = require('fs');
const browserify = require('browserify');
const rollupPlugins = require('./rollup-plugins.js');
const GhPagesApp = require('./gh-pages-app.js');
const {minifyFileTransform} = require('./build-utils.js');
const {LH_ROOT} = require('../root.js');

const localeBasenames = fs.readdirSync(LH_ROOT + '/shared/localization/locales/');
const actualLocales = localeBasenames
.filter(basename => basename.endsWith('.json') && !basename.endsWith('.ctc.json'))
.map(locale => locale.replace('.json', ''))
.sort();

/**
* Build viewer, optionally deploying to gh-pages if `--deploy` flag was set.
*/
Expand Down Expand Up @@ -41,11 +49,32 @@ async function run() {
javascripts: [
await generatorJsPromise,
{path: require.resolve('pako/dist/pako_inflate.js')},
{path: 'src/main.js', rollup: true},
{path: 'src/main.js', rollup: true, rollupPlugins: [
rollupPlugins.replace({
// Default delimiters are word boundraries. Setting them to nothing (empty strings)
// makes this plugin replace any subtring found.
delimiters: ['', ''],
values: {
'[\'__availableLocales__\']': JSON.stringify(actualLocales),
},
}),
rollupPlugins.replace({
values: {
'__dirname': '""',
},
}),
rollupPlugins.shim({
'./locales.js': 'export default {}',
}),
rollupPlugins.commonjs(),
rollupPlugins.nodePolyfills(),
rollupPlugins.nodeResolve({preferBuiltins: true}),
]},
],
assets: [
{path: 'images/**/*'},
{path: 'images/**/*', destDir: 'images'},
{path: 'manifest.json'},
{path: '../../shared/localization/locales/*.json', destDir: 'locales'},
],
});

Expand Down
36 changes: 26 additions & 10 deletions build/gh-pages-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const license = `/*
/**
* Literal string (representing JS, CSS, etc...), or an object with a path, which would
* be interpreted relative to opts.appDir and be glob-able.
* @typedef {{path: string, rollup?: boolean} | string} Source
* @typedef {{path: string, rollup?: boolean, rollupPlugins?: rollup.Plugin[]} | string} Source
*/

/**
Expand All @@ -48,7 +48,7 @@ const license = `/*
* @property {Record<string, string>=} htmlReplacements Needle -> Replacement mapping, used on html source.
* @property {Source[]} stylesheets
* @property {Source[]} javascripts
* @property {Array<{path: string}>} assets List of paths to copy. Glob-able, maintains directory structure.
* @property {Array<{path: string, destDir?: string, rename?: string}>} assets List of paths to copy. Glob-able, maintains directory structure and copies into appDir. Provide a `destDir` and `rename` to state explicitly how to save in the app dir folder.
*/

/**
Expand Down Expand Up @@ -94,10 +94,13 @@ class GhPagesApp {
const bundledJs = await this._compileJs();
safeWriteFile(`${this.distDir}/src/bundled.js`, bundledJs);

await cpy(this.opts.assets.map(asset => asset.path), this.distDir, {
cwd: this.opts.appDir,
parents: true,
});
for (const {path, destDir, rename} of this.opts.assets) {
const dir = destDir ? `${this.distDir}/${destDir}` : this.distDir;
await cpy(path, dir, {
cwd: this.opts.appDir,
rename,
});
}
}

/**
Expand Down Expand Up @@ -127,7 +130,10 @@ class GhPagesApp {
if (typeof source === 'string') {
result.push(source);
} else if (source.rollup) {
result.push(await this._rollupSource(path.resolve(this.opts.appDir, source.path)));
result.push(await this._rollupSource(
path.resolve(this.opts.appDir, source.path),
source.rollupPlugins)
);
} else {
result.push(...loadFiles(path.resolve(this.opts.appDir, source.path)));
}
Expand All @@ -138,10 +144,11 @@ class GhPagesApp {

/**
* @param {string} input
* @param {rollup.Plugin[]=} plugins
* @return {Promise<string>}
*/
async _rollupSource(input) {
const plugins = [
async _rollupSource(input, plugins) {
plugins = plugins || [
rollupPlugins.nodeResolve(),
rollupPlugins.commonjs(),
];
Expand All @@ -150,7 +157,16 @@ class GhPagesApp {
input,
plugins,
});
const {output} = await bundle.generate({format: 'iife'});
const {output} = await bundle.generate({format: 'esm'});

// Return the code from the main chunk, and save the rest to the src directory.
for (let i = 1; i < output.length; i++) {
if (output[i].type === 'chunk') {
// @ts-expect-error This is a chunk, not an asset.
const code = output[i].code;
safeWriteFile(`${this.distDir}/src/${output[i].fileName}`, code);
}
}
return output[0].code;
}

Expand Down
4 changes: 4 additions & 0 deletions build/rollup-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ function rollupPluginTypeCoerce(module) {
}

const commonjs = rollupPluginTypeCoerce(require('@rollup/plugin-commonjs'));
const nodePolyfills = rollupPluginTypeCoerce(require('rollup-plugin-polyfill-node'));
const {nodeResolve} = require('@rollup/plugin-node-resolve');
const replace = rollupPluginTypeCoerce(require('rollup-plugin-replace'));
// @ts-expect-error: no published types.
const shim = require('rollup-plugin-shim');
const {terser} = require('rollup-plugin-terser');
const typescript = rollupPluginTypeCoerce(require('@rollup/plugin-typescript'));

module.exports = {
commonjs,
nodePolyfills,
nodeResolve,
replace,
shim,
terser,
typescript,
Expand Down
2 changes: 1 addition & 1 deletion lighthouse-core/scripts/i18n/collect-strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ async function collectAllStringsInDir(dir) {
// No UIStrings found in the file text or exports, so move to the next.
if (!exportedUIStrings) continue;

throw new Error('UIStrings exported but no definition found');
throw new Error('UIStrings exported but no definition found: ' + relativeToRootPath);
}

if (!exportedUIStrings) {
Expand Down
12 changes: 9 additions & 3 deletions lighthouse-viewer/app/src/lighthouse-report-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,17 +229,23 @@ export class LighthouseReportViewer {
renderer.renderReport(json, container);

// Only give gist-saving callback if current report isn't from a gist.
let saveCallback = null;
let saveGistCallback;
if (!this._reportIsFromGist) {
saveCallback = this._onSaveJson;
saveGistCallback = this._onSaveJson;
}

// Only clear query string if current report isn't from a gist or PSI.
if (!this._reportIsFromGist && !this._reportIsFromPSI && !this._reportIsFromJSON) {
history.pushState({}, '', LighthouseReportViewer.APP_URL);
}

const features = new ViewerUIFeatures(dom, saveCallback);
const features = new ViewerUIFeatures(dom, {
saveGist: saveGistCallback,
/** @param {LH.Result} newLhr */
refresh: newLhr => {
this._replaceReportHtml(newLhr);
},
});
features.initFeatures(json);
} catch (e) {
logger.error(`Error rendering report: ${e.message}`);
Expand Down
50 changes: 47 additions & 3 deletions lighthouse-viewer/app/src/viewer-ui-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
/* global ReportGenerator */

/** @typedef {import('../../../report/renderer/dom').DOM} DOM */
/** @typedef {import('../../../shared/localization/locales').LhlMessages} LhlMessages */

import {ReportUIFeatures} from '../../../report/renderer/report-ui-features.js';
import {SwapLocaleFeature} from '../../../report/renderer/swap-locale-feature.js';

/**
* Extends ReportUIFeatures to add an (optional) ability to save to a gist and
Expand All @@ -18,12 +20,16 @@ import {ReportUIFeatures} from '../../../report/renderer/report-ui-features.js';
export class ViewerUIFeatures extends ReportUIFeatures {
/**
* @param {DOM} dom
* @param {?function(LH.Result): void} saveGistCallback
* @param {{saveGist?: function(LH.Result): void, refresh: function(LH.Result): void}} callbacks
*/
constructor(dom, saveGistCallback) {
constructor(dom, callbacks) {
super(dom);

this._saveGistCallback = saveGistCallback;
this._saveGistCallback = callbacks.saveGist;
this._refreshCallback = callbacks.refresh;
this._swapLocales = new SwapLocaleFeature(this, this._dom, {
onLocaleSelected: this._swapLocale.bind(this),
});
}

/**
Expand All @@ -39,6 +45,12 @@ export class ViewerUIFeatures extends ReportUIFeatures {
this._dom.find('.lh-tools__dropdown a[data-action="save-gist"]', this._document);
saveGistItem.setAttribute('disabled', 'true');
}

this._getI18nModule().then(async (i18nModule) => {
const locales = /** @type {LH.Locale[]} */ (
await i18nModule.format.getCanonicalLocales());
this._swapLocales.enable(locales);
}).catch(err => console.error(err));
}

/**
Expand Down Expand Up @@ -66,4 +78,36 @@ export class ViewerUIFeatures extends ReportUIFeatures {
this._dom.find('.lh-tools__dropdown a[data-action="save-gist"]', this._document);
saveGistItem.setAttribute('disabled', 'true');
}

/**
* @param {LH.Locale} locale
* @return {Promise<LhlMessages>}
*/
async _fetchLocaleMessages(locale) {
const response = await fetch(`./locales/${locale}.json`);
return response.json();
}

/**
* @param {LH.Locale} locale
*/
async _swapLocale(locale) {
const lhlMessages = await this._fetchLocaleMessages(locale);
const i18nModule = await this._getI18nModule();
if (!lhlMessages) throw new Error(`could not fetch data for locale: ${locale}`);

i18nModule.format.registerLocaleData(locale, lhlMessages);
const newLhr = i18nModule.swapLocale(this.json, locale).lhr;
this._refreshCallback(newLhr);
}

/**
* The i18n module is only need for swap-locale-feature.js, and is ~30KB,
* so it is lazily loaded.
* TODO: reduce the size of the formatting code and include it always (remove lazy load),
* possibly moving into base ReportUIFeatures.
*/
_getI18nModule() {
return import('../../../shared/localization/i18n-module.js');
}
}
31 changes: 31 additions & 0 deletions lighthouse-viewer/test/viewer-test-pptr.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import puppeteer from 'puppeteer';
import {server} from '../../lighthouse-cli/test/fixtures/static-server.js';
import defaultConfig from '../../lighthouse-core/config/default-config.js';
import {LH_ROOT} from '../../root.js';
import {getCanonicalLocales} from '../../shared/localization/format.js';

const portNumber = 10200;
const viewerUrl = `http://localhost:${portNumber}/dist/gh-pages/viewer/index.html`;
Expand Down Expand Up @@ -147,6 +148,36 @@ describe('Lighthouse Viewer', () => {
const errors = auditErrors.filter(item => item.explanation.includes('Audit error:'));
assert.deepStrictEqual(errors, [], 'Audit errors found within the report');
});

it('should support swapping locales', async () => {
function queryLocaleState() {
return viewerPage.$$eval('.lh-locale-selector', (elems) => {
const selectEl = elems[0];
const optionEls = [...selectEl.querySelectorAll('option')];
return {
selectedValue: selectEl.value,
options: optionEls.map(el => {
return el.value;
}),
sampleString: document.querySelector('.lh-report-icon--copy').textContent,
};
});
}

const resultBeforeSwap = await queryLocaleState();
expect(resultBeforeSwap.selectedValue).toBe('en-US');
expect(resultBeforeSwap.options).toEqual(getCanonicalLocales());
expect(resultBeforeSwap.sampleString).toBe('Copy JSON');

await viewerPage.select('.lh-locale-selector', 'es');
await viewerPage.waitForFunction(() => {
return document.querySelector('.lh-report-icon--copy').textContent === 'Copiar JSON';
});

const resultAfterSwap = await queryLocaleState();
expect(resultAfterSwap.selectedValue).toBe('es');
expect(resultAfterSwap.sampleString).toBe('Copiar JSON');
});
});

describe('PSI', () => {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@
"puppeteer": "^10.2.0",
"rollup": "^2.50.6",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-polyfill-node": "^0.7.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-shim": "^1.0.0",
"rollup-plugin-terser": "^7.0.2",
"tabulator-tables": "^4.9.3",
Expand Down
4 changes: 4 additions & 0 deletions report/assets/styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit eb4c1ae

Please sign in to comment.