Skip to content

Commit

Permalink
report: create faux psi report (#12815)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish authored Aug 11, 2021
1 parent 740009f commit e6a6b61
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 18 deletions.
18 changes: 15 additions & 3 deletions build/build-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,25 @@ async function buildUmdBundle() {
}

if (require.main === module) {
if (process.argv[2] === '--only-standalone') {
buildStandaloneReport();
} else {
if (process.argv.length <= 2) {
buildStandaloneReport();
buildEsModulesBundle();
buildPsiReport();
buildUmdBundle();
}

if (process.argv.includes('--psi')) {
buildPsiReport();
}
if (process.argv.includes('--standalone')) {
buildStandaloneReport();
}
if (process.argv.includes('--esm')) {
buildEsModulesBundle();
}
if (process.argv.includes('--umd')) {
buildUmdBundle();
}
}

module.exports = {
Expand Down
50 changes: 47 additions & 3 deletions lighthouse-core/scripts/build-report-for-autodeployment.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const {defaultSettings} = require('../config/constants.js');
const lighthouse = require('../index.js');
const lhr = /** @type {LH.Result} */ (require('../../lighthouse-core/test/results/sample_v2.json'));
const {LH_ROOT} = require('../../root.js');
const htmlReportAssets = require('../../report/report-assets.js');


const DIST = path.join(LH_ROOT, `dist/now`);

Expand All @@ -29,19 +31,23 @@ const DIST = path.join(LH_ROOT, `dist/now`);
'ɑrabic': swapLocale(lhr, 'ar').lhr,
'xl-accented': swapLocale(lhr, 'en-XL').lhr,
'error': errorLhr,
'single-category': tweakLhrForPsi(lhr),
};

// Generate and write reports
Object.entries(filenameToLhr).forEach(([filename, lhr]) => {
let html = ReportGenerator.generateReportHtml(lhr);
// TODO: PSI is another variant to consider
for (const variant of ['', '⌣.cdt.']) {
for (const variant of ['', '⌣.cdt.', '⌣.psi.']) {
let html = variant.includes('psi') ?
generatePsiReportHtml() :
ReportGenerator.generateReportHtml(lhr);

if (variant.includes('cdt')) {
// TODO: Make the DevTools Audits panel "emulation" more comprehensive
// - the parent widget/vbox container with overflow
// - a more constrained/realistic default size
html = html.replace(`"lh-root lh-vars"`, `"lh-root lh-vars lh-devtools"`);
}

const filepath = `${DIST}/${variant}${filename}/index.html`;
fs.mkdirSync(path.dirname(filepath), {recursive: true});
fs.writeFileSync(filepath, html, {encoding: 'utf-8'});
Expand All @@ -50,6 +56,26 @@ const DIST = path.join(LH_ROOT, `dist/now`);
});
})();


/**
* @return {string}
*/
function generatePsiReportHtml() {
const sanitizedJson = ReportGenerator.sanitizeJson(tweakLhrForPsi(lhr));
const PSI_TEMPLATE = fs.readFileSync(
`${LH_ROOT}/report/test-assets/faux-psi-template.html`, 'utf8');
const PSI_JAVASCRIPT = `
${fs.readFileSync(`${LH_ROOT}/dist/report/psi.js`, 'utf8')};
${fs.readFileSync(`${LH_ROOT}/report/test-assets/faux-psi.js`, 'utf8')};
`;

const html = ReportGenerator.replaceStrings(PSI_TEMPLATE, [
{search: '%%LIGHTHOUSE_JSON%%', replacement: sanitizedJson},
{search: '%%LIGHTHOUSE_JAVASCRIPT%%', replacement: PSI_JAVASCRIPT},
{search: '/*%%LIGHTHOUSE_CSS%%*/', replacement: htmlReportAssets.REPORT_CSS},
]);
return html;
}
/**
* Add a plugin to demo plugin rendering.
* @param {LH.Result} lhr
Expand All @@ -63,6 +89,24 @@ function addPluginCategory(lhr) {
};
}

/**
* Drops the LHR to only one, solo category (performance), and removes budgets.
* @param {LH.Result} lhr
*/
function tweakLhrForPsi(lhr) {
/** @type {LH.Result} */
const clone = JSON.parse(JSON.stringify(lhr));
clone.categories = {
'performance': clone.categories.performance,
};
// no budgets in PSI
delete clone.audits['performance-budget'];
clone.categories.performance.auditRefs = clone.categories.performance.auditRefs.filter(audit => {
return !audit.id.endsWith('-budget');
});
return clone;
}

/**
* Generate an LHR with errors for the renderer to display.
* We'll write an "empty" artifacts file to disk, only to use it in auditMode.
Expand Down
1 change: 0 additions & 1 deletion lighthouse-viewer/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
<link rel="stylesheet" href="styles/bundled.css">
</head>
<body class="lh-root lh-vars">
<div hidden>%%LIGHTHOUSE_TEMPLATES%%</div>

<div class="drop_zone"></div>

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"build-lr": "yarn reset-link && node ./build/build-lightrider-bundles.js",
"build-pack": "bash build/build-pack.sh",
"build-report": "node build/build-report-components.js && yarn eslint --fix report/renderer/components.js && node build/build-report.js",
"build-dist-reports": "yarn build-report && node lighthouse-core/scripts/build-report-for-autodeployment.js",
"build-treemap": "node ./build/build-treemap.js",
"build-viewer": "node ./build/build-viewer.js",
"reset-link": "(yarn unlink || true) && yarn link && yarn link lighthouse",
Expand All @@ -32,7 +33,7 @@
"lint": "[ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .",
"smoke": "node lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js",
"debug": "node --inspect-brk ./lighthouse-cli/index.js",
"start": "yarn build-report --only-standalone && node ./lighthouse-cli/index.js",
"start": "yarn build-report --standalone && node ./lighthouse-cli/index.js",
"jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
"test": "yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check",
"test-bundle": "yarn smoke --runner bundle -j=1 --retries=2 --invert-match forms",
Expand Down Expand Up @@ -62,7 +63,7 @@
"fast": "node ./lighthouse-cli/index.js --preset=desktop --throttlingMethod=provided",
"deploy-treemap": "yarn build-treemap --deploy",
"deploy-viewer": "yarn build-viewer --deploy",
"now-build": "yarn build-report && node lighthouse-core/scripts/build-report-for-autodeployment.js && yarn build-viewer && yarn build-treemap && cp -r dist/gh-pages dist/now/gh-pages",
"now-build": "yarn build-dist-reports && yarn build-viewer && yarn build-treemap && cp -r dist/gh-pages dist/now/gh-pages",
"dogfood-lhci": "./lighthouse-core/scripts/dogfood-lhci.sh",
"timing-trace": "node lighthouse-core/scripts/generate-timing-trace.js",
"changelog": "conventional-changelog --config ./build/changelog-generator/index.js --infile changelog.md --same-file",
Expand Down
1 change: 0 additions & 1 deletion report/assets/standalone-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
</head>
<body class="lh-root lh-vars">
<noscript>Lighthouse report requires JavaScript. Please enable.</noscript>
<div hidden>%%LIGHTHOUSE_TEMPLATES%%</div>

<main><!-- report populated here --></main>

Expand Down
15 changes: 13 additions & 2 deletions report/clients/psi.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import {PerformanceCategoryRenderer} from '../renderer/performance-category-rend
import {ReportUIFeatures} from '../renderer/report-ui-features.js';
import {Util} from '../renderer/util.js';

/* global window */

/** @typedef {{scoreGaugeEl: Element, perfCategoryEl: Element, finalScreenshotDataUri: string|null, scoreScaleEl: Element, installFeatures: Function}} PrepareLabDataResult */

/**
* Returns all the elements that PSI needs to render the report
* We expose this helper method to minimize the 'public' API surface of the renderer
Expand All @@ -36,7 +40,7 @@ import {Util} from '../renderer/util.js';
*
* @param {LH.Result | string} LHResult The stringified version of {LH.Result}
* @param {Document} document The host page's window.document
* @return {{scoreGaugeEl: Element, perfCategoryEl: Element, finalScreenshotDataUri: string|null, scoreScaleEl: Element, installFeatures: Function}}
* @return {PrepareLabDataResult}
*/
export function prepareLabData(LHResult, document) {
const lhResult = (typeof LHResult === 'string') ?
Expand Down Expand Up @@ -89,10 +93,11 @@ export function prepareLabData(LHResult, document) {
/** @param {HTMLElement} reportEl */
const installFeatures = (reportEl) => {
if (fullPageScreenshot) {
// 1) Add fpss css var to reportEl parent so any thumbnails will work
ElementScreenshotRenderer.installFullPageScreenshot(
reportEl, fullPageScreenshot.screenshot);

// Append the overlay element to a specific part of the DOM so that
// 2) Append the overlay element to a specific part of the DOM so that
// the sticky tab group element renders correctly. If put in the reportEl
// like normal, then the sticky header would bleed through the overlay
// element.
Expand Down Expand Up @@ -141,3 +146,9 @@ function _getFinalScreenshot(perfCategory) {
if (!details || details.type !== 'screenshot') return null;
return details.data;
}

// TODO: remove with report API refactor.
if (typeof window !== 'undefined') {
// @ts-expect-error
window.prepareLabData = prepareLabData;
}
18 changes: 13 additions & 5 deletions report/report-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,23 @@ class ReportGenerator {
}

/**
* Returns the report HTML as a string with the report JSON and renderer JS inlined.
* @param {unknown} object
* @return {string}
*/
static sanitizeJson(object) {
return JSON.stringify(object)
.replace(/</g, '\\u003c') // replaces opening script tags
.replace(/\u2028/g, '\\u2028') // replaces line separators ()
.replace(/\u2029/g, '\\u2029'); // replaces paragraph separators
}

/**
* Returns the standalone report HTML as a string with the report JSON and renderer JS inlined.
* @param {LH.Result} lhr
* @return {string}
*/
static generateReportHtml(lhr) {
const sanitizedJson = JSON.stringify(lhr)
.replace(/</g, '\\u003c') // replaces opening script tags
.replace(/\u2028/g, '\\u2028') // replaces line separators ()
.replace(/\u2029/g, '\\u2029'); // replaces paragraph separators
const sanitizedJson = ReportGenerator.sanitizeJson(lhr);
// terser does its own sanitization, but keep this basic replace for when
// we want to generate a report without minification.
const sanitizedJavascript = htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g, '\\u003c/');
Expand Down
126 changes: 126 additions & 0 deletions report/test-assets/faux-psi-template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!--
* Copyright 2021 The Lighthouse Authors. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-->

<!--
This fake psi page is intended to reproduce the experience of rendering two LHRs within the same DOM,
like in PageSpeed Insights. This helps surface the peculiar behavior around tabs,
expectations of unique IDs, and scoped report containment.

This comment has been minimized.

Copy link
@gifhuppp

gifhuppp Aug 12, 2021

ขอบคุณสำหรับความรู้

-->

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<title>Faux PageSpeed Report</title>
<style>/*%%LIGHTHOUSE_CSS%%*/</style>

<style>
/* Inspired by https://codepen.io/markcaron/pen/MvGRYV?editors=1100 but improved. s*/
/*
The tab visibility basics
*/
.tabset > input[type="radio"] {
position: absolute;
left: -200vw;
}

.tabset .tab-panel {
display: none;
}

.tabset > input:nth-of-type(1):checked ~ .tab-panels > .tab-panel:nth-of-type(1),
.tabset > input:nth-of-type(2):checked ~ .tab-panels > .tab-panel:nth-of-type(2) {
display: block;
}

/*
Purdy tabs
*/
.tabset > label {
position: relative;
display: inline-block;
padding: 15px 55px 15px;
border: 1px solid transparent;
border-bottom: 0;
cursor: pointer;
font-weight: 600;
}

.tabset > label:hover {
background-color: hsl(0deg 0% 100% / 24%);
}

.tabset > label:hover,
.tabset > input:focus + label {
color: #06c;
}

.tabset > input:checked + label {
border-color: #ccc;
border-bottom: 1px solid #fff;
margin-bottom: -1px;
background: white;
}

.tab-panel {
padding: 30px 0;
border-top: 1px solid #ccc;
}

body {
padding: 30px;
}

.tabset {
max-width: 65em;
background: #eee;
}

.tab-panels {
background: white;
}

/* extra styles */
body {
background: hsl(217deg 89% 61%);
}
</style>
</head>
<body >
<noscript>PSI requires JavaScript. Please enable.</noscript>

<div class="element-screenshots-container"></div>


<div class="tabset lh-vars lh-root">

<input type="radio" name="tabset" id="tab1" aria-controls="mobile" checked>
<label for="tab1">Mobile</label>

<input type="radio" name="tabset" id="tab2" aria-controls="desktop">
<label for="tab2">Desktop</label>

<div class="tab-panels">
<section id="mobile" class="tab-panel">
<main></main>
</section>

<section id="desktop" class="tab-panel">
<main></main>
</section>

</div>
</div>

<script>window.__LIGHTHOUSE_JSON__ = %%LIGHTHOUSE_JSON%%;</script>
<script type="module">
%%LIGHTHOUSE_JAVASCRIPT%%
//# sourceURL=psi-reportrenderer.js
</script>
<script>console.log('window.__LIGHTHOUSE_JSON__', __LIGHTHOUSE_JSON__);</script>
</body>
</html>
Loading

0 comments on commit e6a6b61

Please sign in to comment.