|
| 1 | +// Copyright 2025 The Chromium Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +import * as i18n from '../../../core/i18n/i18n.js'; |
| 6 | +import * as LegacyJavaScriptLib from '../../../third_party/legacy-javascript/legacy-javascript.js'; |
| 7 | +import type * as Handlers from '../handlers/handlers.js'; |
| 8 | +import * as Helpers from '../helpers/helpers.js'; |
| 9 | + |
| 10 | +import {estimateCompressionRatioForScript, metricSavingsForWastedBytes} from './Common.js'; |
| 11 | +import { |
| 12 | + InsightCategory, |
| 13 | + InsightKeys, |
| 14 | + type InsightModel, |
| 15 | + type InsightSetContext, |
| 16 | + type PartialInsightModel, |
| 17 | +} from './types.js'; |
| 18 | + |
| 19 | +const {detectLegacyJavaScript} = LegacyJavaScriptLib.LegacyJavaScript; |
| 20 | + |
| 21 | +export const UIStrings = { |
| 22 | + /** |
| 23 | + * @description Title of an insight that identifies polyfills for modern JavaScript features, and recommends their removal. |
| 24 | + */ |
| 25 | + title: 'Legacy JavaScript', |
| 26 | + /** |
| 27 | + * @description Description of an insight that identifies polyfills for modern JavaScript features, and recommends their removal. |
| 28 | + */ |
| 29 | + description: 'Legacy JavaScript', |
| 30 | +} as const; |
| 31 | + |
| 32 | +const str_ = i18n.i18n.registerUIStrings('models/trace/insights/LegacyJavaScript.ts', UIStrings); |
| 33 | +export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| 34 | + |
| 35 | +interface PatternMatchResult { |
| 36 | + name: string; |
| 37 | + line: number; |
| 38 | + column: number; |
| 39 | +} |
| 40 | + |
| 41 | +interface LegacyJavaScriptResult { |
| 42 | + matches: PatternMatchResult[]; |
| 43 | + estimatedByteSavings: number; |
| 44 | +} |
| 45 | + |
| 46 | +type LegacyJavaScriptResults = Map<Handlers.ModelHandlers.Scripts.Script, LegacyJavaScriptResult>; |
| 47 | + |
| 48 | +export type LegacyJavaScriptInsightModel = InsightModel<typeof UIStrings, { |
| 49 | + legacyJavaScriptResults: LegacyJavaScriptResults, |
| 50 | +}>; |
| 51 | + |
| 52 | +function finalize(partialModel: PartialInsightModel<LegacyJavaScriptInsightModel>): LegacyJavaScriptInsightModel { |
| 53 | + const requests = [...partialModel.legacyJavaScriptResults.keys()].map(script => script.request).filter(e => !!e); |
| 54 | + |
| 55 | + return { |
| 56 | + insightKey: InsightKeys.LEGACY_JAVASCRIPT, |
| 57 | + strings: UIStrings, |
| 58 | + title: i18nString(UIStrings.title), |
| 59 | + description: i18nString(UIStrings.description), |
| 60 | + category: InsightCategory.ALL, |
| 61 | + state: requests.length ? 'fail' : 'pass', |
| 62 | + relatedEvents: [...new Set(requests)], |
| 63 | + ...partialModel, |
| 64 | + }; |
| 65 | +} |
| 66 | + |
| 67 | +export function generateInsight( |
| 68 | + parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): LegacyJavaScriptInsightModel { |
| 69 | + const scripts = parsedTrace.Scripts.scripts.filter(script => { |
| 70 | + if (!context.navigation) { |
| 71 | + return false; |
| 72 | + } |
| 73 | + |
| 74 | + if (script.frame !== context.frameId) { |
| 75 | + return false; |
| 76 | + } |
| 77 | + |
| 78 | + if (script.url?.startsWith('chrome-extension://')) { |
| 79 | + return false; |
| 80 | + } |
| 81 | + |
| 82 | + return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts); |
| 83 | + }); |
| 84 | + |
| 85 | + const legacyJavaScriptResults: LegacyJavaScriptResults = new Map(); |
| 86 | + const wastedBytesByRequestId = new Map<string, number>(); |
| 87 | + |
| 88 | + for (const script of scripts) { |
| 89 | + if (!script.content) { |
| 90 | + continue; |
| 91 | + } |
| 92 | + |
| 93 | + const result = detectLegacyJavaScript(script.content, script.sourceMap); |
| 94 | + legacyJavaScriptResults.set(script, result); |
| 95 | + |
| 96 | + if (script.request) { |
| 97 | + const compressionRatio = estimateCompressionRatioForScript(script); |
| 98 | + const transferSize = Math.round(result.estimatedByteSavings * compressionRatio); |
| 99 | + const requestId = script.request.args.data.requestId; |
| 100 | + wastedBytesByRequestId.set(requestId, transferSize); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + return finalize({ |
| 105 | + legacyJavaScriptResults, |
| 106 | + metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context), |
| 107 | + }); |
| 108 | +} |
0 commit comments