Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(lightwallet): add resource-summary audit #8522

Merged
merged 7 commits into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions lighthouse-core/audits/resource-summary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* @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';

const Audit = require('./audit.js');
const NetworkRecords = require('../computed/network-records.js');
const ComputedResourceSummary = require('../computed/resource-summary.js');
const i18n = require('../lib/i18n/i18n.js');
const MainResource = require('../computed/main-resource.js');

const UIStrings = {
/** Imperative title of a Lighthouse audit that tells the user to minimize the size and quantity of resources used to load the page. */
title: 'Keep request counts and transfer sizes small',
khempenius marked this conversation as resolved.
Show resolved Hide resolved
/** Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits. */
description: 'To set budgets for the quantity and size of page resources,' +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry if I already said this but are we gonna link this up to a doc? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was planning on doing that in a separate PR once we know where that lives.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also added it to #8331 in the lightwallet section

' add a budget.json file.',
/** [ICU Syntax] Label for an audit identifying the number of requests and kilobytes used to load the page. */
displayValue: `{requestCount, plural, =1 {1 request} other {# requests}}` +
` • { byteCount, number, bytes } KB`,
/** Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page. */
totalResourceType: 'Total',
khempenius marked this conversation as resolved.
Show resolved Hide resolved
/** Label for a row in a data table; entries will be the total number and byte size of all 'Document' resources loaded by a web page. */
documentResourceType: 'Document',
/** Label for a row in a data table; entries will be the total number and byte size of all 'Script' resources loaded by a web page. */
khempenius marked this conversation as resolved.
Show resolved Hide resolved
scriptResourceType: 'Script',
/** Label for a row in a data table; entries will be the total number and byte size of all 'Stylesheet' resources loaded by a web page. */
khempenius marked this conversation as resolved.
Show resolved Hide resolved
stylesheetResourceType: 'Stylesheet',
/** Label for a row in a data table; entries will be the total number and byte size of all 'Image' resources loaded by a web page */
khempenius marked this conversation as resolved.
Show resolved Hide resolved
imageResourceType: 'Image',
/** Label for a row in a data table; entries will be the total number and byte size of all 'Media' resources loaded by a web page */
khempenius marked this conversation as resolved.
Show resolved Hide resolved
mediaResourceType: 'Media',
/** Label for a row in a data table; entries will be the total number and byte size of all 'Font' resources loaded by a web page */
khempenius marked this conversation as resolved.
Show resolved Hide resolved
fontResourceType: 'Font',
/** Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page that don't fit into the categories of Document, Script, Stylesheet, Image, Media, & Font.*/
otherResourceType: 'Other',
/** Label for a row in a data table; entries will be the total number and byte size of all third-part resources loaded by a web page */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** Label for a row in a data table; entries will be the total number and byte size of all third-part resources loaded by a web page */
/** Label for a row in a data table; entries will be the total number and byte size of all third-party resources loaded by a web page. 'Third-party resources are items loaded from URLs that aren't controlled by the owner of the web page. */

thirdPartyResourceType: 'Third-party',
};

const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);

class ResourceSummary extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'resource-summary',
title: str_(UIStrings.title),
description: str_(UIStrings.description),
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
khempenius marked this conversation as resolved.
Show resolved Hide resolved
requiredArtifacts: ['devtoolsLogs'],
khempenius marked this conversation as resolved.
Show resolved Hide resolved
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
const mainResource = await (MainResource.request({devtoolsLog, URL: artifacts.URL}, context));
khempenius marked this conversation as resolved.
Show resolved Hide resolved
const resourceSummary = ComputedResourceSummary.summarize(networkRecords, mainResource.url);

/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
{key: 'label', itemType: 'text', text: 'Resource Type'},
{key: 'count', itemType: 'numeric', text: 'Requests'},
khempenius marked this conversation as resolved.
Show resolved Hide resolved
{key: 'size', itemType: 'bytes', text: 'Transfer Size'},
];


