UNPKG

chrome-devtools-frontend

Version:
131 lines (113 loc) 5.28 kB
// Copyright 2024 The Chromium Authors // 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 type * as Types from '../types/types.js'; import { InsightCategory, InsightKeys, type InsightModel, type InsightSetContext, type PartialInsightModel, } 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: '3rd 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: '3rd party code can significantly impact load performance. ' + '[Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page\'s content.', /** Label for a table column that displays the name of a third-party provider. */ columnThirdParty: '3rd 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', } as const; const str_ = i18n.i18n.registerUIStrings('models/trace/insights/ThirdParties.ts', UIStrings); export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, { /** The entity for this navigation's URL. Any other entity is from a third party. */ entitySummaries: Extras.ThirdParties.EntitySummary[], firstPartyEntity?: Extras.ThirdParties.Entity, }>; function getRelatedEvents( summaries: Extras.ThirdParties.EntitySummary[], firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] { const relatedEvents = []; for (const summary of summaries) { if (summary.entity !== firstPartyEntity) { relatedEvents.push(...summary.relatedEvents); } } return relatedEvents; } function finalize(partialModel: PartialInsightModel<ThirdPartiesInsightModel>): ThirdPartiesInsightModel { return { insightKey: InsightKeys.THIRD_PARTIES, strings: UIStrings, title: i18nString(UIStrings.title), description: i18nString(UIStrings.description), docs: 'https://developer.chrome.com/docs/performance/insights/third-parties', category: InsightCategory.ALL, state: partialModel.entitySummaries.find(summary => summary.entity !== partialModel.firstPartyEntity) ? 'informative' : 'pass', ...partialModel, }; } export function isThirdPartyInsight(model: InsightModel): model is ThirdPartiesInsightModel { return model.insightKey === InsightKeys.THIRD_PARTIES; } export function generateInsight( data: Handlers.Types.HandlerData, context: InsightSetContext): ThirdPartiesInsightModel { const entitySummaries = Extras.ThirdParties.summarizeByThirdParty(data as Handlers.Types.HandlerData, context.bounds); const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data.Meta.mainFrameURL; const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) || Handlers.Helpers.makeUpEntity(data.Renderer.entityMappings.createdEntityCache, firstPartyUrl); return finalize({ relatedEvents: getRelatedEvents(entitySummaries, firstPartyEntity), firstPartyEntity, entitySummaries, }); } export function createOverlaysForSummary(summary: Extras.ThirdParties.EntitySummary): Types.Overlays.Overlay[] { const overlays = []; for (const event of summary.relatedEvents) { // The events found for a third party can be vast, as they gather every // single main thread task along with everything else on the page. If the // main thread is busy with large icicles, we can easily create tens of // thousands of overlays. Therefore, only create overlays for events of at least 1ms. if (event.dur === undefined || event.dur < 1_000) { continue; } const overlay: Types.Overlays.Overlay = { type: 'ENTRY_OUTLINE', entry: event, outlineReason: 'INFO', }; overlays.push(overlay); } return overlays; } export function createOverlays(model: ThirdPartiesInsightModel): Types.Overlays.Overlay[] { const overlays: Types.Overlays.Overlay[] = []; const summaries = model.entitySummaries ?? []; for (const summary of summaries) { if (summary.entity === model.firstPartyEntity) { continue; } const summaryOverlays = createOverlaysForSummary(summary); overlays.push(...summaryOverlays); } return overlays; }