44 * SPDX-License-Identifier: Apache-2.0
55 */
66
7- import { UIStrings } from '@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js' ;
7+ import { UIStrings , TOO_MANY_PRECONNECTS_THRESHOLD } from '@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js' ;
88
99import { Audit } from '../audit.js' ;
1010import * as i18n from '../../lib/i18n/i18n.js' ;
11- import { adaptInsightToAuditProduct } from './insight-audit.js' ;
11+ import { adaptInsightToAuditProduct , makeNodeItemForNodeId } from './insight-audit.js' ;
1212
1313// eslint-disable-next-line max-len
1414const str_ = i18n . createIcuMessageFn ( 'node_modules/@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js' , UIStrings ) ;
@@ -24,8 +24,8 @@ class NetworkDependencyTreeInsight extends Audit {
2424 failureTitle : str_ ( UIStrings . title ) ,
2525 description : str_ ( UIStrings . description ) ,
2626 guidanceLevel : 1 ,
27- requiredArtifacts : [ 'Trace' , 'SourceMaps' ] ,
28- replacesAudits : [ 'critical-request-chains' ] ,
27+ requiredArtifacts : [ 'Trace' , 'SourceMaps' , 'TraceElements' ] ,
28+ replacesAudits : [ 'critical-request-chains' , 'uses-rel-preconnect' ] ,
2929 } ;
3030 }
3131
@@ -59,15 +59,92 @@ class NetworkDependencyTreeInsight extends Audit {
5959 */
6060 static async audit ( artifacts , context ) {
6161 return adaptInsightToAuditProduct ( artifacts , context , 'NetworkDependencyTree' , ( insight ) => {
62- const chains = this . traceEngineNodesToDetailsNodes ( insight . rootNodes ) ;
62+ const list = [ ] ;
63+ let sectionDetails ;
6364
64- return {
65+ sectionDetails = /** @type { LH.Audit.Details.NetworkTree } */ ( {
6566 type : 'network-tree' ,
66- chains,
67+ chains : this . traceEngineNodesToDetailsNodes ( insight . rootNodes ) ,
6768 longestChain : {
6869 duration : Math . round ( insight . maxTime / 1000 ) ,
6970 } ,
70- } ;
71+ } ) ;
72+ list . push ( Audit . makeListDetailSectionItem ( sectionDetails ) ) ;
73+
74+ // Preconnected origins table.
75+ if ( insight . preconnectedOrigins . length ) {
76+ /** @type {LH.Audit.Details.Table['headings'] } */
77+ const headings = [
78+ /* eslint-disable max-len */
79+ { key : 'origin' , valueType : 'text' , subItemsHeading : { key : 'warning' } , label : str_ ( UIStrings . columnOrigin ) } ,
80+ { key : 'source' , valueType : 'node' , label : str_ ( UIStrings . columnSource ) } ,
81+ /* eslint-enable max-len */
82+ ] ;
83+
84+ /** @type {LH.Audit.Details.Table['items'] } */
85+ const items = insight . preconnectedOrigins . map ( c => {
86+ const warnings = [ ] ;
87+ if ( c . unused ) {
88+ warnings . push ( str_ ( UIStrings . unusedWarning ) ) ;
89+ }
90+ if ( c . crossorigin ) {
91+ warnings . push ( str_ ( UIStrings . crossoriginWarning ) ) ;
92+ }
93+ /** @type {LH.Audit.Details.TableSubItems } */
94+ const subItems = {
95+ type : 'subitems' ,
96+ items : warnings . map ( warning => ( { warning} ) ) ,
97+ } ;
98+ return {
99+ origin : c . url ,
100+ source : c . source === 'DOM' ?
101+ makeNodeItemForNodeId ( artifacts . TraceElements , c . node_id ) :
102+ { type : 'text' , value : c . headerText } ,
103+ subItems,
104+ } ;
105+ } ) ;
106+
107+ sectionDetails = Audit . makeTableDetails ( headings , items ) ;
108+ } else {
109+ sectionDetails = /** @type {LH.Audit.Details.TextValue } */ (
110+ { type : 'text' , value : str_ ( UIStrings . noPreconnectOrigins ) } ) ;
111+ }
112+
113+ list . push ( Audit . makeListDetailSectionItem (
114+ sectionDetails ,
115+ str_ ( UIStrings . preconnectOriginsTableTitle ) ,
116+ str_ ( UIStrings . preconnectOriginsTableDescription ) ) ) ;
117+
118+ // Estimated savings table.
119+ if ( insight . preconnectCandidates . length ) {
120+ /** @type {LH.Audit.Details.Table['headings'] } */
121+ const headings = [
122+ { key : 'origin' , valueType : 'text' , label : str_ ( UIStrings . columnOrigin ) } ,
123+ { key : 'wastedMs' , valueType : 'ms' , label : str_ ( UIStrings . columnWastedMs ) } ,
124+ ] ;
125+
126+ /** @type {LH.Audit.Details.Table['items'] } */
127+ const items = insight . preconnectCandidates . map ( c => {
128+ return { origin : c . origin , wastedMs : c . wastedMs } ;
129+ } ) ;
130+
131+ sectionDetails = Audit . makeTableDetails ( headings , items ) ;
132+ } else {
133+ sectionDetails = /** @type {LH.Audit.Details.TextValue } */ (
134+ { type : 'text' , value : str_ ( UIStrings . noPreconnectCandidates ) } ) ;
135+ }
136+
137+ list . push ( Audit . makeListDetailSectionItem (
138+ sectionDetails ,
139+ str_ ( UIStrings . estSavingTableTitle ) ,
140+ str_ ( UIStrings . estSavingTableDescription ) ) ) ;
141+
142+ const warnings = [ ] ;
143+ if ( insight . preconnectedOrigins . length > TOO_MANY_PRECONNECTS_THRESHOLD ) {
144+ warnings . push ( str_ ( UIStrings . tooManyPreconnectLinksWarning ) ) ;
145+ }
146+
147+ return { details : Audit . makeListDetails ( list ) , warnings} ;
71148 } ) ;
72149 }
73150}
0 commit comments