/** @type {Record<LH.Budget.ResourceType,string>} */
const strMappings = {
khempenius marked this conversation as resolved.
Show resolved Hide resolved
'total': str_(UIStrings.totalResourceType),
'document': str_(UIStrings.documentResourceType),
'script': str_(UIStrings.scriptResourceType),
'stylesheet': str_(UIStrings.stylesheetResourceType),
'image': str_(UIStrings.imageResourceType),
'media': str_(UIStrings.mediaResourceType),
'font': str_(UIStrings.fontResourceType),
'other': str_(UIStrings.otherResourceType),
'third-party': str_(UIStrings.thirdPartyResourceType),
};

const types = /** @type {Array<LH.Budget.ResourceType>} */ (Object.keys(resourceSummary));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we rename resourceTypes and still fit on the line?


const tableContents = types.map((type) => {
khempenius marked this conversation as resolved.
Show resolved Hide resolved
return {
// ResourceType is included as an "id". It does not appear directly in the table.
khempenius marked this conversation as resolved.
Show resolved Hide resolved
resourceType: type,
label: strMappings[type],
count: resourceSummary[type].count,
size: resourceSummary[type].size,
};
}).sort((a, b) => {
return b.size - a.size;
khempenius marked this conversation as resolved.
Show resolved Hide resolved
});

const tableDetails = Audit.makeTableDetails(headings, tableContents);

return {
details: tableDetails,
score: 1,
displayValue: str_(UIStrings.displayValue, {
requestCount: resourceSummary.total.count,
byteCount: resourceSummary.total.size,
}),
};
}
}

