From 4f3016bd2b06b0b40962e6c886e0b01d5b826f80 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Fri, 11 May 2018 18:44:30 -0700 Subject: [PATCH 1/8] viewer: support legacy versions --- .../html/renderer/report-ui-features.js | 19 +++++++------- .../app/src/lighthouse-report-viewer.js | 26 +++++++++++++++++-- .../app/src/viewer-ui-features.js | 7 ----- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index 67541a25fa23..bec5ce967a1a 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -10,6 +10,8 @@ * the report. */ +const VIEWER_ORIGIN = 'https://googlechrome.github.io'; + /* globals self URL Blob CustomEvent getFilenamePrefix window */ class ReportUIFeatures { @@ -318,7 +320,8 @@ class ReportUIFeatures { break; } case 'open-viewer': { - this.sendJsonReport(); + const viewerPath = '/lighthouse/viewer/'; + this.sendJsonReport(this.json, viewerPath); break; } case 'save-gist': { @@ -344,30 +347,28 @@ class ReportUIFeatures { /** * Opens a new tab to the online viewer and sends the local page's JSON results * to the online viewer using postMessage. + * @param {!ReportRenderer.ReportJSON} reportJson + * @param {string} viewerPath * @protected */ - sendJsonReport() { - const VIEWER_ORIGIN = 'https://googlechrome.github.io'; - const VIEWER_URL = `${VIEWER_ORIGIN}/lighthouse/viewer/`; - + sendJsonReport(reportJson, viewerPath, onMessageCallback = function() { }) { // Chrome doesn't allow us to immediately postMessage to a popup right // after it's created. Normally, we could also listen for the popup window's // load event, however it is cross-domain and won't fire. Instead, listen // for a message from the target app saying "I'm open". - const json = this.json; + const json = reportJson; window.addEventListener('message', function msgHandler(/** @type {!Event} */ e) { const messageEvent = /** @type {!MessageEvent<{opened: boolean}>} */ (e); if (messageEvent.origin !== VIEWER_ORIGIN) { return; } - if (messageEvent.data.opened) { popup.postMessage({lhresults: json}, VIEWER_ORIGIN); - window.removeEventListener('message', msgHandler); } + onMessageCallback(messageEvent.data); }); - const popup = /** @type {!Window} */ (window.open(VIEWER_URL, '_blank')); + const popup = /** @type {!Window} */ (window.open(`${VIEWER_ORIGIN}${viewerPath}`, 'zblank')); } /** diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js index e1436d21b992..dafee0509262 100644 --- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js +++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js @@ -164,12 +164,30 @@ class LighthouseReportViewer { } catch (e) { throw new Error('Could not parse JSON file.'); } - this._reportIsFromGist = false; - this._replaceReportHtml(json); + + if (!json.lighthouseVersion.startsWith('3')) { + this._loadInLegacyViewerVersion(json); + } else { + this._replaceReportHtml(json); + } }).catch(err => logger.error(err.message)); } + /** + * Opens new tab with compatible report viewer version + * @param {!ReportRenderer.ReportJSON} reportJson + * @private + */ + _loadInLegacyViewerVersion(json) { + const features = new ViewerUIFeatures(new DOM(document)); + const viewerPath = '/lighthouse/viewer2x/'; + function onMessage(data) { + if (data.rendered) window.close(); + } + features.sendJsonReport(json, viewerPath, onMessage); + } + /** * Reads a file and returns its content as a string. * @param {!File} file @@ -296,6 +314,10 @@ class LighthouseReportViewer { if (e.source === self.opener && e.data.lhresults) { this._reportIsFromGist = false; this._replaceReportHtml(e.data.lhresults); + + if (self.opener && !self.opener.closed) { + self.opener.postMessage({rendered: true}, '*'); + } if (window.ga) { window.ga('send', 'event', 'report', 'open in viewer'); } diff --git a/lighthouse-viewer/app/src/viewer-ui-features.js b/lighthouse-viewer/app/src/viewer-ui-features.js index 8d880b157d2a..e213bf358d32 100644 --- a/lighthouse-viewer/app/src/viewer-ui-features.js +++ b/lighthouse-viewer/app/src/viewer-ui-features.js @@ -46,13 +46,6 @@ class ViewerUIFeatures extends ReportUIFeatures { return ReportGenerator.generateReportHtml(this.json); } - /** - * @override - */ - sendJsonReport() { - throw new Error('Cannot send JSON to Viewer from Viewer.'); - } - /** * @override */ From f98f218f1a829c9a0f23ef7ce8d1c68467af7552 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Mon, 14 May 2018 10:46:24 -0700 Subject: [PATCH 2/8] always consider loading in legacy viewer, regardless of input. --- .../app/src/lighthouse-report-viewer.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js index dafee0509262..ee26858cce4f 100644 --- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js +++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js @@ -113,6 +113,11 @@ class LighthouseReportViewer { _replaceReportHtml(json) { this._validateReportJson(json); + if (!json.lighthouseVersion.startsWith('3')) { + this._loadInLegacyViewerVersion(json); + return; + } + const dom = new DOM(document); const renderer = new ReportRenderer(dom); @@ -165,12 +170,7 @@ class LighthouseReportViewer { throw new Error('Could not parse JSON file.'); } this._reportIsFromGist = false; - - if (!json.lighthouseVersion.startsWith('3')) { - this._loadInLegacyViewerVersion(json); - } else { - this._replaceReportHtml(json); - } + this._replaceReportHtml(json); }).catch(err => logger.error(err.message)); } From 6166fb5632db90d4b4adf1625ccd2f791b0f43eb Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Mon, 14 May 2018 10:53:51 -0700 Subject: [PATCH 3/8] log warnings. --- lighthouse-viewer/app/src/lighthouse-report-viewer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js index ee26858cce4f..46edd1a37483 100644 --- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js +++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js @@ -180,12 +180,17 @@ class LighthouseReportViewer { * @private */ _loadInLegacyViewerVersion(json) { + const warnMsg = `Version mismatch between viewer and JSON. + Opening new tab with compatible viewer.`; const features = new ViewerUIFeatures(new DOM(document)); const viewerPath = '/lighthouse/viewer2x/'; + + logger.log(warnMsg, false); + features.sendJsonReport(json, viewerPath, onMessage); function onMessage(data) { if (data.rendered) window.close(); + logger.log(`${warnMsg} You can close this tab.`, false); } - features.sendJsonReport(json, viewerPath, onMessage); } /** From 4e8bd186d1c28c9c3ee93538909f67946391a4f9 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Mon, 14 May 2018 11:09:34 -0700 Subject: [PATCH 4/8] auto-popup keyed by version+url+fetchTime --- lighthouse-core/report/html/renderer/report-ui-features.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index bec5ce967a1a..cb5a2b488492 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -368,7 +368,10 @@ class ReportUIFeatures { onMessageCallback(messageEvent.data); }); - const popup = /** @type {!Window} */ (window.open(`${VIEWER_ORIGIN}${viewerPath}`, 'zblank')); + // The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly + const fetchTime = json.fetchTime || json.generatedTime; + const windowName = `${json.lighthouseVersion}-${json.initialUrl}-${fetchTime}`; + const popup = /** @type {!Window} */ (window.open(`${VIEWER_ORIGIN}${viewerPath}`, windowName)); } /** From 79446e3b002bd8f3f635846ccebcac50f04cfc82 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Mon, 14 May 2018 12:30:08 -0700 Subject: [PATCH 5/8] patrick feeedback. --- .../report/html/renderer/report-ui-features.js | 16 +++++++++++----- .../app/src/lighthouse-report-viewer.js | 11 ++++------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index cb5a2b488492..d9305e174882 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -321,7 +321,7 @@ class ReportUIFeatures { } case 'open-viewer': { const viewerPath = '/lighthouse/viewer/'; - this.sendJsonReport(this.json, viewerPath); + ReportUIFeatures.openTabAndSendJsonReport(this.json, viewerPath); break; } case 'save-gist': { @@ -351,27 +351,33 @@ class ReportUIFeatures { * @param {string} viewerPath * @protected */ - sendJsonReport(reportJson, viewerPath, onMessageCallback = function() { }) { + static openTabAndSendJsonReport(reportJson, viewerPath) { + let resolve; + const p = new Promise(res => resolve = res); // Chrome doesn't allow us to immediately postMessage to a popup right // after it's created. Normally, we could also listen for the popup window's // load event, however it is cross-domain and won't fire. Instead, listen // for a message from the target app saying "I'm open". const json = reportJson; window.addEventListener('message', function msgHandler(/** @type {!Event} */ e) { - const messageEvent = /** @type {!MessageEvent<{opened: boolean}>} */ (e); + const messageEvent = /** @type {!MessageEvent<{opened: boolean, rendered: boolean}>} */ (e); if (messageEvent.origin !== VIEWER_ORIGIN) { return; } if (messageEvent.data.opened) { popup.postMessage({lhresults: json}, VIEWER_ORIGIN); } - onMessageCallback(messageEvent.data); + if (messageEvent.data.rendered) { + resolve(popup); + } }); // The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly - const fetchTime = json.fetchTime || json.generatedTime; + const fetchTime = /** @type {!string} */ (json.fetchTime || json.generatedTime); const windowName = `${json.lighthouseVersion}-${json.initialUrl}-${fetchTime}`; const popup = /** @type {!Window} */ (window.open(`${VIEWER_ORIGIN}${viewerPath}`, windowName)); + + return p; } /** diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js index 46edd1a37483..a799da19ffce 100644 --- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js +++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js @@ -179,18 +179,15 @@ class LighthouseReportViewer { * @param {!ReportRenderer.ReportJSON} reportJson * @private */ - _loadInLegacyViewerVersion(json) { + async _loadInLegacyViewerVersion(json) { const warnMsg = `Version mismatch between viewer and JSON. Opening new tab with compatible viewer.`; - const features = new ViewerUIFeatures(new DOM(document)); const viewerPath = '/lighthouse/viewer2x/'; logger.log(warnMsg, false); - features.sendJsonReport(json, viewerPath, onMessage); - function onMessage(data) { - if (data.rendered) window.close(); - logger.log(`${warnMsg} You can close this tab.`, false); - } + await ViewerUIFeatures.openTabAndSendJsonReport(json, viewerPath); + window.close(); + logger.log(`${warnMsg} You can close this tab.`, false); } /** From 5cf1d57d03847e9d43c683127e5ddb37e4fbc4eb Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 15 May 2018 13:13:55 -0700 Subject: [PATCH 6/8] can't do async/await in viewer because reasons. --- lighthouse-viewer/app/src/lighthouse-report-viewer.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js index a799da19ffce..5a63ec9b4808 100644 --- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js +++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js @@ -179,15 +179,16 @@ class LighthouseReportViewer { * @param {!ReportRenderer.ReportJSON} reportJson * @private */ - async _loadInLegacyViewerVersion(json) { + _loadInLegacyViewerVersion(json) { const warnMsg = `Version mismatch between viewer and JSON. Opening new tab with compatible viewer.`; const viewerPath = '/lighthouse/viewer2x/'; logger.log(warnMsg, false); - await ViewerUIFeatures.openTabAndSendJsonReport(json, viewerPath); - window.close(); - logger.log(`${warnMsg} You can close this tab.`, false); + ViewerUIFeatures.openTabAndSendJsonReport(json, viewerPath).then(_ => { + window.close(); + logger.log(`${warnMsg} You can close this tab.`, false); + }); } /** From 9f1762e083ece38c124d30dd08c6121d0090a7e7 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 15 May 2018 13:14:26 -0700 Subject: [PATCH 7/8] reintroduce removeEvtListener('message') --- lighthouse-core/report/html/renderer/report-ui-features.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index d9305e174882..a947f0399746 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -364,10 +364,12 @@ class ReportUIFeatures { if (messageEvent.origin !== VIEWER_ORIGIN) { return; } + // Most recent deployment if (messageEvent.data.opened) { popup.postMessage({lhresults: json}, VIEWER_ORIGIN); } if (messageEvent.data.rendered) { + window.removeEventListener('message', msgHandler); resolve(popup); } }); From b50639dce13d35b89d9e90d23dacbf54a1b1cbc3 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 15 May 2018 17:29:12 -0700 Subject: [PATCH 8/8] closure --- lighthouse-core/report/html/renderer/report-ui-features.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index a947f0399746..14ffbd3355bf 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -349,6 +349,7 @@ class ReportUIFeatures { * to the online viewer using postMessage. * @param {!ReportRenderer.ReportJSON} reportJson * @param {string} viewerPath + * @suppress {reportUnknownTypes} * @protected */ static openTabAndSendJsonReport(reportJson, viewerPath) { @@ -375,8 +376,8 @@ class ReportUIFeatures { }); // The popup's window.name is keyed by version+url+fetchTime, so we reuse/select tabs correctly - const fetchTime = /** @type {!string} */ (json.fetchTime || json.generatedTime); - const windowName = `${json.lighthouseVersion}-${json.initialUrl}-${fetchTime}`; + const fetchTime = json.fetchTime || json.generatedTime; + const windowName = `${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`; const popup = /** @type {!Window} */ (window.open(`${VIEWER_ORIGIN}${viewerPath}`, windowName)); return p;