lighthouse 12.0.0 → 12.1.0-dev.20240619

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.
Files changed (219) hide show
  1. package/cli/run.js +5 -38
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.js +1 -1
  3. package/cli/test/smokehouse/smokehouse.js +11 -1
  4. package/core/audits/accessibility/aria-allowed-role.js +7 -9
  5. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  6. package/core/audits/byte-efficiency/byte-efficiency-audit.js +3 -3
  7. package/core/audits/byte-efficiency/offscreen-images.js +1 -1
  8. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
  9. package/core/audits/byte-efficiency/render-blocking-resources.js +10 -10
  10. package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
  11. package/core/audits/dobetterweb/uses-http2.js +5 -5
  12. package/core/audits/long-tasks.d.ts +7 -6
  13. package/core/audits/long-tasks.js +5 -4
  14. package/core/audits/metrics/first-meaningful-paint.d.ts +1 -17
  15. package/core/audits/metrics/first-meaningful-paint.js +5 -47
  16. package/core/audits/metrics/interactive.d.ts +1 -1
  17. package/core/audits/metrics/interactive.js +1 -1
  18. package/core/audits/predictive-perf.js +0 -6
  19. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  20. package/core/audits/prioritize-lcp-image.js +2 -2
  21. package/core/audits/redirects.js +2 -3
  22. package/core/audits/third-party-facades.js +1 -1
  23. package/core/audits/third-party-summary.js +1 -1
  24. package/core/audits/uses-rel-preconnect.js +2 -2
  25. package/core/audits/uses-rel-preload.js +9 -9
  26. package/core/computed/critical-request-chains.js +3 -3
  27. package/core/computed/document-urls.js +3 -2
  28. package/core/computed/load-simulator.d.ts +4 -4
  29. package/core/computed/load-simulator.js +3 -54
  30. package/core/computed/main-resource.js +3 -2
  31. package/core/computed/metrics/interactive.d.ts +6 -0
  32. package/core/computed/metrics/interactive.js +2 -2
  33. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
  34. package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
  35. package/core/computed/metrics/lantern-interactive.d.ts +4 -4
  36. package/core/computed/metrics/lantern-interactive.js +6 -6
  37. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
  38. package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  39. package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
  40. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  41. package/core/computed/metrics/lantern-metric.d.ts +21 -2
  42. package/core/computed/metrics/lantern-metric.js +39 -4
  43. package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
  44. package/core/computed/metrics/lantern-speed-index.js +4 -4
  45. package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
  46. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  47. package/core/computed/metrics/timing-summary.js +0 -6
  48. package/core/computed/metrics/total-blocking-time.js +3 -1
  49. package/core/computed/navigation-insights.d.ts +2 -20
  50. package/core/computed/network-analysis.d.ts +0 -5
  51. package/core/computed/network-analysis.js +2 -42
  52. package/core/computed/page-dependency-graph.d.ts +5 -3
  53. package/core/computed/page-dependency-graph.js +17 -7
  54. package/core/computed/processed-navigation.d.ts +1 -1
  55. package/core/computed/tbt-impact-tasks.js +4 -2
  56. package/core/computed/trace-engine-result.d.ts +0 -11
  57. package/core/computed/trace-engine-result.js +5 -19
  58. package/core/config/constants.d.ts +28 -53
  59. package/core/config/constants.js +2 -43
  60. package/core/gather/driver/navigation.js +1 -1
  61. package/core/gather/driver/network-monitor.d.ts +2 -1
  62. package/core/gather/driver/network-monitor.js +4 -4
  63. package/core/gather/driver/target-manager.d.ts +1 -1
  64. package/core/gather/driver.d.ts +0 -12
  65. package/core/gather/driver.js +1 -26
  66. package/core/gather/gatherers/inspector-issues.js +1 -0
  67. package/core/gather/gatherers/root-causes.js +0 -1
  68. package/core/gather/session.d.ts +5 -3
  69. package/core/gather/session.js +22 -1
  70. package/core/lib/asset-saver.d.ts +13 -9
  71. package/core/lib/asset-saver.js +77 -30
  72. package/core/lib/bf-cache-strings.js +2 -2
  73. package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
  74. package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
  75. package/core/lib/lantern/BaseNode.test.js +385 -0
  76. package/core/lib/lantern/CpuNode.d.ts +43 -0
  77. package/core/lib/lantern/{cpu-node.js → CpuNode.js} +8 -9
  78. package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
  79. package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +23 -25
  80. package/core/lib/lantern/{metric.js → Metric.js} +14 -16
  81. package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +6 -7
  82. package/core/lib/lantern/{network-node.js → NetworkNode.js} +7 -9
  83. package/core/lib/lantern/PageDependencyGraph.d.ts +82 -0
  84. package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +185 -50
  85. package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
  86. package/core/{computed/metrics/tbt-utils.d.ts → lib/lantern/TBTUtils.d.ts} +1 -1
  87. package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
  88. package/core/lib/lantern/TBTUtils.test.js +130 -0
  89. package/core/lib/lantern/TraceEngineComputationData.d.ts +25 -0
  90. package/core/lib/lantern/TraceEngineComputationData.js +466 -0
  91. package/core/lib/lantern/lantern.d.ts +19 -7
  92. package/core/lib/lantern/lantern.js +21 -1
  93. package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
  94. package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +11 -13
  95. package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
  96. package/core/lib/lantern/metrics/Interactive.d.ts +20 -0
  97. package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +23 -26
  98. package/core/lib/lantern/metrics/Interactive.test.js +56 -0
  99. package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +19 -0
  100. package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +16 -19
  101. package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
  102. package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +24 -0
  103. package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +12 -13
  104. package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
  105. package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
  106. package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +7 -13
  107. package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +14 -16
  108. package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
  109. package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +25 -0
  110. package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +13 -16
  111. package/core/lib/lantern/metrics/__snapshots__/FirstContentfulPaint.test.js.snap +11 -0
  112. package/core/lib/lantern/metrics/__snapshots__/Interactive.test.js.snap +17 -0
  113. package/core/lib/lantern/metrics/metrics.d.ts +9 -0
  114. package/core/lib/lantern/metrics/metrics.js +16 -0
  115. package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +15 -15
  116. package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +25 -25
  117. package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
  118. package/core/lib/lantern/simulation/Constants.d.ts +52 -0
  119. package/core/lib/lantern/simulation/Constants.js +48 -0
  120. package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +3 -3
  121. package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +2 -2
  122. package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
  123. package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +34 -21
  124. package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +106 -57
  125. package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
  126. package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
  127. package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
  128. package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +21 -19
  129. package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +100 -45
  130. package/core/lib/lantern/simulation/Simulator.test.js +434 -0
  131. package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
  132. package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
  133. package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
  134. package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
  135. package/core/lib/lantern/simulation/simulation.d.ts +21 -0
  136. package/core/lib/lantern/simulation/simulation.js +28 -0
  137. package/core/lib/lantern/types/lantern.d.ts +145 -20
  138. package/core/lib/lantern-trace-saver.d.ts +4 -4
  139. package/core/lib/lantern-trace-saver.js +4 -4
  140. package/core/lib/navigation-error.js +3 -3
  141. package/core/lib/network-recorder.js +2 -2
  142. package/core/lib/network-request.d.ts +29 -3
  143. package/core/lib/network-request.js +20 -13
  144. package/core/lib/tracehouse/trace-processor.d.ts +0 -2
  145. package/core/lib/tracehouse/trace-processor.js +1 -31
  146. package/core/lib/traces/metric-trace-events.js +0 -5
  147. package/dist/report/bundle.esm.js +1 -1
  148. package/dist/report/flow.js +1 -1
  149. package/dist/report/standalone.js +1 -1
  150. package/package.json +14 -13
  151. package/report/renderer/performance-category-renderer.js +1 -1
  152. package/shared/localization/locales/ar-XB.json +43 -4
  153. package/shared/localization/locales/ar.json +43 -4
  154. package/shared/localization/locales/bg.json +43 -4
  155. package/shared/localization/locales/ca.json +44 -5
  156. package/shared/localization/locales/cs.json +43 -4
  157. package/shared/localization/locales/da.json +43 -4
  158. package/shared/localization/locales/de.json +43 -4
  159. package/shared/localization/locales/el.json +43 -4
  160. package/shared/localization/locales/en-GB.json +42 -3
  161. package/shared/localization/locales/en-US.json +4 -4
  162. package/shared/localization/locales/en-XA.json +43 -4
  163. package/shared/localization/locales/en-XL.json +4 -4
  164. package/shared/localization/locales/es-419.json +43 -4
  165. package/shared/localization/locales/es.json +42 -3
  166. package/shared/localization/locales/fi.json +43 -4
  167. package/shared/localization/locales/fil.json +42 -3
  168. package/shared/localization/locales/fr.json +42 -3
  169. package/shared/localization/locales/he.json +48 -9
  170. package/shared/localization/locales/hi.json +43 -4
  171. package/shared/localization/locales/hr.json +43 -4
  172. package/shared/localization/locales/hu.json +42 -3
  173. package/shared/localization/locales/id.json +42 -3
  174. package/shared/localization/locales/it.json +43 -4
  175. package/shared/localization/locales/ja.json +42 -3
  176. package/shared/localization/locales/ko.json +43 -4
  177. package/shared/localization/locales/lt.json +42 -3
  178. package/shared/localization/locales/lv.json +43 -4
  179. package/shared/localization/locales/nl.json +44 -5
  180. package/shared/localization/locales/no.json +42 -3
  181. package/shared/localization/locales/pl.json +43 -4
  182. package/shared/localization/locales/pt-PT.json +43 -4
  183. package/shared/localization/locales/pt.json +43 -4
  184. package/shared/localization/locales/ro.json +43 -4
  185. package/shared/localization/locales/ru.json +43 -4
  186. package/shared/localization/locales/sk.json +43 -4
  187. package/shared/localization/locales/sl.json +42 -3
  188. package/shared/localization/locales/sr-Latn.json +43 -4
  189. package/shared/localization/locales/sr.json +43 -4
  190. package/shared/localization/locales/sv.json +42 -3
  191. package/shared/localization/locales/ta.json +42 -3
  192. package/shared/localization/locales/te.json +43 -4
  193. package/shared/localization/locales/th.json +44 -5
  194. package/shared/localization/locales/tr.json +43 -4
  195. package/shared/localization/locales/uk.json +43 -4
  196. package/shared/localization/locales/vi.json +43 -4
  197. package/shared/localization/locales/zh-HK.json +43 -4
  198. package/shared/localization/locales/zh-TW.json +43 -4
  199. package/shared/localization/locales/zh.json +43 -4
  200. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
  201. package/tsconfig-all.json +1 -0
  202. package/tsconfig.json +11 -7
  203. package/types/artifacts.d.ts +23 -25
  204. package/types/gatherer.d.ts +2 -3
  205. package/types/lhr/lhr.d.ts +2 -0
  206. package/core/computed/metrics/first-meaningful-paint.d.ts +0 -21
  207. package/core/computed/metrics/first-meaningful-paint.js +0 -44
  208. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +0 -25
  209. package/core/computed/metrics/lantern-first-meaningful-paint.js +0 -43
  210. package/core/lib/lantern/cpu-node.d.ts +0 -44
  211. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +0 -6
  212. package/core/lib/lantern/metrics/first-meaningful-paint.js +0 -64
  213. package/core/lib/lantern/metrics/interactive.d.ts +0 -26
  214. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
  215. package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
  216. package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
  217. package/core/lib/lantern/page-dependency-graph.d.ts +0 -58
  218. /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
  219. /package/core/{computed/metrics/tbt-utils.js → lib/lantern/TBTUtils.js} +0 -0
