chrome-devtools-frontend
Version:
Chrome DevTools UI
114 lines (97 loc) • 4.81 kB
text/typescript
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as i18n from '../../../core/i18n/i18n.js';
import * as ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';
import * as Extras from '../extras/extras.js';
import * as Handlers from '../handlers/handlers.js';
import * as Helpers from '../helpers/helpers.js';
import type * as Types from '../types/types.js';
import {
InsightCategory,
type InsightModel,
type InsightSetContext,
type PartialInsightModel,
type RequiredData
} from './types.js';
export const UIStrings = {
/** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as "third-party code"). */
title: 'Third parties',
/**
* @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.
* This is displayed after a user expands the section to see more. No character length limits.
*/
description: 'Third party code can significantly impact load performance. ' +
'[Reduce and defer loading of third party code](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/) to prioritize your page\'s content.',
/** Label for a table column that displays the name of a third-party provider. */
columnThirdParty: 'Third party',
/** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */
columnTransferSize: 'Transfer size',
/** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */
columnMainThreadTime: 'Main thread time',
/**
* @description Text block indicating that no third party content was detected on the page
*/
noThirdParties: 'No third parties found',
};
const str_ = i18n.i18n.registerUIStrings('models/trace/insights/ThirdParties.ts', UIStrings);
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export function deps(): ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'] {
return ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'];
}
export type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, {
eventsByEntity: Map<Extras.ThirdParties.Entity, Types.Events.Event[]>,
summaryByEntity: Map<Extras.ThirdParties.Entity, Extras.ThirdParties.Summary>,
summaryByUrl: Map<string, Extras.ThirdParties.Summary>,
urlsByEntity: Map<Extras.ThirdParties.Entity, Set<string>>,
/** The entity for this navigation's URL. Any other entity is from a third party. */
firstPartyEntity?: Extras.ThirdParties.Entity,
}>;
function getRelatedEvents(
summaries: Extras.ThirdParties.ThirdPartySummary,
firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] {
const relatedEvents = [];
for (const [entity, events] of summaries.eventsByEntity.entries()) {
if (entity !== firstPartyEntity) {
relatedEvents.push(...events);
}
}
return relatedEvents;
}
function finalize(partialModel: PartialInsightModel<ThirdPartiesInsightModel>): ThirdPartiesInsightModel {
return {
strings: UIStrings,
title: i18nString(UIStrings.title),
description: i18nString(UIStrings.description),
category: InsightCategory.ALL,
state: [...partialModel.summaryByEntity.entries()].find(kv => kv[0] !== partialModel.firstPartyEntity) ?
'informative' :
'pass',
...partialModel,
};
}
export function generateInsight(
parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ThirdPartiesInsightModel {
const networkRequests = parsedTrace.NetworkRequests.byTime.filter(event => {
if (!context.navigation) {
return false;
}
if (event.args.data.frame !== context.frameId) {
return false;
}
return Helpers.Timing.eventIsInBounds(event, context.bounds);
});
const thirdPartySummary = Extras.ThirdParties.summarizeThirdParties(
parsedTrace as Handlers.Types.ParsedTrace, context.bounds, networkRequests);
const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;
const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||
Handlers.Helpers.makeUpEntity(thirdPartySummary.madeUpEntityCache, firstPartyUrl);
return finalize({
relatedEvents: getRelatedEvents(thirdPartySummary, firstPartyEntity),
eventsByEntity: thirdPartySummary.eventsByEntity,
summaryByEntity: thirdPartySummary.byEntity,
summaryByUrl: thirdPartySummary.byUrl,
urlsByEntity: thirdPartySummary.urlsByEntity,
firstPartyEntity,
});
}