lighthouse
Version:
Automated auditing, performance metrics, and best practices for the web.
369 lines (334 loc) • 11.1 kB
TypeScript
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {IcuMessage} from './i18n.js';
import Treemap from './treemap.js';
/** Common properties for all details types. */
interface BaseDetails {
/** Additional information, usually used for including debug or meta information in the LHR */
debugData?: Details.DebugData;
}
type Details =
Details.CriticalRequestChain |
Details.NetworkTree |
Details.DebugData |
Details.TreemapData |
Details.Filmstrip |
Details.List |
Details.Opportunity |
Details.Screenshot |
Details.Checklist |
Details.Table;
// Details namespace.
declare module Details {
type NetworkNode = {
[id: string]: {
url: string;
/** In ms */
navStartToEndTime: number;
transferSize: number;
isLongest?: boolean;
children?: NetworkNode;
}
};
/**
* This detail type is introduced to address the differences in how the RPP network tree is displayed vs the old Lighthouse CRC audit:
* - The CRC audit will show individual request durations but the new NDT insight will show the entire chain duration
* - The CRC audit will only show any timing/size for leaf node requests, but the NDT insight will show this info for all requests
* - The CRC audit contains extra request timing info like `responseReceivedTime` but we don't need this for the NDT insight.
* The NDT insight has enough information to fill in this extra data, but we shouldn't add calculations just to fill in the CRC detail type.
*/
interface NetworkTree extends BaseDetails {
type: 'network-tree';
longestChain: {
/** In ms */
duration: number;
};
chains: NetworkNode;
}
interface CriticalRequestChain extends BaseDetails {
type: 'criticalrequestchain';
longestChain: {
/** In ms */
duration: number;
length: number;
transferSize: number;
};
chains: SimpleCriticalRequestNode;
}
type SimpleCriticalRequestNode = {
[id: string]: {
request: {
url: string;
/** In seconds */
startTime: number;
/** In seconds */
endTime: number;
/** In seconds */
responseReceivedTime: number;
transferSize: number;
};
children?: SimpleCriticalRequestNode;
}
}
interface Filmstrip extends BaseDetails {
type: 'filmstrip';
scale: number;
items: {
/** The relative time from navigationStart to this frame, in milliseconds. */
timing: number;
/** The raw timestamp of this frame, in microseconds. */
timestamp: number;
/** The data URL encoding of this frame. */
data: string;
}[];
}
// NOTE: any `Details` type *should* be usable in `items`, but check
// styles/report-ui-features are good before adding.
type ListableDetail = Table | Checklist | NetworkTree | NodeValue | TextValue | DebugData;
interface ListSectionItem {
type: 'list-section';
title?: IcuMessage | string;
description?: IcuMessage | string;
value: ListableDetail;
}
interface List extends BaseDetails {
type: 'list';
items: Array<ListSectionItem | ListableDetail>;
}
interface Opportunity extends BaseDetails {
type: 'opportunity';
headings: TableColumnHeading[];
items: OpportunityItem[];
/**
* Columns to sort the items by, during grouping.
* If omitted, entity groups will be sorted by the audit ordering vs. the new totals.
*/
sortedBy?: Array<string>;
/** Will be true if the table is already grouped by entities. */
isEntityGrouped?: boolean;
/** Column keys to skip summing. If omitted, all column types supported are summed. */
skipSumming?: Array<string>;
/**
* @deprecated
* Historically this represents the time saved on the entire page load. It's mostly used as an
* alias for `metricSavings.LCP` now. We recommend using `metricSavings` directly for more
* metric-specific savings estimates.
*/
overallSavingsMs?: number;
/** Total byte savings covered by this audit. */
overallSavingsBytes?: number;
}
interface Screenshot extends BaseDetails {
type: 'screenshot';
timing: number;
timestamp: number;
data: string;
}
interface Rect {
width: number;
height: number;
top: number;
right: number;
bottom: number;
left: number;
}
interface Checklist extends BaseDetails {
type: 'checklist',
items: Record<string, {value: boolean, label: IcuMessage | string}>,
}
interface Table extends BaseDetails {
type: 'table';
headings: TableColumnHeading[];
items: TableItem[];
summary?: {
wastedMs?: number;
wastedBytes?: number;
};
/**
* Columns to sort the items by, during grouping.
* If omitted, entity groups will be sorted by the audit ordering vs. the new totals.
*/
sortedBy?: Array<string>;
/** Will be true if the table is already grouped by entities. */
isEntityGrouped?: boolean;
/** Column keys to skip summing. If omitted, all column types supported are summed. */
skipSumming?: Array<string>;
}
/** A table item for rows that are nested within a top-level TableItem (row). */
interface TableSubItems {
type: 'subitems';
items: TableItem[];
}
/**
* A details type that is not rendered in the final report; usually used
* for including debug information in the LHR. Can contain anything.
*/
interface DebugData {
type: 'debugdata';
[p: string]: any;
}
interface TreemapData extends BaseDetails {
type: 'treemap-data';
nodes: Treemap.Node[];
}
/** String enum of possible types of values found within table items. */
type ItemValueType = 'bytes' | 'code' | 'link' | 'ms' | 'multi' | 'node' | 'source-location' | 'numeric' | 'text' | 'thumbnail' | 'timespanMs' | 'url';
/** Possible types of values found within table items. */
type ItemValue = string | number | boolean | DebugData | NodeValue | SourceLocationValue | LinkValue | UrlValue | CodeValue | NumericValue | TextValue | IcuMessage | TableSubItems;
interface TableColumnHeading {
/**
* The name of the property within items being described.
* If null, subItemsHeading must be defined, and the first table row in this column for
* every item will be empty.
* See legacy-javascript for an example.
*/
key: string|null;
/** Readable text label of the field. */
label: IcuMessage | string;
/**
* The data format of the column of values being described. Usually
* those values will be primitives rendered as this type, but the values
* could also be objects with their own type to override this field.
*/
valueType: ItemValueType;
/**
* Optional - defines an inner table of values that correspond to this column.
* Key is required - if other properties are not provided, the value for the heading is used.
*/
subItemsHeading?: {key: string, valueType?: ItemValueType, displayUnit?: string, granularity?: number};
displayUnit?: string;
granularity?: number;
}
interface TableItem {
debugData?: DebugData;
subItems?: TableSubItems;
[p: string]: undefined | ItemValue;
}
/** A more specific table element used for `opportunity` tables. */
interface OpportunityItem extends TableItem {
url: string;
wastedBytes?: number;
totalBytes?: number;
wastedMs?: number;
debugData?: DebugData;
[p: string]: undefined | ItemValue;
}
/**
* A value used within a details object, intended to be displayed as code,
* regardless of the controlling heading's valueType.
*/
interface CodeValue {
type: 'code';
value: IcuMessage | string;
}
/**
* A value used within a details object, intended to be displayed as a
* link with text, regardless of the controlling heading's valueType.
* If URL is the empty string, fallsback to a basic `TextValue`.
*/
interface LinkValue {
type: 'link',
text: string;
url: string;
}
/**
* A value used within a details object, intended to be displayed an HTML
* node, regardless of the controlling heading's valueType.
*/
interface NodeValue {
type: 'node';
/** Unique identifier. */
lhId?: string;
path?: string;
selector?: string;
boundingRect?: Rect;
/** An HTML snippet used to identify the node. */
snippet?: string;
/** A human-friendly text descriptor that's used to identify the node more quickly. */
nodeLabel?: string;
/** A human-friendly explainer on how to approach the possible fix. */
explanation?: string;
}
/**
* A value used within a details object, intended to be displayed as a URL
* encoded with line and column info (url:line:column).
*/
interface SourceLocationValue {
type: 'source-location';
/** A "url" representing the source file. May not be a valid URL, see `urlProvider`. */
url: string;
/**
* - `network` when the url is the actual, observed resource url. This is always a valid URL.
* - `comment` when the url comes from a sourceURL comment. This could be anything, really.
*/
urlProvider: 'network' | 'comment';
/** Zero-indexed. */
line: number;
/** Zero-indexed. */
column: number;
/** The original file location from the source map. */
original?: {
/** The relevant file from the map's `sources` array. */
file: string;
line: number;
column: number;
};
functionName?: string;
}
/**
* A value used within a details object, intended to be displayed as a
* linkified URL, regardless of the controlling heading's valueType.
*/
interface UrlValue {
type: 'url';
value: string;
}
/**
* Snippet of text with line numbers and annotations.
*/
interface SnippetValue {
type: 'snippet',
title: string,
/** Node where the content of this snippet came from. */
node?: NodeValue,
/**
* The lines that should be rendered. For long snippets we only include important lines
* in the audit result.
*/
lines: {
content: string
/** Line number, starting from 1. */
lineNumber: number;
truncated?: boolean
}[],
/** The total number of lines in the snippet, equal to lines.length for short snippets. */
lineCount: number,
/** Messages that provide information about a specific lines. */
lineMessages: {
/** Line number, starting from 1. */
lineNumber: number,
message: string
}[];
/** Messages that provide information about the snippet in general. */
generalMessages: {
message: string
}[];
}
/**
* A value used within a details object, intended to be displayed as a ms timing
* or a numeric value based on the metric name.
*/
interface NumericValue {
type: 'numeric',
value: number,
granularity?: number,
}
interface TextValue {
type: 'text',
value: IcuMessage | string,
}
}
export default Details;