@@ -114,7 +114,6 @@ class RootCauses extends BaseGatherer {
114
114
  const rootCausesEngine = new TraceEngine.RootCauses(protocolInterface);
115
115
  const layoutShiftEvents = traceParsedData.LayoutShifts.clusters.flatMap(c => c.events);
116
116
  for (const event of layoutShiftEvents) {
117
- // @ts-expect-error The data we do get in the trace processor is still enough here
118
117
  const r = await rootCausesEngine.layoutShifts.rootCausesForEvent(traceParsedData, event);
119
118
  if (!r) continue;
120
119
 
@@ -17,7 +17,8 @@ export class ProtocolSession extends ProtocolSession_base implements LH.Gatherer
17
17
  * @param {E} method
18
18
  * @param {LH.CrdpEvents[E]} params
19
19
  */
20
- _handleProtocolEvent<E extends keyof import("puppeteer-core").ProtocolMapping.Events>(method: E, ...params: import("puppeteer-core").ProtocolMapping.Events[E]): void;
20
+ _handleProtocolEvent<E extends keyof import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Events>(method: E, ...params: import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Events[E]): void;
21
+ _targetCrashedPromise: Promise<never>;
21
22
  id(): string;
22
23
  /** @param {LH.Crdp.Target.TargetInfo} targetInfo */
23
24
  setTargetInfo(targetInfo: LH.Crdp.Target.TargetInfo): void;
@@ -39,7 +40,7 @@ export class ProtocolSession extends ProtocolSession_base implements LH.Gatherer
39
40
  * @param {LH.CrdpCommands[C]['paramsType']} params
40
41
  * @return {Promise<LH.CrdpCommands[C]['returnType']>}
41
42
  */
42
- sendCommand<C extends keyof import("puppeteer-core").ProtocolMapping.Commands>(method: C, ...params: import("puppeteer-core").ProtocolMapping.Commands[C]["paramsType"]): Promise<import("puppeteer-core").ProtocolMapping.Commands[C]["returnType"]>;
43
+ sendCommand<C extends keyof import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Commands>(method: C, ...params: import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Commands[C]["paramsType"]): Promise<import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Commands[C]["returnType"]>;
43
44
  /**
44
45
  * Send and if there's an error response, do not reject.
45
46
  * @template {keyof LH.CrdpCommands} C
@@ -47,12 +48,13 @@ export class ProtocolSession extends ProtocolSession_base implements LH.Gatherer
47
48
  * @param {LH.CrdpCommands[C]['paramsType']} params
48
49
  * @return {Promise<void>}
49
50
  */
50
- sendCommandAndIgnore<C_1 extends keyof import("puppeteer-core").ProtocolMapping.Commands>(method: C_1, ...params: import("puppeteer-core").ProtocolMapping.Commands[C_1]["paramsType"]): Promise<void>;
51
+ sendCommandAndIgnore<C_1 extends keyof import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Commands>(method: C_1, ...params: import("devtools-protocol/types/protocol-mapping.js").ProtocolMapping.Commands[C_1]["paramsType"]): Promise<void>;
51
52
  /**
52
53
  * Disposes of a session so that it can no longer talk to Chrome.
53
54
  * @return {Promise<void>}
54
55
  */
55
56
  dispose(): Promise<void>;
57
+ onCrashPromise(): Promise<never>;
56
58
  }
57
59
  export {};
58
60
  //# sourceMappingURL=session.d.ts.map
@@ -44,6 +44,22 @@ class ProtocolSession extends CrdpEventEmitter {
44
44
  this._handleProtocolEvent = this._handleProtocolEvent.bind(this);
45
45
  // @ts-expect-error Puppeteer expects the handler params to be type `unknown`
46
46
  this._cdpSession.on('*', this._handleProtocolEvent);
47
+
48
+ // If the target crashes, we can't continue gathering.
49
+ // FWIW, if the target unexpectedly detaches (eg the user closed the tab), pptr will
50
+ // catch that and reject in this._cdpSession.send, which is caught by us.
51
+ /** @param {Error} _ */
52
+ let rej = _ => {}; // Poor man's Promise.withResolvers()
53
+ this._targetCrashedPromise = /** @type {Promise<never>} */ (
54
+ new Promise((_, theRej) => rej = theRej));
55
+ this.on('Inspector.targetCrashed', async () => {
56
+ log.error('TargetManager', 'Inspector.targetCrashed');
57
+ // Manually detach so no more CDP traffic is attempted.
58
+ // Don't await, else our rejection will be a 'Target closed' protocol error on cross-talk
59
+ // CDP calls.
60
+ void this.dispose();
61
+ rej(new LighthouseError(LighthouseError.errors.TARGET_CRASHED));
62
+ });
47
63
  }
48
64
 
49
65
  id() {
@@ -114,7 +130,8 @@ class ProtocolSession extends CrdpEventEmitter {
114
130
  log.formatProtocol('method <= browser ERR', {method}, 'error');
115
131
  throw LighthouseError.fromProtocolMessage(method, error);
116
132
  });
117
- const resultWithTimeoutPromise = Promise.race([resultPromise, timeoutPromise]);
133
+ const resultWithTimeoutPromise =
134
+ Promise.race([resultPromise, timeoutPromise, this._targetCrashedPromise]);
118
135
 
119
136
  return resultWithTimeoutPromise.finally(() => {
120
137
  if (timeout) clearTimeout(timeout);
@@ -142,6 +159,10 @@ class ProtocolSession extends CrdpEventEmitter {
142
159
  this._cdpSession.off('*', this._handleProtocolEvent);
143
160
  await this._cdpSession.detach().catch(e => log.verbose('session', 'detach failed', e.message));
144
161
  }
162
+
163
+ onCrashPromise() {
164
+ return this._targetCrashedPromise;
165
+ }
145
166
  }
146
167
 
147
168
  export {ProtocolSession};
@@ -4,12 +4,15 @@ export type PreparedAssets = {
4
4
  };
5
5
  /**
6
6
  * Save artifacts object mostly to single file located at basePath/artifacts.json.
7
- * Also save the traces & devtoolsLogs to their own files
7
+ * Also save the traces & devtoolsLogs to their own files, with optional compression.
8
8
  * @param {LH.Artifacts} artifacts
9
9
  * @param {string} basePath
10
+ * @param {{gzip?: boolean}} options
10
11
  * @return {Promise<void>}
11
12
  */
12
- export function saveArtifacts(artifacts: LH.Artifacts, basePath: string): Promise<void>;
13
+ export function saveArtifacts(artifacts: LH.Artifacts, basePath: string, options?: {
14
+ gzip?: boolean;
15
+ }): Promise<void>;
13
16
  /**
14
17
  * Saves flow artifacts with the following file structure:
15
18
  * flow/ -- Directory specified by `basePath`.
@@ -32,11 +35,6 @@ export function saveFlowArtifacts(flowArtifacts: LH.UserFlow.FlowArtifacts, base
32
35
  * @param {string} basePath
33
36
  */
34
37
  export function saveLhr(lhr: LH.Result, basePath: string): void;
35
- /**
36
- * @typedef {object} PreparedAssets
37
- * @property {LH.Trace} [traceData]
38
- * @property {LH.DevtoolsLog} [devtoolsLog]
39
- */
40
38
  /**
41
39
  * Load artifacts object from files located within basePath
42
40
  * Also save the traces to their own files
@@ -67,16 +65,22 @@ export function prepareAssets(artifacts: LH.Artifacts, audits?: Record<string, i
67
65
  * Save a trace as JSON by streaming to disk at traceFilename.
68
66
  * @param {LH.Trace} traceData
69
67
  * @param {string} traceFilename
68
+ * @param {{gzip?: boolean}=} options
70
69
  * @return {Promise<void>}
71
70
  */
72
- export function saveTrace(traceData: LH.Trace, traceFilename: string): Promise<void>;
71
+ export function saveTrace(traceData: LH.Trace, traceFilename: string, options?: {
72
+ gzip?: boolean;
73
+ } | undefined): Promise<void>;
73
74
  /**
74
75
  * Save a devtoolsLog as JSON by streaming to disk at devtoolLogFilename.
75
76
  * @param {LH.DevtoolsLog} devtoolsLog
76
77
  * @param {string} devtoolLogFilename
78
+ * @param {{gzip?: boolean}=} options
77
79
  * @return {Promise<void>}
78
80
  */
79
- export function saveDevtoolsLog(devtoolsLog: import("../index.js").DevtoolsLog, devtoolLogFilename: string): Promise<void>;
81
+ export function saveDevtoolsLog(devtoolsLog: import("../index.js").DevtoolsLog, devtoolLogFilename: string, options?: {
82
+ gzip?: boolean;
83
+ } | undefined): Promise<void>;
80
84
  /**
81
85
  * @param {LH.DevtoolsLog} devtoolsLog
82
86
  * @param {string} outputPath
@@ -8,10 +8,11 @@ import fs from 'fs';
8
8
  import path from 'path';
9
9
  import stream from 'stream';
10
10
  import url from 'url';
11
+ import {createGzip, gunzipSync} from 'zlib';
11
12
 
12
13
  import log from 'lighthouse-logger';
13
14
 
14
- import {Simulator} from './lantern/simulator/simulator.js';
15
+ import * as Lantern from './lantern/lantern.js';
15
16
  import lanternTraceSaver from './lantern-trace-saver.js';
16
17
  import {MetricTraceEvents} from './traces/metric-trace-events.js';
17
18
  import {NetworkAnalysis} from '../computed/network-analysis.js';
@@ -33,6 +34,46 @@ const stepDirectoryRegex = /^step(\d+)$/;
33
34
  * @property {LH.DevtoolsLog} [devtoolsLog]
34
35
  */
35
36
 
37
+ /**
38
+ * @param {import('stream').PipelineSource<any>} contents
39
+ * @param {string} path
40
+ * @param {boolean} gzip
41
+ */
42
+ async function writeJson(contents, path, gzip) {
43
+ const writeStream = fs.createWriteStream(gzip ? path + '.gz' : path);
44
+ if (gzip) {
45
+ await stream.promises.pipeline(contents, createGzip(), writeStream);
46
+ } else {
47
+ await stream.promises.pipeline(contents, writeStream);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Prefers reading a gzipped file (.gz) if present.
53
+ * @param {string} filename
54
+ * @param {(this: any, key: string, value: any) => any=} reviver
55
+ */
56
+ function readJson(filename, reviver) {
57
+ if (fs.existsSync(filename + '.gz')) {
58
+ filename = filename + '.gz';
59
+ }
60
+
61
+ if (!filename.endsWith('.json.gz')) {
62
+ return JSON.parse(fs.readFileSync(filename, 'utf8'), reviver);
63
+ }
64
+
65
+ const buffer = gunzipSync(fs.readFileSync(filename));
66
+ return JSON.parse(buffer.toString('utf8'), reviver);
67
+ }
68
+
69
+ /**
70
+ * @param {string} filename
71
+ * @param {string} suffix
72
+ * @returns
73
+ */
74
+ function endsWithSuffix(filename, suffix) {
75
+ return filename.endsWith(suffix) || filename.endsWith(suffix + '.gz');
76
+ }
36
77
 
37
78
  /**
38
79
  * Load artifacts object from files located within basePath
@@ -48,16 +89,15 @@ function loadArtifacts(basePath) {
48
89
  }
49
90
 
50
91
  // load artifacts.json using a reviver to deserialize any LighthouseErrors in artifacts.
51
- const artifactsStr = fs.readFileSync(path.join(basePath, artifactsFilename), 'utf8');
52
92
  /** @type {LH.Artifacts} */
53
- const artifacts = JSON.parse(artifactsStr, LighthouseError.parseReviver);
93
+ const artifacts = readJson(path.join(basePath, artifactsFilename), LighthouseError.parseReviver);
54
94
 
55
95
  const filenames = fs.readdirSync(basePath);
56
96
 
57
- filenames.filter(f => f.endsWith(devtoolsLogSuffix)).forEach(filename => {
97
+ filenames.filter(f => endsWithSuffix(f, devtoolsLogSuffix)).forEach(filename => {
58
98
  if (!artifacts.devtoolsLogs) artifacts.devtoolsLogs = {};
59
- const prefix = filename.replace(devtoolsLogSuffix, '');
60
- const devtoolsLog = JSON.parse(fs.readFileSync(path.join(basePath, filename), 'utf8'));
99
+ const prefix = filename.replace(devtoolsLogSuffix + '.gz', '').replace(devtoolsLogSuffix, '');
100
+ const devtoolsLog = readJson(path.join(basePath, filename));
61
101
  artifacts.devtoolsLogs[prefix] = devtoolsLog;
62
102
  if (prefix === defaultPrefix) {
63
103
  artifacts.DevtoolsLog = devtoolsLog;
@@ -67,11 +107,10 @@ function loadArtifacts(basePath) {
67
107
  }
68
108
  });
69
109
 
70
- filenames.filter(f => f.endsWith(traceSuffix)).forEach(filename => {
110
+ filenames.filter(f => endsWithSuffix(f, traceSuffix)).forEach(filename => {
71
111
  if (!artifacts.traces) artifacts.traces = {};
72
- const file = fs.readFileSync(path.join(basePath, filename), {encoding: 'utf-8'});
73
- const trace = JSON.parse(file);
74
- const prefix = filename.replace(traceSuffix, '');
112
+ const trace = readJson(path.join(basePath, filename));
113
+ const prefix = filename.replace(traceSuffix + '.gz', '').replace(traceSuffix, '');
75
114
  artifacts.traces[prefix] = Array.isArray(trace) ? {traceEvents: trace} : trace;
76
115
  if (prefix === defaultPrefix) {
77
116
  artifacts.Trace = artifacts.traces[prefix];
@@ -200,12 +239,13 @@ async function saveFlowArtifacts(flowArtifacts, basePath) {
200
239
 
201
240
  /**
202
241
  * Save artifacts object mostly to single file located at basePath/artifacts.json.
203
- * Also save the traces & devtoolsLogs to their own files
242
+ * Also save the traces & devtoolsLogs to their own files, with optional compression.
204
243
  * @param {LH.Artifacts} artifacts
205
244
  * @param {string} basePath
245
+ * @param {{gzip?: boolean}} options
206
246
  * @return {Promise<void>}
207
247
  */
208
- async function saveArtifacts(artifacts, basePath) {
248
+ async function saveArtifacts(artifacts, basePath, options = {}) {
209
249
  const status = {msg: 'Saving artifacts', id: 'lh:assetSaver:saveArtifacts'};
210
250
  log.time(status);
211
251
  fs.mkdirSync(basePath, {recursive: true});
@@ -213,8 +253,11 @@ async function saveArtifacts(artifacts, basePath) {
213
253
  // Delete any previous artifacts in this directory.
214
254
  const filenames = fs.readdirSync(basePath);
215
255
  for (const filename of filenames) {
216
- if (filename.endsWith(traceSuffix) || filename.endsWith(devtoolsLogSuffix) ||
217
- filename === artifactsFilename) {
256
+ const isPreviousFile =
257
+ filename.endsWith(traceSuffix) || filename.endsWith(devtoolsLogSuffix) ||
258
+ filename.endsWith(traceSuffix + '.gz') || filename.endsWith(devtoolsLogSuffix + '.gz') ||
259
+ filename === artifactsFilename || filename === artifactsFilename + '.gz';
260
+ if (isPreviousFile) {
218
261
  fs.unlinkSync(`${basePath}/${filename}`);
219
262
  }
220
263
  }
@@ -234,24 +277,30 @@ async function saveArtifacts(artifacts, basePath) {
234
277
  } = artifacts;
235
278
 
236
279
  if (Trace) {
237
- await saveTrace(Trace, `${basePath}/${defaultPrefix}${traceSuffix}`);
280
+ await saveTrace(Trace, `${basePath}/${defaultPrefix}${traceSuffix}`, options);
238
281
  }
239
282
 
240
283
  if (TraceError) {
241
- await saveTrace(TraceError, `${basePath}/${errorPrefix}${traceSuffix}`);
284
+ await saveTrace(TraceError, `${basePath}/${errorPrefix}${traceSuffix}`, options);
242
285
  }
243
286
 
244
287
  if (DevtoolsLog) {
245
- await saveDevtoolsLog(DevtoolsLog, `${basePath}/${defaultPrefix}${devtoolsLogSuffix}`);
288
+ await saveDevtoolsLog(
289
+ DevtoolsLog, `${basePath}/${defaultPrefix}${devtoolsLogSuffix}`, options);
246
290
  }
247
291
 
248
292
  if (DevtoolsLogError) {
249
- await saveDevtoolsLog(DevtoolsLogError, `${basePath}/${errorPrefix}${devtoolsLogSuffix}`);
293
+ await saveDevtoolsLog(
294
+ DevtoolsLogError, `${basePath}/${errorPrefix}${devtoolsLogSuffix}`, options);
250
295
  }
251
296
 
252
297
  // save everything else, using a replacer to serialize LighthouseErrors in the artifacts.
253
- const restArtifactsString = JSON.stringify(restArtifacts, stringifyReplacer, 2) + '\n';
254
- fs.writeFileSync(`${basePath}/${artifactsFilename}`, restArtifactsString, 'utf8');
298
+ const restArtifactsString = JSON.stringify(restArtifacts, stringifyReplacer, 2);
299
+ await writeJson(function* () {
300
+ yield restArtifactsString;
301
+ yield '\n';
302
+ }, `${basePath}/${artifactsFilename}`, !!options.gzip);
303
+
255
304
  log.log('Artifacts saved to disk in folder:', basePath);
256
305
  log.timeEnd(status);
257
306
  }
@@ -371,28 +420,26 @@ function* traceJsonGenerator(traceData) {
371
420
  * Save a trace as JSON by streaming to disk at traceFilename.
372
421
  * @param {LH.Trace} traceData
373
422
  * @param {string} traceFilename
423
+ * @param {{gzip?: boolean}=} options
374
424
  * @return {Promise<void>}
375
425
  */
376
- async function saveTrace(traceData, traceFilename) {
426
+ function saveTrace(traceData, traceFilename, options = {}) {
377
427
  const traceIter = traceJsonGenerator(traceData);
378
- const writeStream = fs.createWriteStream(traceFilename);
379
-
380
- return stream.promises.pipeline(traceIter, writeStream);
428
+ return writeJson(traceIter, traceFilename, !!options.gzip);
381
429
  }
382
430
 
383
431
  /**
384
432
  * Save a devtoolsLog as JSON by streaming to disk at devtoolLogFilename.
385
433
  * @param {LH.DevtoolsLog} devtoolsLog
386
434
  * @param {string} devtoolLogFilename
435
+ * @param {{gzip?: boolean}=} options
387
436
  * @return {Promise<void>}
388
437
  */
389
- function saveDevtoolsLog(devtoolsLog, devtoolLogFilename) {
390
- const writeStream = fs.createWriteStream(devtoolLogFilename);
391
-
392
- return stream.promises.pipeline(function* () {
438
+ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename, options = {}) {
439
+ return writeJson(function* () {
393
440
  yield* arrayOfObjectsJsonGenerator(devtoolsLog);
394
441
  yield '\n';
395
- }, writeStream);
442
+ }, devtoolLogFilename, !!options.gzip);
396
443
  }
397
444
 
398
445
  /**
@@ -402,7 +449,7 @@ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename) {
402
449
  async function saveLanternDebugTraces(pathWithBasename) {
403
450
  if (!process.env.LANTERN_DEBUG) return;
404
451
 
405
- for (const [label, nodeTimings] of Simulator.ALL_NODE_TIMINGS) {
452
+ for (const [label, nodeTimings] of Lantern.Simulation.Simulator.ALL_NODE_TIMINGS) {
406
453
  if (lanternTraceSaver.simulationNamesToIgnore.includes(label)) continue;
407
454
 
408
455
  const traceFilename = `${pathWithBasename}-${label}${traceSuffix}`;
@@ -380,7 +380,7 @@ const UIStrings = {
380
380
  /**
381
381
  * @description Description text for not restored reason NotMainFrame.
382
382
  */
383
- contentWebAuthenticationAPI: 'Pages that use WebAuthetication API are not eligible for back/forward cache.',
383
+ contentWebAuthenticationAPI: 'Pages that use WebAuthentication API are not eligible for back/forward cache.',
384
384
  /**
385
385
  * @description Description text for not restored reason NotMainFrame.
386
386
  */
@@ -674,4 +674,4 @@ const NotRestoredReasonDescription = {
674
674
  export {
675
675
  NotRestoredReasonDescription,
676
676
  UIStrings,
677
- };
677
+ };
@@ -2,7 +2,7 @@
2
2
  * A union of all types derived from BaseNode, allowing type check discrimination
3
3
  * based on `node.type`. If a new node type is created, it should be added here.
4
4
  */
5
- export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>;
5
+ export type Node<T = any> = import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>;
6
6
  /**
7
7
  * @license
8
8
  * Copyright 2017 Google LLC
@@ -12,7 +12,7 @@ export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./netwo
12
12
  * A union of all types derived from BaseNode, allowing type check discrimination
13
13
  * based on `node.type`. If a new node type is created, it should be added here.
14
14
  * @template [T=any]
15
- * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
15
+ * @typedef {import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>} Node
16
16
  */
17
17
  /**
18
18
  * @fileoverview This class encapsulates logic for handling resources and tasks used to model the
@@ -30,6 +30,10 @@ export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./netwo
30
30
  * @template [T=any]
31
31
  */
32
32
  export class BaseNode<T = any> {
33
+ static TYPES: {
34
+ NETWORK: 'network';
35
+ CPU: 'cpu';
36
+ };
33
37
  /**
34
38
  * Returns whether the given node has a cycle in its dependent graph by performing a DFS.
35
39
  * @param {Node} node
@@ -156,10 +160,4 @@ export class BaseNode<T = any> {
156
160
  */
157
161
  canDependOn(node: Node): boolean;
158
162
  }
159
- export namespace BaseNode {
160
- namespace TYPES {
161
- const NETWORK: 'network';
162
- const CPU: 'cpu';
163
- }
164
- }
165
- //# sourceMappingURL=base-node.d.ts.map
163
+ //# sourceMappingURL=BaseNode.d.ts.map
@@ -8,7 +8,7 @@
8
8
  * A union of all types derived from BaseNode, allowing type check discrimination
9
9
  * based on `node.type`. If a new node type is created, it should be added here.
10
10
  * @template [T=any]
11
- * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
11
+ * @typedef {import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>} Node
12
12
  */
13
13
 
14
14
  /**
@@ -28,6 +28,11 @@
28
28
  * @template [T=any]
29
29
  */
30
30
  class BaseNode {
31
+ static TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({
32
+ NETWORK: 'network',
33
+ CPU: 'cpu',
34
+ });
35
+
31
36
  /**
32
37
  * @param {string} id
33
38
  */
@@ -361,9 +366,4 @@ class BaseNode {
361
366
  }
362
367
  }
363
368
 
364
- BaseNode.TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({
365
- NETWORK: 'network',
366
- CPU: 'cpu',
367
- });
368
-
369
369
  export {BaseNode};