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: add hidden audits for each insight #16312

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
22b7291
wip add viewport-insight
connorjclark Jan 22, 2025
8ba0676
license
connorjclark Jan 22, 2025
f32b4e5
resolve trace engine result nodes in TraceElements
connorjclark Jan 29, 2025
9369fb6
update
connorjclark Jan 29, 2025
63efe6a
rendering
connorjclark Jan 29, 2025
46e62aa
dom-size
connorjclark Jan 30, 2025
ae78390
update package, got all the strings now
connorjclark Feb 4, 2025
8f474ba
generate skeletons
connorjclark Feb 4, 2025
c280ae5
lints
connorjclark Feb 4, 2025
59fa89d
update sample json
connorjclark Feb 4, 2025
e3a2608
mv
connorjclark Feb 4, 2025
af806a1
oops
connorjclark Feb 4, 2025
f9afe92
recursiveObjectEnumerate for node ids
connorjclark Feb 4, 2025
98896d1
prevent cycle
connorjclark Feb 4, 2025
91cf402
fix
connorjclark Feb 4, 2025
b4f51d4
snaps
connorjclark Feb 5, 2025
49b7a07
hide
connorjclark Feb 5, 2025
86ab3dc
navid
connorjclark Feb 5, 2025
d7b3f97
dom-size-insghts
connorjclark Feb 5, 2025
12f9669
Merge remote-tracking branch 'origin/main' into insight-audit
connorjclark Feb 5, 2025
a826ce5
fix tests, merge
connorjclark Feb 5, 2025
8b518f4
fix insight set resolver
connorjclark Feb 5, 2025
0e299f1
fix getAuditList
connorjclark Feb 5, 2025
a4d240c
graceful failure
connorjclark Feb 5, 2025
52cbf14
oops
connorjclark Feb 5, 2025
eafd228
maybe fix smoke
connorjclark Feb 5, 2025
d011c22
e2e
connorjclark Feb 5, 2025
058e947
update trace engine
connorjclark Feb 5, 2025
1b7a488
guidance
connorjclark Feb 5, 2025
b7d2e3f
render-blocking-insight
connorjclark Feb 6, 2025
adb1f1e
NOT_APPLICABLE
connorjclark Feb 6, 2025
0bf466e
handle empty tables
connorjclark Feb 6, 2025
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ jobs:
- run: yarn test-legacy-javascript
- run: yarn i18n:checks
- run: yarn dogfood-lhci
- run: yarn generate-insight-audits
adamraine marked this conversation as resolved.
Show resolved Hide resolved

# Fail if any changes were written to any source files or generated untracked files (ex, from: build/build-cdt-lib.js).
- run: git add -A && git diff --cached --exit-code
Expand Down
2 changes: 1 addition & 1 deletion build/build-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function buildStandaloneReport() {
outfile: 'dist/report/standalone.js',
format: 'iife',
bundle: true,
minify: true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

drive by. this is very useful. surprised we didn't already do this.

minify: !process.env.DEBUG,
});
}

