@paulirish/trace_engine 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
- package/README.md +2 -2
- package/core/platform/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/core/platform/platform.prebundle.d.ts +18 -0
- package/core/platform/platform.prebundle.js +53 -0
- package/core/platform/platform.prebundle.js.map +1 -0
- package/core/platform/platform.prebundle.ts +71 -0
- package/generated/protocol.d.ts +51 -23
- package/locales/af.json +8 -8
- package/locales/am.json +8 -8
- package/locales/ar.json +8 -8
- package/locales/as.json +8 -8
- package/locales/az.json +8 -8
- package/locales/be.json +7 -7
- package/locales/bg.json +8 -8
- package/locales/bn.json +8 -8
- package/locales/bs.json +8 -8
- package/locales/ca.json +8 -8
- package/locales/cs.json +8 -8
- package/locales/cy.json +8 -8
- package/locales/da.json +8 -8
- package/locales/de.json +8 -8
- package/locales/el.json +8 -8
- package/locales/en-GB.json +8 -8
- package/locales/en-US.json +72 -51
- package/locales/en-XL.json +72 -51
- package/locales/es-419.json +8 -8
- package/locales/es.json +8 -8
- package/locales/et.json +8 -8
- package/locales/eu.json +8 -8
- package/locales/fa.json +11 -11
- package/locales/fi.json +8 -8
- package/locales/fil.json +8 -8
- package/locales/fr-CA.json +8 -8
- package/locales/fr.json +8 -8
- package/locales/gl.json +8 -8
- package/locales/gu.json +8 -8
- package/locales/he.json +8 -8
- package/locales/hi.json +8 -8
- package/locales/hr.json +8 -8
- package/locales/hu.json +8 -8
- package/locales/hy.json +8 -8
- package/locales/id.json +8 -8
- package/locales/is.json +8 -8
- package/locales/it.json +8 -8
- package/locales/ja.json +8 -8
- package/locales/ka.json +8 -8
- package/locales/kk.json +8 -8
- package/locales/km.json +8 -8
- package/locales/kn.json +7 -7
- package/locales/ko.json +8 -8
- package/locales/ky.json +7 -7
- package/locales/lo.json +8 -8
- package/locales/lt.json +8 -8
- package/locales/lv.json +8 -8
- package/locales/mk.json +8 -8
- package/locales/ml.json +8 -8
- package/locales/mn.json +8 -8
- package/locales/mr.json +7 -7
- package/locales/ms.json +7 -7
- package/locales/my.json +8 -8
- package/locales/ne.json +8 -8
- package/locales/nl.json +8 -8
- package/locales/no.json +8 -8
- package/locales/or.json +8 -8
- package/locales/pa.json +7 -7
- package/locales/pl.json +8 -8
- package/locales/pt-PT.json +8 -8
- package/locales/pt.json +8 -8
- package/locales/ro.json +8 -8
- package/locales/ru.json +8 -8
- package/locales/si.json +8 -8
- package/locales/sk.json +8 -8
- package/locales/sl.json +8 -8
- package/locales/sq.json +8 -8
- package/locales/sr-Latn.json +8 -8
- package/locales/sr.json +8 -8
- package/locales/sv.json +8 -8
- package/locales/sw.json +7 -7
- package/locales/ta.json +8 -8
- package/locales/te.json +8 -8
- package/locales/th.json +8 -8
- package/locales/tr.json +7 -7
- package/locales/uk.json +7 -7
- package/locales/ur.json +8 -8
- package/locales/uz.json +7 -7
- package/locales/vi.json +8 -8
- package/locales/zh-HK.json +8 -8
- package/locales/zh-TW.json +8 -8
- package/locales/zh.json +8 -8
- package/locales/zu.json +8 -8
- package/models/cpu_profile/cpu_profile.prebundle.d.ts +3 -0
- package/models/cpu_profile/cpu_profile.prebundle.js +7 -0
- package/models/cpu_profile/cpu_profile.prebundle.js.map +1 -0
- package/models/cpu_profile/cpu_profile.prebundle.ts +11 -0
- package/models/cpu_profile/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/ModelImpl.d.ts +1 -0
- package/models/trace/ModelImpl.js +2 -4
- package/models/trace/ModelImpl.js.map +1 -1
- package/models/trace/Processor.js +20 -14
- package/models/trace/Processor.js.map +1 -1
- package/models/trace/devtools_entrypoint-bundle-tsconfig-tsconfig.json +61 -0
- package/models/trace/extras/TraceTree.d.ts +0 -1
- package/models/trace/extras/TraceTree.js +0 -3
- package/models/trace/extras/TraceTree.js.map +1 -1
- package/models/trace/extras/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/extras/extras.prebundle.d.ts +7 -0
- package/models/trace/extras/extras.prebundle.js +11 -0
- package/models/trace/extras/extras.prebundle.js.map +1 -0
- package/models/trace/extras/extras.prebundle.ts +11 -0
- package/models/trace/handlers/ExtensionTraceDataHandler.js +28 -14
- package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
- package/models/trace/handlers/ImagePaintingHandler.d.ts +7 -1
- package/models/trace/handlers/ImagePaintingHandler.js +33 -1
- package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.js +70 -3
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/SamplesHandler.js +2 -6
- package/models/trace/handlers/SamplesHandler.js.map +1 -1
- package/models/trace/handlers/SelectorStatsHandler.d.ts +17 -0
- package/models/trace/handlers/SelectorStatsHandler.js +42 -0
- package/models/trace/handlers/SelectorStatsHandler.js.map +1 -1
- package/models/trace/handlers/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/handlers/handlers.prebundle.d.ts +4 -0
- package/models/trace/handlers/handlers.prebundle.js +8 -0
- package/models/trace/handlers/handlers.prebundle.js.map +1 -0
- package/models/trace/handlers/handlers.prebundle.ts +8 -0
- package/models/trace/helpers/SamplesIntegrator.js +14 -22
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
- package/models/trace/helpers/SyntheticEvents.d.ts +0 -6
- package/models/trace/helpers/SyntheticEvents.js +2 -2
- package/models/trace/helpers/SyntheticEvents.js.map +1 -1
- package/models/trace/helpers/Timing.d.ts +5 -0
- package/models/trace/helpers/Timing.js +53 -3
- package/models/trace/helpers/Timing.js.map +1 -1
- package/models/trace/helpers/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/helpers/helpers.prebundle.d.ts +7 -0
- package/models/trace/helpers/helpers.prebundle.js +11 -0
- package/models/trace/helpers/helpers.prebundle.js.map +1 -0
- package/models/trace/helpers/helpers.prebundle.ts +11 -0
- package/models/trace/insights/CLSCulprits.d.ts +5 -4
- package/models/trace/insights/CLSCulprits.js +29 -7
- package/models/trace/insights/CLSCulprits.js.map +1 -1
- package/models/trace/insights/Cache.d.ts +2 -0
- package/models/trace/insights/Cache.js +10 -0
- package/models/trace/insights/Cache.js.map +1 -1
- package/models/trace/insights/Common.d.ts +1 -1
- package/models/trace/insights/Common.js +3 -3
- package/models/trace/insights/Common.js.map +1 -1
- package/models/trace/insights/DOMSize.d.ts +27 -1
- package/models/trace/insights/DOMSize.js +42 -1
- package/models/trace/insights/DOMSize.js.map +1 -1
- package/models/trace/insights/DocumentLatency.d.ts +1 -0
- package/models/trace/insights/DocumentLatency.js +43 -1
- package/models/trace/insights/DocumentLatency.js.map +1 -1
- package/models/trace/insights/DuplicatedJavaScript.d.ts +2 -0
- package/models/trace/insights/DuplicatedJavaScript.js +9 -0
- package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
- package/models/trace/insights/FontDisplay.d.ts +1 -0
- package/models/trace/insights/FontDisplay.js +7 -0
- package/models/trace/insights/FontDisplay.js.map +1 -1
- package/models/trace/insights/ForcedReflow.d.ts +3 -1
- package/models/trace/insights/ForcedReflow.js +18 -1
- package/models/trace/insights/ForcedReflow.js.map +1 -1
- package/models/trace/insights/{InteractionToNextPaint.d.ts → INPBreakdown.d.ts} +14 -8
- package/models/trace/insights/{InteractionToNextPaint.js → INPBreakdown.js} +41 -10
- package/models/trace/insights/INPBreakdown.js.map +1 -0
- package/models/trace/insights/ImageDelivery.d.ts +2 -0
- package/models/trace/insights/ImageDelivery.js +28 -7
- package/models/trace/insights/ImageDelivery.js.map +1 -1
- package/models/trace/insights/{LCPPhases.d.ts → LCPBreakdown.d.ts} +27 -22
- package/models/trace/insights/{LCPPhases.js → LCPBreakdown.js} +77 -48
- package/models/trace/insights/LCPBreakdown.js.map +1 -0
- package/models/trace/insights/LCPDiscovery.d.ts +12 -0
- package/models/trace/insights/LCPDiscovery.js +59 -1
- package/models/trace/insights/LCPDiscovery.js.map +1 -1
- package/models/trace/insights/LegacyJavaScript.d.ts +2 -0
- package/models/trace/insights/LegacyJavaScript.js +9 -0
- package/models/trace/insights/LegacyJavaScript.js.map +1 -1
- package/models/trace/insights/Models.d.ts +2 -2
- package/models/trace/insights/Models.js +2 -2
- package/models/trace/insights/Models.js.map +1 -1
- package/models/trace/insights/ModernHTTP.d.ts +8 -5
- package/models/trace/insights/ModernHTTP.js +26 -13
- package/models/trace/insights/ModernHTTP.js.map +1 -1
- package/models/trace/insights/NetworkDependencyTree.d.ts +5 -4
- package/models/trace/insights/NetworkDependencyTree.js +36 -11
- package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
- package/models/trace/insights/RenderBlocking.d.ts +2 -0
- package/models/trace/insights/RenderBlocking.js +10 -0
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/SlowCSSSelector.d.ts +11 -2
- package/models/trace/insights/SlowCSSSelector.js +33 -14
- package/models/trace/insights/SlowCSSSelector.js.map +1 -1
- package/models/trace/insights/ThirdParties.d.ts +3 -0
- package/models/trace/insights/ThirdParties.js +31 -0
- package/models/trace/insights/ThirdParties.js.map +1 -1
- package/models/trace/insights/Viewport.d.ts +2 -1
- package/models/trace/insights/Viewport.js +16 -0
- package/models/trace/insights/Viewport.js.map +1 -1
- package/models/trace/insights/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/insights/insights-tsconfig.json +2 -2
- package/models/trace/insights/insights.prebundle.d.ts +4 -0
- package/models/trace/insights/insights.prebundle.js +8 -0
- package/models/trace/insights/insights.prebundle.js.map +1 -0
- package/models/trace/insights/insights.prebundle.ts +8 -0
- package/models/trace/insights/types.d.ts +6 -3
- package/models/trace/insights/types.js +3 -2
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/lantern/core/core.prebundle.d.ts +2 -0
- package/models/trace/lantern/core/core.prebundle.js +6 -0
- package/models/trace/lantern/core/core.prebundle.js.map +1 -0
- package/models/trace/lantern/core/core.prebundle.ts +6 -0
- package/models/trace/lantern/core/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/graph/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/graph/graph.prebundle.d.ts +4 -0
- package/models/trace/lantern/graph/graph.prebundle.js +8 -0
- package/models/trace/lantern/graph/graph.prebundle.js.map +1 -0
- package/models/trace/lantern/graph/graph.prebundle.ts +8 -0
- package/models/trace/lantern/lantern.prebundle.d.ts +6 -0
- package/models/trace/lantern/lantern.prebundle.js +10 -0
- package/models/trace/lantern/lantern.prebundle.js.map +1 -0
- package/models/trace/lantern/lantern.prebundle.ts +17 -0
- package/models/trace/lantern/metrics/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/metrics/metrics.prebundle.d.ts +8 -0
- package/models/trace/lantern/metrics/metrics.prebundle.js +12 -0
- package/models/trace/lantern/metrics/metrics.prebundle.js.map +1 -0
- package/models/trace/lantern/metrics/metrics.prebundle.ts +12 -0
- package/models/trace/lantern/simulation/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/simulation/simulation.prebundle.d.ts +6 -0
- package/models/trace/lantern/simulation/simulation.prebundle.js +10 -0
- package/models/trace/lantern/simulation/simulation.prebundle.js.map +1 -0
- package/models/trace/lantern/simulation/simulation.prebundle.ts +10 -0
- package/models/trace/lantern/types/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/lantern/types/types.prebundle.d.ts +1 -0
- package/models/trace/lantern/types/types.prebundle.js +5 -0
- package/models/trace/lantern/types/types.prebundle.js.map +1 -0
- package/models/trace/lantern/types/types.prebundle.ts +5 -0
- package/models/trace/trace.prebundle.d.ts +10 -0
- package/models/trace/trace.prebundle.js +14 -0
- package/models/trace/trace.prebundle.js.map +1 -0
- package/models/trace/trace.prebundle.ts +25 -0
- package/models/trace/types/Extensions.d.ts +13 -1
- package/models/trace/types/Extensions.js +5 -1
- package/models/trace/types/Extensions.js.map +1 -1
- package/models/trace/types/File.d.ts +1 -0
- package/models/trace/types/File.js.map +1 -1
- package/models/trace/types/Overlays.d.ts +110 -0
- package/models/trace/types/Overlays.js +5 -0
- package/models/trace/types/Overlays.js.map +1 -0
- package/models/trace/types/Timing.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +27 -9
- package/models/trace/types/TraceEvents.js +7 -18
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/models/trace/types/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
- package/models/trace/types/types-tsconfig.json +1 -0
- package/models/trace/types/types.d.ts +1 -0
- package/models/trace/types/types.js +1 -0
- package/models/trace/types/types.js.map +1 -1
- package/models/trace/types/types.prebundle.d.ts +5 -0
- package/models/trace/types/types.prebundle.js +9 -0
- package/models/trace/types/types.prebundle.js.map +1 -0
- package/models/trace/types/types.prebundle.ts +9 -0
- package/package.json +1 -1
- package/test/test-trace-engine.mjs +3 -3
- package/models/trace/insights/InteractionToNextPaint.js.map +0 -1
- package/models/trace/insights/LCPPhases.js.map +0 -1
|
@@ -26,10 +26,13 @@ export const UIStrings = {
|
|
|
26
26
|
/**
|
|
27
27
|
* @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. "HTTP/1.1" should not be translated.
|
|
28
28
|
*/
|
|
29
|
-
noOldProtocolRequests: 'No requests used HTTP/1.1'
|
|
29
|
+
noOldProtocolRequests: 'No requests used HTTP/1.1, or its current use of HTTP/1.1 does not present a significant optimization opportunity. HTTP/1.1 requests are only flagged if six or more static assets originate from the same origin, and they are not served from a local development environment or a third-party source.'
|
|
30
30
|
};
|
|
31
31
|
// const str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);
|
|
32
32
|
export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
33
|
+
export function isModernHTTP(model) {
|
|
34
|
+
return model.insightKey === InsightKeys.MODERN_HTTP;
|
|
35
|
+
}
|
|
33
36
|
/**
|
|
34
37
|
* Determines whether a network request is a "static resource" that would benefit from H2 multiplexing.
|
|
35
38
|
* XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse
|
|
@@ -75,8 +78,8 @@ function isMultiplexableStaticAsset(request, entityMappings, firstPartyEntity) {
|
|
|
75
78
|
* [2] https://www.twilio.com/blog/2017/10/http2-issues.html
|
|
76
79
|
* [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/
|
|
77
80
|
*/
|
|
78
|
-
export function
|
|
79
|
-
const
|
|
81
|
+
export function determineHttp1Requests(requests, entityMappings, firstPartyEntity) {
|
|
82
|
+
const http1Requests = [];
|
|
80
83
|
const groupedByOrigin = new Map();
|
|
81
84
|
for (const record of requests) {
|
|
82
85
|
const url = new URL(record.args.data.url);
|
|
@@ -112,9 +115,9 @@ export function determineNonHttp2Resources(requests, entityMappings, firstPartyE
|
|
|
112
115
|
continue;
|
|
113
116
|
}
|
|
114
117
|
seenURLs.add(request.args.data.url);
|
|
115
|
-
|
|
118
|
+
http1Requests.push(request);
|
|
116
119
|
}
|
|
117
|
-
return
|
|
120
|
+
return http1Requests;
|
|
118
121
|
}
|
|
119
122
|
/**
|
|
120
123
|
* Computes the estimated effect of all results being converted to http/2 on the provided graph.
|
|
@@ -148,11 +151,11 @@ function computeWasteWithGraph(urlsToChange, graph, simulator) {
|
|
|
148
151
|
const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;
|
|
149
152
|
return Platform.NumberUtilities.floor(savings, 1 / 10);
|
|
150
153
|
}
|
|
151
|
-
function computeMetricSavings(
|
|
154
|
+
function computeMetricSavings(http1Requests, context) {
|
|
152
155
|
if (!context.navigation || !context.lantern) {
|
|
153
156
|
return;
|
|
154
157
|
}
|
|
155
|
-
const urlsToChange = new Set(
|
|
158
|
+
const urlsToChange = new Set(http1Requests.map(r => r.args.data.url));
|
|
156
159
|
const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;
|
|
157
160
|
const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;
|
|
158
161
|
return {
|
|
@@ -162,14 +165,14 @@ function computeMetricSavings(nonHttp2Requests, context) {
|
|
|
162
165
|
}
|
|
163
166
|
function finalize(partialModel) {
|
|
164
167
|
return {
|
|
165
|
-
insightKey: InsightKeys.
|
|
168
|
+
insightKey: InsightKeys.MODERN_HTTP,
|
|
166
169
|
strings: UIStrings,
|
|
167
170
|
title: i18nString(UIStrings.title),
|
|
168
171
|
description: i18nString(UIStrings.description),
|
|
169
172
|
category: InsightCategory.LCP,
|
|
170
|
-
state: partialModel.
|
|
173
|
+
state: partialModel.http1Requests.length > 0 ? 'fail' : 'pass',
|
|
171
174
|
...partialModel,
|
|
172
|
-
relatedEvents: partialModel.
|
|
175
|
+
relatedEvents: partialModel.http1Requests,
|
|
173
176
|
};
|
|
174
177
|
}
|
|
175
178
|
export function generateInsight(parsedTrace, context) {
|
|
@@ -178,10 +181,20 @@ export function generateInsight(parsedTrace, context) {
|
|
|
178
181
|
const entityMappings = parsedTrace.NetworkRequests.entityMappings;
|
|
179
182
|
const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;
|
|
180
183
|
const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);
|
|
181
|
-
const
|
|
184
|
+
const http1Requests = determineHttp1Requests(contextRequests, entityMappings, firstPartyEntity ?? null);
|
|
182
185
|
return finalize({
|
|
183
|
-
|
|
184
|
-
metricSavings: computeMetricSavings(
|
|
186
|
+
http1Requests,
|
|
187
|
+
metricSavings: computeMetricSavings(http1Requests, context),
|
|
185
188
|
});
|
|
186
189
|
}
|
|
190
|
+
export function createOverlayForRequest(request) {
|
|
191
|
+
return {
|
|
192
|
+
type: 'ENTRY_OUTLINE',
|
|
193
|
+
entry: request,
|
|
194
|
+
outlineReason: 'ERROR',
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export function createOverlays(model) {
|
|
198
|
+
return model.http1Requests.map(req => createOverlayForRequest(req)) ?? [];
|
|
199
|
+
}
|
|
187
200
|
//# sourceMappingURL=ModernHTTP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModernHTTP.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ModernHTTP.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type MetricSavings,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n title: 'Modern HTTP',\n /**\n * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n description:\n 'HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',\n /**\n * @description Column header for a table where each cell represents a network request.\n */\n request: 'Request',\n /**\n * @description Column header for a table where each cell represents the protocol of a network request.\n */\n protocol: 'Protocol',\n /**\n * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. \"HTTP/1.1\" should not be translated.\n */\n noOldProtocolRequests: 'No requests used HTTP/1.1'\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type UseModernHTTPInsightModel = InsightModel<typeof UIStrings, {\n requests: Types.Events.SyntheticNetworkRequest[],\n}>;\n\n/**\n * Determines whether a network request is a \"static resource\" that would benefit from H2 multiplexing.\n * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse\n * for the same origin at the exact same time.\n */\nfunction isMultiplexableStaticAsset(\n request: Types.Events.SyntheticNetworkRequest, entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): boolean {\n if (!Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType)) {\n return false;\n }\n\n // Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.\n // They can masquerade as static types though (gifs, documents, etc)\n if (request.args.data.decodedBodyLength < 100) {\n const entity = entityMappings.entityByEvent.get(request);\n if (entity) {\n // Third-party assets are multiplexable in their first-party context.\n if (firstPartyEntity?.name === entity.name) {\n return true;\n }\n // Skip recognizable third-parties' requests.\n if (!entity.isUnrecognized) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Determine the set of resources that aren't HTTP/2 but should be.\n * We're a little conservative about what we surface for a few reasons:\n *\n * - The simulator approximation of HTTP/2 is a little more generous than reality.\n * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss. [1][2][3]\n * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).\n *\n * Therefore, we only surface requests that were...\n *\n * - Served over HTTP/1.1 or earlier\n * - Served over an origin that serves at least 6 static asset requests\n * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)\n * - Not served on localhost (h2 is a pain to deal with locally & and CI)\n *\n * [1] https://news.ycombinator.com/item?id=19086639\n * [2] https://www.twilio.com/blog/2017/10/http2-issues.html\n * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/\n */\nexport function determineNonHttp2Resources(\n requests: Types.Events.SyntheticNetworkRequest[], entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): Types.Events.SyntheticNetworkRequest[] {\n const nonHttp2Resources: Types.Events.SyntheticNetworkRequest[] = [];\n\n const groupedByOrigin = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\n for (const record of requests) {\n const url = new URL(record.args.data.url);\n if (!isMultiplexableStaticAsset(record, entityMappings, firstPartyEntity)) {\n continue;\n }\n if (Helpers.Network.isSyntheticNetworkRequestLocalhost(record)) {\n continue;\n }\n const originRequests = Platform.MapUtilities.getWithDefault(groupedByOrigin, url.origin, () => []);\n originRequests.push(record);\n }\n\n const seenURLs = new Set<string>();\n\n for (const request of requests) {\n // Skip duplicates.\n if (seenURLs.has(request.args.data.url)) {\n continue;\n }\n\n // Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.\n // These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).\n if (request.args.data.fromServiceWorker) {\n continue;\n }\n\n // Test the protocol to see if it was http/1.1.\n const isOldHttp = /HTTP\\/[01][.\\d]?/i.test(request.args.data.protocol);\n if (!isOldHttp) {\n continue;\n }\n\n const url = new URL(request.args.data.url);\n\n // Check if the origin has enough requests to bother flagging.\n const group = groupedByOrigin.get(url.origin) || [];\n if (group.length < 6) {\n continue;\n }\n\n seenURLs.add(request.args.data.url);\n nonHttp2Resources.push(request);\n }\n\n return nonHttp2Resources;\n}\n\n/**\n * Computes the estimated effect of all results being converted to http/2 on the provided graph.\n */\nfunction computeWasteWithGraph(\n urlsToChange: Set<string>, graph: Lantern.Graph.Node, simulator: Lantern.Simulation.Simulator): Types.Timing.Milli {\n const simulationBefore = simulator.simulate(graph);\n\n // Update all the protocols to reflect implementing our recommendations\n const originalProtocols = new Map();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n if (!urlsToChange.has(node.request.url)) {\n return;\n }\n\n originalProtocols.set(node.request.requestId, node.request.protocol);\n node.request.protocol = 'h2';\n });\n\n const simulationAfter = simulator.simulate(graph);\n\n // Restore the original protocol after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalProtocol = originalProtocols.get(node.request.requestId);\n if (originalProtocol === undefined) {\n return;\n }\n node.request.protocol = originalProtocol;\n });\n\n const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;\n\n return Platform.NumberUtilities.floor(savings, 1 / 10) as Types.Timing.Milli;\n}\n\nfunction computeMetricSavings(\n nonHttp2Requests: Types.Events.SyntheticNetworkRequest[], context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n const urlsToChange = new Set(nonHttp2Requests.map(r => r.args.data.url));\n\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: computeWasteWithGraph(urlsToChange, fcpGraph, context.lantern.simulator),\n LCP: computeWasteWithGraph(urlsToChange, lcpGraph, context.lantern.simulator),\n };\n}\n\nfunction finalize(partialModel: PartialInsightModel<UseModernHTTPInsightModel>): UseModernHTTPInsightModel {\n return {\n insightKey: InsightKeys.IMAGE_DELIVERY,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: partialModel.requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n relatedEvents: partialModel.requests,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): UseModernHTTPInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const contextRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n\n const entityMappings = parsedTrace.NetworkRequests.entityMappings;\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);\n const nonHttp2Requests = determineNonHttp2Resources(contextRequests, entityMappings, firstPartyEntity ?? null);\n\n return finalize({\n requests: nonHttp2Requests,\n metricSavings: computeMetricSavings(nonHttp2Requests, context),\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ModernHTTP.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ModernHTTP.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type MetricSavings,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n title: 'Modern HTTP',\n /**\n * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n description:\n 'HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',\n /**\n * @description Column header for a table where each cell represents a network request.\n */\n request: 'Request',\n /**\n * @description Column header for a table where each cell represents the protocol of a network request.\n */\n protocol: 'Protocol',\n /**\n * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. \"HTTP/1.1\" should not be translated.\n */\n noOldProtocolRequests:\n 'No requests used HTTP/1.1, or its current use of HTTP/1.1 does not present a significant optimization opportunity. HTTP/1.1 requests are only flagged if six or more static assets originate from the same origin, and they are not served from a local development environment or a third-party source.'\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type ModernHTTPInsightModel = InsightModel<typeof UIStrings, {\n http1Requests: Types.Events.SyntheticNetworkRequest[],\n}>;\n\nexport function isModernHTTP(model: InsightModel): model is ModernHTTPInsightModel {\n return model.insightKey === InsightKeys.MODERN_HTTP;\n}\n\n/**\n * Determines whether a network request is a \"static resource\" that would benefit from H2 multiplexing.\n * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse\n * for the same origin at the exact same time.\n */\nfunction isMultiplexableStaticAsset(\n request: Types.Events.SyntheticNetworkRequest, entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): boolean {\n if (!Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType)) {\n return false;\n }\n\n // Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.\n // They can masquerade as static types though (gifs, documents, etc)\n if (request.args.data.decodedBodyLength < 100) {\n const entity = entityMappings.entityByEvent.get(request);\n if (entity) {\n // Third-party assets are multiplexable in their first-party context.\n if (firstPartyEntity?.name === entity.name) {\n return true;\n }\n // Skip recognizable third-parties' requests.\n if (!entity.isUnrecognized) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Determine the set of resources that aren't HTTP/2 but should be.\n * We're a little conservative about what we surface for a few reasons:\n *\n * - The simulator approximation of HTTP/2 is a little more generous than reality.\n * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss. [1][2][3]\n * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).\n *\n * Therefore, we only surface requests that were...\n *\n * - Served over HTTP/1.1 or earlier\n * - Served over an origin that serves at least 6 static asset requests\n * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)\n * - Not served on localhost (h2 is a pain to deal with locally & and CI)\n *\n * [1] https://news.ycombinator.com/item?id=19086639\n * [2] https://www.twilio.com/blog/2017/10/http2-issues.html\n * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/\n */\nexport function determineHttp1Requests(\n requests: Types.Events.SyntheticNetworkRequest[], entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): Types.Events.SyntheticNetworkRequest[] {\n const http1Requests: Types.Events.SyntheticNetworkRequest[] = [];\n\n const groupedByOrigin = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\n for (const record of requests) {\n const url = new URL(record.args.data.url);\n if (!isMultiplexableStaticAsset(record, entityMappings, firstPartyEntity)) {\n continue;\n }\n if (Helpers.Network.isSyntheticNetworkRequestLocalhost(record)) {\n continue;\n }\n const originRequests = Platform.MapUtilities.getWithDefault(groupedByOrigin, url.origin, () => []);\n originRequests.push(record);\n }\n\n const seenURLs = new Set<string>();\n\n for (const request of requests) {\n // Skip duplicates.\n if (seenURLs.has(request.args.data.url)) {\n continue;\n }\n\n // Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.\n // These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).\n if (request.args.data.fromServiceWorker) {\n continue;\n }\n\n // Test the protocol to see if it was http/1.1.\n const isOldHttp = /HTTP\\/[01][.\\d]?/i.test(request.args.data.protocol);\n if (!isOldHttp) {\n continue;\n }\n\n const url = new URL(request.args.data.url);\n\n // Check if the origin has enough requests to bother flagging.\n const group = groupedByOrigin.get(url.origin) || [];\n if (group.length < 6) {\n continue;\n }\n\n seenURLs.add(request.args.data.url);\n http1Requests.push(request);\n }\n\n return http1Requests;\n}\n\n/**\n * Computes the estimated effect of all results being converted to http/2 on the provided graph.\n */\nfunction computeWasteWithGraph(\n urlsToChange: Set<string>, graph: Lantern.Graph.Node, simulator: Lantern.Simulation.Simulator): Types.Timing.Milli {\n const simulationBefore = simulator.simulate(graph);\n\n // Update all the protocols to reflect implementing our recommendations\n const originalProtocols = new Map();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n if (!urlsToChange.has(node.request.url)) {\n return;\n }\n\n originalProtocols.set(node.request.requestId, node.request.protocol);\n node.request.protocol = 'h2';\n });\n\n const simulationAfter = simulator.simulate(graph);\n\n // Restore the original protocol after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalProtocol = originalProtocols.get(node.request.requestId);\n if (originalProtocol === undefined) {\n return;\n }\n node.request.protocol = originalProtocol;\n });\n\n const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;\n\n return Platform.NumberUtilities.floor(savings, 1 / 10) as Types.Timing.Milli;\n}\n\nfunction computeMetricSavings(\n http1Requests: Types.Events.SyntheticNetworkRequest[], context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n const urlsToChange = new Set(http1Requests.map(r => r.args.data.url));\n\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: computeWasteWithGraph(urlsToChange, fcpGraph, context.lantern.simulator),\n LCP: computeWasteWithGraph(urlsToChange, lcpGraph, context.lantern.simulator),\n };\n}\n\nfunction finalize(partialModel: PartialInsightModel<ModernHTTPInsightModel>): ModernHTTPInsightModel {\n return {\n insightKey: InsightKeys.MODERN_HTTP,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: partialModel.http1Requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n relatedEvents: partialModel.http1Requests,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): ModernHTTPInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const contextRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n\n const entityMappings = parsedTrace.NetworkRequests.entityMappings;\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);\n const http1Requests = determineHttp1Requests(contextRequests, entityMappings, firstPartyEntity ?? null);\n\n return finalize({\n http1Requests,\n metricSavings: computeMetricSavings(http1Requests, context),\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: ModernHTTPInsightModel): Types.Overlays.Overlay[] {\n return model.http1Requests.map(req => createOverlayForRequest(req)) ?? [];\n}\n"]}
|
|
@@ -42,15 +42,15 @@ export declare const UIStrings: {
|
|
|
42
42
|
*/
|
|
43
43
|
readonly noPreconnectOrigins: "no origins were preconnected";
|
|
44
44
|
/**
|
|
45
|
-
* @description A warning message that is shown when found more than 4 preconnected links
|
|
45
|
+
* @description A warning message that is shown when found more than 4 preconnected links. "preconnect" should not be translated.
|
|
46
46
|
*/
|
|
47
47
|
readonly tooManyPreconnectLinksWarning: "More than 4 `preconnect` connections were found. These should be used sparingly and only to the most important origins.";
|
|
48
48
|
/**
|
|
49
|
-
* @description A warning message that is shown when the user added preconnect for some unnecessary origins.
|
|
49
|
+
* @description A warning message that is shown when the user added preconnect for some unnecessary origins. "preconnect" should not be translated.
|
|
50
50
|
*/
|
|
51
51
|
readonly unusedWarning: "Unused preconnect. Only use `preconnect` for origins that the page is likely to request.";
|
|
52
52
|
/**
|
|
53
|
-
* @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links.
|
|
53
|
+
* @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links. "preconnect" should not be translated.
|
|
54
54
|
* */
|
|
55
55
|
readonly crossoriginWarning: "Unused preconnect. Check that the `crossorigin` attribute is used properly.";
|
|
56
56
|
/**
|
|
@@ -66,7 +66,7 @@ export declare const UIStrings: {
|
|
|
66
66
|
*/
|
|
67
67
|
readonly estSavingTableTitle: "Preconnect candidates";
|
|
68
68
|
/**
|
|
69
|
-
* @description Description of the table that recommends preconnecting to the origins to save time.
|
|
69
|
+
* @description Description of the table that recommends preconnecting to the origins to save time. "preconnect" should not be translated.
|
|
70
70
|
*/
|
|
71
71
|
readonly estSavingTableDescription: "Add [preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints to your most important origins, but try to use no more than 4.";
|
|
72
72
|
/**
|
|
@@ -129,6 +129,7 @@ export declare function handleLinkResponseHeader(linkHeaderValue: string): Array
|
|
|
129
129
|
export declare function generatePreconnectedOrigins(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContextWithNavigation, contextRequests: Types.Events.SyntheticNetworkRequest[], preconnectCandidates: PreconnectCandidate[]): PreconnectedOrigin[];
|
|
130
130
|
export declare function generatePreconnectCandidates(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContextWithNavigation, contextRequests: Types.Events.SyntheticNetworkRequest[]): PreconnectCandidate[];
|
|
131
131
|
export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): NetworkDependencyTreeInsightModel;
|
|
132
|
+
export declare function createOverlays(model: NetworkDependencyTreeInsightModel): Types.Overlays.Overlay[];
|
|
132
133
|
/**
|
|
133
134
|
* http://tools.ietf.org/html/rfc3986#section-5.2.4
|
|
134
135
|
*/
|
|
@@ -45,15 +45,15 @@ export const UIStrings = {
|
|
|
45
45
|
*/
|
|
46
46
|
noPreconnectOrigins: 'no origins were preconnected',
|
|
47
47
|
/**
|
|
48
|
-
* @description A warning message that is shown when found more than 4 preconnected links
|
|
48
|
+
* @description A warning message that is shown when found more than 4 preconnected links. "preconnect" should not be translated.
|
|
49
49
|
*/
|
|
50
50
|
tooManyPreconnectLinksWarning: 'More than 4 `preconnect` connections were found. These should be used sparingly and only to the most important origins.',
|
|
51
51
|
/**
|
|
52
|
-
* @description A warning message that is shown when the user added preconnect for some unnecessary origins.
|
|
52
|
+
* @description A warning message that is shown when the user added preconnect for some unnecessary origins. "preconnect" should not be translated.
|
|
53
53
|
*/
|
|
54
54
|
unusedWarning: 'Unused preconnect. Only use `preconnect` for origins that the page is likely to request.',
|
|
55
55
|
/**
|
|
56
|
-
* @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links.
|
|
56
|
+
* @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links. "preconnect" should not be translated.
|
|
57
57
|
* */
|
|
58
58
|
crossoriginWarning: 'Unused preconnect. Check that the `crossorigin` attribute is used properly.',
|
|
59
59
|
/**
|
|
@@ -69,7 +69,7 @@ export const UIStrings = {
|
|
|
69
69
|
*/
|
|
70
70
|
estSavingTableTitle: 'Preconnect candidates',
|
|
71
71
|
/**
|
|
72
|
-
* @description Description of the table that recommends preconnecting to the origins to save time.
|
|
72
|
+
* @description Description of the table that recommends preconnecting to the origins to save time. "preconnect" should not be translated.
|
|
73
73
|
*/
|
|
74
74
|
estSavingTableDescription: 'Add [preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints to your most important origins, but try to use no more than 4.',
|
|
75
75
|
/**
|
|
@@ -313,12 +313,21 @@ export function handleLinkResponseHeader(linkHeaderValue) {
|
|
|
313
313
|
return [];
|
|
314
314
|
}
|
|
315
315
|
const preconnectedOrigins = [];
|
|
316
|
-
// const headerTextParts = linkHeaderValue.split(',');
|
|
317
316
|
for (let i = 0; i < linkHeaderValue.length;) {
|
|
318
317
|
const firstUrlEnd = linkHeaderValue.indexOf('>', i);
|
|
318
|
+
if (firstUrlEnd === -1) {
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
319
321
|
const commaIndex = linkHeaderValue.indexOf(',', firstUrlEnd);
|
|
320
322
|
const partEnd = commaIndex !== -1 ? commaIndex : linkHeaderValue.length;
|
|
321
323
|
const part = linkHeaderValue.substring(i, partEnd);
|
|
324
|
+
// This shouldn't be necessary, but we had a bug that created an infinite loop so
|
|
325
|
+
// let's guard against that.
|
|
326
|
+
// See crbug.com/431239629
|
|
327
|
+
if (partEnd + 1 <= i) {
|
|
328
|
+
console.warn('unexpected infinite loop, bailing');
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
322
331
|
i = partEnd + 1;
|
|
323
332
|
const preconnectedOrigin = handleLinkResponseHeaderPart(part.trim());
|
|
324
333
|
if (preconnectedOrigin) {
|
|
@@ -344,7 +353,7 @@ export function generatePreconnectedOrigins(parsedTrace, context, contextRequest
|
|
|
344
353
|
source: 'DOM',
|
|
345
354
|
});
|
|
346
355
|
}
|
|
347
|
-
const documentRequest = parsedTrace.NetworkRequests.
|
|
356
|
+
const documentRequest = parsedTrace.NetworkRequests.byId.get(context.navigationId);
|
|
348
357
|
documentRequest?.args.data.responseHeaders?.forEach(header => {
|
|
349
358
|
if (header.name.toLowerCase() === 'link') {
|
|
350
359
|
const preconnectedOriginsFromResponseHeader = handleLinkResponseHeader(header.value); // , documentRequest);
|
|
@@ -431,8 +440,8 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
|
|
|
431
440
|
if (!context.lantern) {
|
|
432
441
|
return [];
|
|
433
442
|
}
|
|
434
|
-
const
|
|
435
|
-
if (!
|
|
443
|
+
const documentRequest = parsedTrace.NetworkRequests.byId.get(context.navigationId);
|
|
444
|
+
if (!documentRequest) {
|
|
436
445
|
return [];
|
|
437
446
|
}
|
|
438
447
|
const { rtt, additionalRttByOrigin } = context.lantern.simulator.getOptions();
|
|
@@ -450,11 +459,11 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
|
|
|
450
459
|
fcpGraphURLs.add(node.request.url);
|
|
451
460
|
}
|
|
452
461
|
});
|
|
453
|
-
const
|
|
462
|
+
const groupedOrigins = candidateRequestsByOrigin(parsedTrace, documentRequest, contextRequests, lcpGraphURLs);
|
|
454
463
|
let maxWastedLcp = Types.Timing.Milli(0);
|
|
455
464
|
let maxWastedFcp = Types.Timing.Milli(0);
|
|
456
465
|
let preconnectCandidates = [];
|
|
457
|
-
|
|
466
|
+
groupedOrigins.forEach(requests => {
|
|
458
467
|
const firstRequestOfOrigin = requests[0];
|
|
459
468
|
// Skip the origin if we don't have timing information
|
|
460
469
|
if (!firstRequestOfOrigin.args.data.timing) {
|
|
@@ -471,7 +480,8 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
|
|
|
471
480
|
if (firstRequestOfOriginParsedURL.scheme === 'https') {
|
|
472
481
|
connectionTime = Types.Timing.Milli(connectionTime * 2);
|
|
473
482
|
}
|
|
474
|
-
const timeBetweenMainResourceAndDnsStart = Types.Timing.Micro(firstRequestOfOrigin.args.data.syntheticData.sendStartTime -
|
|
483
|
+
const timeBetweenMainResourceAndDnsStart = Types.Timing.Micro(firstRequestOfOrigin.args.data.syntheticData.sendStartTime -
|
|
484
|
+
documentRequest.args.data.syntheticData.finishTime +
|
|
475
485
|
Helpers.Timing.milliToMicro(firstRequestOfOrigin.args.data.timing.dnsStart));
|
|
476
486
|
const wastedMs = Math.min(connectionTime, Helpers.Timing.microToMilli(timeBetweenMainResourceAndDnsStart));
|
|
477
487
|
if (wastedMs < IGNORE_THRESHOLD_IN_MILLISECONDS) {
|
|
@@ -513,6 +523,21 @@ export function generateInsight(parsedTrace, context) {
|
|
|
513
523
|
preconnectCandidates,
|
|
514
524
|
});
|
|
515
525
|
}
|
|
526
|
+
export function createOverlays(model) {
|
|
527
|
+
function walk(nodes, overlays) {
|
|
528
|
+
nodes.forEach(node => {
|
|
529
|
+
overlays.push({
|
|
530
|
+
type: 'ENTRY_OUTLINE',
|
|
531
|
+
entry: node.request,
|
|
532
|
+
outlineReason: 'ERROR',
|
|
533
|
+
});
|
|
534
|
+
walk(node.children, overlays);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
const overlays = [];
|
|
538
|
+
walk(model.rootNodes, overlays);
|
|
539
|
+
return overlays;
|
|
540
|
+
}
|
|
516
541
|
// the rest of this file is copied from core/common/common.js, which can't be bundled right now.
|
|
517
542
|
/**
|
|
518
543
|
* http://tools.ietf.org/html/rfc3986#section-5.2.4
|