module.exports = ResourceSummary;
module.exports.UIStrings = UIStrings;
2 changes: 2 additions & 0 deletions lighthouse-core/config/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ const defaultConfig = {
'main-thread-tasks',
'metrics',
'offline-start-url',
'resource-summary',
'manual/pwa-cross-browser',
'manual/pwa-page-transitions',
'manual/pwa-each-page-has-url',
Expand Down Expand Up @@ -378,6 +379,7 @@ const defaultConfig = {
{id: 'bootup-time', weight: 0, group: 'diagnostics'},
{id: 'mainthread-work-breakdown', weight: 0, group: 'diagnostics'},
{id: 'font-display', weight: 0, group: 'diagnostics'},
{id: 'resource-summary', weight: 0, group: 'diagnostics'},
// Audits past this point don't belong to a group and will not be shown automatically
{id: 'network-requests', weight: 0},
{id: 'network-rtt', weight: 0},
Expand Down
48 changes: 48 additions & 0 deletions lighthouse-core/lib/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,54 @@
"message": "Avoid multiple page redirects",
"description": "Imperative title of a Lighthouse audit that tells the user to eliminate the redirects taken through multiple URLs to load the page. This is shown in a list of audits that Lighthouse generates."
},
"lighthouse-core/audits/resource-summary.js | description": {
"message": "To set budgets for the quantity and size of page resources, add a budget.json file.",
"description": "Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits."
},
"lighthouse-core/audits/resource-summary.js | displayValue": {
"message": "{requestCount, plural, =1 {1 request} other {# requests}} • { byteCount, number, bytes } KB",
"description": "[ICU Syntax] Label for an audit identifying the number of requests and kilobytes used to load the page."
},
"lighthouse-core/audits/resource-summary.js | documentResourceType": {
"message": "Document",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Document' resources loaded by a web page."
},
"lighthouse-core/audits/resource-summary.js | fontResourceType": {
"message": "Font",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Font' resources loaded by a web page"
},
"lighthouse-core/audits/resource-summary.js | imageResourceType": {
"message": "Image",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Image' resources loaded by a web page"
},
"lighthouse-core/audits/resource-summary.js | mediaResourceType": {
"message": "Media",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Media' resources loaded by a web page"
},
"lighthouse-core/audits/resource-summary.js | otherResourceType": {
"message": "Other",
"description": "Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page that don't fit into the categories of Document, Script, Stylesheet, Image, Media, & Font."
},
"lighthouse-core/audits/resource-summary.js | scriptResourceType": {
"message": "Script",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Script' resources loaded by a web page."
},
"lighthouse-core/audits/resource-summary.js | stylesheetResourceType": {
"message": "Stylesheet",
"description": "Label for a row in a data table; entries will be the total number and byte size of all 'Stylesheet' resources loaded by a web page."
},
"lighthouse-core/audits/resource-summary.js | thirdPartyResourceType": {
"message": "Third-party",
"description": "Label for a row in a data table; entries will be the total number and byte size of all third-part resources loaded by a web page"
},
"lighthouse-core/audits/resource-summary.js | title": {
"message": "Keep request counts and transfer sizes small",
"description": "Imperative title of a Lighthouse audit that tells the user to minimize the size and quantity of resources used to load the page."
},
"lighthouse-core/audits/resource-summary.js | totalResourceType": {
"message": "Total",
"description": "Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page."
},
"lighthouse-core/audits/seo/canonical.js | description": {
"message": "Canonical links suggest which URL to show in search results. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/canonical).",
"description": "Description of a Lighthouse audit that tells the user *why* they need to have a valid rel=canonical link. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation."
Expand Down
6 changes: 6 additions & 0 deletions lighthouse-core/report/html/report-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@
display: none;
}

.lh-audit--informative .lh-audit__score-icon {
khempenius marked this conversation as resolved.
Show resolved Hide resolved
border: none;
border-radius: 100%;
background: var(--color-black-400);
}

.lh-audit__description,
.lh-audit__stackpack {
color: var(--secondary-text-color);
Expand Down
70 changes: 70 additions & 0 deletions lighthouse-core/test/audits/resource-summary-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @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';

const ResourceSummaryAudit = require('../../audits/resource-summary.js');
const assert = require('assert');
const networkRecordsToDevtoolsLog = require('../network-records-to-devtools-log.js');
khempenius marked this conversation as resolved.
Show resolved Hide resolved

/* eslint-env jest */

describe('Performance: Resource summary audit', () => {
let artifacts;
let context;
beforeEach(() => {
context = {computedCache: new Map()};

artifacts = {
devtoolsLogs: {
defaultPass: networkRecordsToDevtoolsLog([
{url: 'http://example.com/file.html', resourceType: 'Document', transferSize: 30},
{url: 'http://example.com/app.js', resourceType: 'Script', transferSize: 10},
{url: 'http://third-party.com/script.js', resourceType: 'Script', transferSize: 50},
{url: 'http://third-party.com/file.jpg', resourceType: 'Image', transferSize: 70},
])},
URL: {requestedUrl: 'https://example.com', finalUrl: 'https://example.com'},
};
});

khempenius marked this conversation as resolved.
Show resolved Hide resolved
it('has three table columns', () => {
return ResourceSummaryAudit.audit(artifacts, context).then(result => {
khempenius marked this conversation as resolved.
Show resolved Hide resolved
assert.equal(result.details.headings.length, 3);
});
});

it('includes the correct properties for each table item', () => {
return ResourceSummaryAudit.audit(artifacts, context).then(result => {
const item = result.details.items[0];
assert.equal(item.resourceType, 'total');
assert.ok(item.label);
khempenius marked this conversation as resolved.
Show resolved Hide resolved
assert.equal(item.count, 4);
assert.equal(item.size, 160);
});
});

it('includes all resource types, regardless of whether page contains them', () => {
return ResourceSummaryAudit.audit(artifacts, context).then(result => {
assert.equal(Object.keys(result.details.items).length, 9);
});
});

it('it displays "0" if there are no resources of that type', () => {
return ResourceSummaryAudit.audit(artifacts, context).then(result => {
const fontItem = result.details.items.find(item => item.resourceType === 'font');
assert.equal(fontItem.count, 0);
assert.equal(fontItem.size, 0);
});
});

it('it sorts items by size (descending)', () => {
return ResourceSummaryAudit.audit(artifacts, context).then(result => {
const items = result.details.items;
assert.ok(items[0].size >= items[1].size);
assert.ok(items[1].size >= items[2].size);
assert.ok(items[2].size >= items[3].size);
});
});
});
Loading