Skip to content

Commit

Permalink
report(viewer): add option for loading from the PSI API (#9546)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark authored and brendankenny committed Aug 21, 2019
1 parent dc0295d commit 1f77b0b
Show file tree
Hide file tree
Showing 10 changed files with 377 additions and 88 deletions.
19 changes: 19 additions & 0 deletions lighthouse-viewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,22 @@ yarn deploy-viewer
```

For more information on deployment, see `releasing.md`.

## Gist

http://localhost:8000/?gist=bd1779783a5bbcb348564a58f80f7099

## PSI

Example:
```
http://localhost:8000/?psiurl=https://www.example.com&category=pwa&category=seo
```

Options:

`psiurl` - URL to audit
`category` - Category to enable. One per category.
`strategy` - mobile, desktop
`locale` - locale to render report with
`utm_source` - id that identifies the tool using the viewer
7 changes: 7 additions & 0 deletions lighthouse-viewer/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ <h1 class="viewer-placeholder__heading">Lighthouse Report Viewer</h1>
<script src="https://www.gstatic.com/firebasejs/4.1.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.2/firebase-auth.js"></script>
<script src="src/viewer.js"></script>
<script>
window.addEventListener('DOMContentLoaded', main);

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js');
}
</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
Expand Down
79 changes: 65 additions & 14 deletions lighthouse-viewer/app/src/lighthouse-report-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
*/
'use strict';

/* global DOM, ViewerUIFeatures, ReportRenderer, DragAndDrop, GithubApi, logger, idbKeyval */
/* global DOM, ViewerUIFeatures, ReportRenderer, DragAndDrop, GithubApi, PSIApi, logger, idbKeyval */

/** @typedef {import('./psi-api').PSIParams} PSIParams */

/**
* Guaranteed context.querySelector. Always returns an element or throws if
Expand Down Expand Up @@ -36,11 +38,13 @@ class LighthouseReportViewer {
this._dragAndDropper = new DragAndDrop(this._onFileLoad);
this._github = new GithubApi();

this._psi = new PSIApi();
/**
* Used for tracking whether to offer to upload as a gist.
* @type {boolean}
*/
this._reportIsFromGist = false;
this._reportIsFromPSI = false;

this._addEventListeners();
this._loadFromDeepLink();
Expand Down Expand Up @@ -93,15 +97,30 @@ class LighthouseReportViewer {
*/
_loadFromDeepLink() {
const params = new URLSearchParams(location.search);

const gistId = params.get('gist');
if (!gistId) {
return Promise.resolve();
const psiurl = params.get('psiurl');

if (!gistId && !psiurl) return Promise.resolve();

this._toggleLoadingBlur(true);
let loadPromise = Promise.resolve();
if (psiurl) {
loadPromise = this._fetchFromPSI({
url: psiurl,
category: params.has('category') ? params.getAll('category') : undefined,
strategy: params.get('strategy') || undefined,
locale: params.get('locale') || undefined,
utm_source: params.get('utm_source') || undefined,
});
} else if (gistId) {
loadPromise = this._github.getGistFileContentAsJson(gistId).then(reportJson => {
this._reportIsFromGist = true;
this._replaceReportHtml(reportJson);
}).catch(err => logger.error(err.message));
}

return this._github.getGistFileContentAsJson(gistId).then(reportJson => {
this._reportIsFromGist = true;
this._replaceReportHtml(reportJson);
}).catch(err => logger.error(err.message));
return loadPromise.finally(() => this._toggleLoadingBlur(false));
}

/**
Expand Down Expand Up @@ -158,11 +177,14 @@ class LighthouseReportViewer {
try {
renderer.renderReport(json, container);

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

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

Expand All @@ -173,6 +195,8 @@ class LighthouseReportViewer {
dom.resetTemplates(); // TODO(bckenny): hack
container.textContent = '';
throw e;
} finally {
this._reportIsFromGist = this._reportIsFromPSI = false;
}

// Remove the placeholder UI once the user has loaded a report.
Expand Down Expand Up @@ -202,7 +226,6 @@ class LighthouseReportViewer {
} catch (e) {
throw new Error('Could not parse JSON file.');
}
this._reportIsFromGist = false;
this._replaceReportHtml(json);
}).catch(err => logger.error(err.message));
}
Expand Down Expand Up @@ -263,7 +286,6 @@ class LighthouseReportViewer {
window.ga('send', 'event', 'report', 'created');
}

this._reportIsFromGist = true;
history.pushState({}, '', `${LighthouseReportViewer.APP_URL}?gist=${id}`);

return id;
Expand Down Expand Up @@ -294,14 +316,12 @@ class LighthouseReportViewer {
// Try paste as json content.
try {
const json = JSON.parse(e.clipboardData.getData('text'));
this._reportIsFromGist = false;
this._replaceReportHtml(json);

if (window.ga) {
window.ga('send', 'event', 'report', 'paste');
}
} catch (err) {
// noop
}
}

Expand Down Expand Up @@ -358,7 +378,6 @@ class LighthouseReportViewer {
_listenForMessages() {
window.addEventListener('message', e => {
if (e.source === self.opener && e.data.lhresults) {
this._reportIsFromGist = false;
this._replaceReportHtml(e.data.lhresults);

if (self.opener && !self.opener.closed) {
Expand All @@ -375,6 +394,38 @@ class LighthouseReportViewer {
self.opener.postMessage({opened: true}, '*');
}
}

/**
* @param {PSIParams} params
*/
_fetchFromPSI(params) {
logger.log('Waiting for Lighthouse results ...');
return this._psi.fetchPSI(params).then(response => {
logger.hide();

if (!response.lighthouseResult) {
if (response.error) {
// eslint-disable-next-line no-console
console.error(response.error);
logger.error(response.error.message);
} else {
logger.error('PSI did not return a Lighthouse Result');
}
return;
}

this._reportIsFromPSI = true;
this._replaceReportHtml(response.lighthouseResult);
});
}

/**
* @param {boolean} force
*/
_toggleLoadingBlur(force) {
const placeholder = document.querySelector('.viewer-placeholder-inner');
if (placeholder) placeholder.classList.toggle('lh-loading', force);
}
}

// node export for testing.
Expand Down
7 changes: 1 addition & 6 deletions lighthouse-viewer/app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

/* global LighthouseReportViewer, Logger */

// eslint-disable-next-line no-unused-vars
function main() {
const logEl = document.querySelector('#lh-log');
if (!logEl) {
Expand Down Expand Up @@ -47,9 +48,3 @@ function main() {

window.viewer = new LighthouseReportViewer();
}

main();

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js');
}
57 changes: 57 additions & 0 deletions lighthouse-viewer/app/src/psi-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license Copyright 2019 Google Inc. 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.
*/
'use strict';

/** @typedef {{lighthouseResult?: LH.Result, error?: {message: string}}} PSIResponse */

const PSI_URL = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed';
const PSI_KEY = 'AIzaSyAjcDRNN9CX9dCazhqI4lGR7yyQbkd_oYE';
const PSI_DEFAULT_CATEGORIES = [
'performance',
'accessibility',
'seo',
'best-practices',
'pwa',
];

/**
* @typedef PSIParams
* @property {string} url
* @property {string[]=} category
* @property {string=} locale
* @property {string=} strategy
* @property {string=} utm_source
*/

/**
* Wrapper around the PSI API for fetching LHR.
*/
class PSIApi {
/**
* @param {PSIParams} params
* @return {Promise<PSIResponse>}
*/
fetchPSI(params) {
const apiUrl = new URL(PSI_URL);
// eslint-disable-next-line prefer-const
for (let [name, value] of Object.entries(params)) {
if (Array.isArray(value)) continue;
if (name === 'strategy') value = value || 'mobile';
if (typeof value !== 'undefined') apiUrl.searchParams.append(name, value);
}
for (const singleCategory of (params.category || PSI_DEFAULT_CATEGORIES)) {
apiUrl.searchParams.append('category', singleCategory);
}
apiUrl.searchParams.append('key', PSI_KEY);
return fetch(apiUrl.href).then(res => res.json());
}
}

// node export for testing.
if (typeof module !== 'undefined' && module.exports) {
module.exports = PSIApi;
module.exports.PSI_DEFAULT_CATEGORIES = PSI_DEFAULT_CATEGORIES;
}
3 changes: 3 additions & 0 deletions lighthouse-viewer/app/styles/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
cursor: pointer;
background-color: #fff;
}
.viewer-placeholder-inner.lh-loading {
filter: blur(2px);
}
.viewer-placeholder-inner.dropping {
border-color: currentColor;
}
Expand Down
Loading

0 comments on commit 1f77b0b

Please sign in to comment.