Expand Down
6 changes: 6 additions & 0 deletions cli/test/smokehouse/test-definitions/perf-trace-elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ const expectations = {
},
artifacts: {
TraceElements: [
{traceEventType: 'trace-engine'},
{traceEventType: 'trace-engine'},
{traceEventType: 'trace-engine'},
{traceEventType: 'trace-engine'},
{traceEventType: 'trace-engine'},
{traceEventType: 'trace-engine', _minChromiumVersion: '135'},
{
traceEventType: 'largest-contentful-paint',
node: {
Expand Down
3 changes: 3 additions & 0 deletions core/audits/insights/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Insight audits

When adding new insight audits, you can start off by just running `yarn generate-insight-audits`
52 changes: 52 additions & 0 deletions core/audits/insights/cls-culprits-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable no-unused-vars */ // TODO: remove once implemented.

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/CLSCulprits.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js', UIStrings);

class CLSCulpritsInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'cls-culprits-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
// TODO: implement.
return adaptInsightToAuditProduct(artifacts, context, 'CLSCulprits', (insight) => {
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default CLSCulpritsInsight;
54 changes: 54 additions & 0 deletions core/audits/insights/document-latency-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/DocumentLatency.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js', UIStrings);

class DocumentLatencyInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'document-latency-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
// TODO: implement.
return adaptInsightToAuditProduct(artifacts, context, 'DocumentLatency', (insight) => {
if (!insight.data) {
return;
}

/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default DocumentLatencyInsight;
84 changes: 84 additions & 0 deletions core/audits/insights/dom-size-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/DOMSize.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DOMSize.js', UIStrings);

class DOMSizeInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'dom-size-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
return adaptInsightToAuditProduct(artifacts, context, 'DOMSize', (insight) => {
if (!insight.maxDOMStats?.args.data.maxChildren || !insight.maxDOMStats?.args.data.maxDepth) {
Copy link
Member

Choose a reason for hiding this comment

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

Technically we will still have a valid totalElements value even if these are missing. In practice though, this will only happen if the document element is removed so it's an edge case that really doesn't matter.

return;
}

const {totalElements, maxChildren, maxDepth} = insight.maxDOMStats.args.data;

/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
{key: 'statistic', valueType: 'text', label: str_(UIStrings.statistic)},
{key: 'node', valueType: 'node', label: str_(UIStrings.element)},
{key: 'value', valueType: 'numeric', label: str_(UIStrings.value)},
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
{
connorjclark marked this conversation as resolved.
Show resolved Hide resolved
statistic: str_(UIStrings.totalElements),
value: {
type: 'numeric',
granularity: 1,
value: totalElements,
},
},
{
statistic: str_(UIStrings.maxChildren),
node: makeNodeItemForNodeId(artifacts.TraceElements, maxChildren.nodeId),
value: {
type: 'numeric',
granularity: 1,
value: maxChildren.numChildren,
},
},
{
statistic: str_(UIStrings.maxDOMDepth),
node: makeNodeItemForNodeId(artifacts.TraceElements, maxDepth.nodeId),
value: {
type: 'numeric',
granularity: 1,
value: maxDepth.depth,
},
},
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default DOMSizeInsight;
52 changes: 52 additions & 0 deletions core/audits/insights/font-display-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable no-unused-vars */ // TODO: remove once implemented.

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/FontDisplay.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js', UIStrings);

class FontDisplayInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'font-display-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
// TODO: implement.
return adaptInsightToAuditProduct(artifacts, context, 'FontDisplay', (insight) => {
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default FontDisplayInsight;
52 changes: 52 additions & 0 deletions core/audits/insights/forced-reflow-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable no-unused-vars */ // TODO: remove once implemented.

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ForcedReflow.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js', UIStrings);

class ForcedReflowInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'forced-reflow-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
// TODO: implement.
return adaptInsightToAuditProduct(artifacts, context, 'ForcedReflow', (insight) => {
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default ForcedReflowInsight;
52 changes: 52 additions & 0 deletions core/audits/insights/image-delivery-insight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable no-unused-vars */ // TODO: remove once implemented.

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ImageDelivery.js';

import {Audit} from '../audit.js';
import * as i18n from '../../lib/i18n/i18n.js';
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';

// eslint-disable-next-line max-len
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ImageDelivery.js', UIStrings);

class ImageDeliveryInsight extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'image-delivery-insight',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.title),
description: str_(UIStrings.description),
guidanceLevel: 3,
requiredArtifacts: ['traces', 'TraceElements'],
};
}

/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
// TODO: implement.
return adaptInsightToAuditProduct(artifacts, context, 'ImageDelivery', (insight) => {
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
];
/** @type {LH.Audit.Details.Table['items']} */
const items = [
];
return Audit.makeTableDetails(headings, items);
});
}
}

export default ImageDeliveryInsight;
Loading
Loading