Repository: GoogleChrome/lighthouse
Pull request #5698 (2018-07-20 18:56:53)

report: link to our own "unused css" reference doc
LMK if `report:` is the correct commit tag to use...

wardpeet: Report is good 👍 , you can find our commit linting values here
https://github.com/GoogleChrome/lighthouse/blob/master/.cz-config.js

LGTM :)

googlebot: So there's good news and bad news.

:thumbsup: The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so.  Everything is all good there.

:confused: The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter.  We need to confirm that all authors are ok with their commits being contributed to this project.  Please have them confirm that here in the pull request.

*Note to project maintainer: This is a terminal state, meaning the `cla/google` commit status will not change from this state. It's up to you to confirm consent of the commit author(s) and merge this pull request when appropriate.*

<!-- need_author_consent -->

Patch:
diff --git a/lighthouse-core/audits/byte-efficiency/unused-css-rules.js b/lighthouse-core/audits/byte-efficiency/unused-css-rules.js
index 8858ddaa7..347af4d40 100644
--- a/lighthouse-core/audits/byte-efficiency/unused-css-rules.js
+++ b/lighthouse-core/audits/byte-efficiency/unused-css-rules.js
@@ -23,7 +23,7 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
       scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC,
       description: 'Remove unused rules from stylesheets to reduce unnecessary ' +
           'bytes consumed by network activity. ' +
-          '[Learn more](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery).',
+          '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).',
       requiredArtifacts: ['CSSUsage', 'URL', 'devtoolsLogs'],
     };
   }
diff --git a/lighthouse-core/audits/time-to-first-byte.js b/lighthouse-core/audits/time-to-first-byte.js
index 244ac31af..3bbebbc0c 100644
--- a/lighthouse-core/audits/time-to-first-byte.js
+++ b/lighthouse-core/audits/time-to-first-byte.js
@@ -35,46 +35,32 @@ class TTFBMetric extends Audit {
    * @param {LH.Artifacts} artifacts
    * @return {Promise<LH.Audit.Product>}
    */
-  static audit(artifacts) {
-    const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+  static async audit(artifacts) {
+    const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
+    const mainResource = await artifacts.requestMainResource({devtoolsLog, URL: artifacts.URL});
 
-    return artifacts.requestNetworkRecords(devtoolsLogs)
-      .then((networkRecords) => {
-        /** @type {LH.Audit.DisplayValue} */
-        let displayValue = '';
+    const ttfb = TTFBMetric.caclulateTTFB(mainResource);
+    const passed = ttfb < TTFB_THRESHOLD;
 
-        const finalUrl = artifacts.URL.finalUrl;
-        const finalUrlRequest = networkRecords.find(record => record.url === finalUrl);
-        if (!finalUrlRequest) {
-          throw new Error(`finalUrl '${finalUrl} not found in network records.`);
-        }
-        const ttfb = TTFBMetric.caclulateTTFB(finalUrlRequest);
-        const passed = ttfb < TTFB_THRESHOLD;
-
-        if (!passed) {
-          displayValue = ['Root document took %10d', ttfb];
-        }
-
-        /** @type {LH.Result.Audit.OpportunityDetails} */
-        const details = {
-          type: 'opportunity',
-          overallSavingsMs: ttfb - TTFB_THRESHOLD,
-          headings: [],
-          items: [],
-        };
+    /** @type {LH.Result.Audit.OpportunityDetails} */
+    const details = {
+      type: 'opportunity',
+      overallSavingsMs: ttfb - TTFB_THRESHOLD,
+      headings: [],
+      items: [],
+    };
 
-        return {
-          rawValue: ttfb,
-          score: Number(passed),
-          displayValue,
-          details,
-          extendedInfo: {
-            value: {
-              wastedMs: ttfb - TTFB_THRESHOLD,
-            },
-          },
-        };
-      });
+    return {
+      rawValue: ttfb,
+      score: Number(passed),
+      displayValue: passed ? '' : ['Root document took %10d', ttfb],
+      details,
+      extendedInfo: {
+        value: {
+          wastedMs: ttfb - TTFB_THRESHOLD,
+        },
+      },
+    };
   }
 }
 


Test patch:
diff --git a/lighthouse-core/test/audits/time-to-first-byte-test.js b/lighthouse-core/test/audits/time-to-first-byte-test.js
index 5a668ae7d..d1f4258c0 100644
--- a/lighthouse-core/test/audits/time-to-first-byte-test.js
+++ b/lighthouse-core/test/audits/time-to-first-byte-test.js
@@ -11,14 +11,15 @@ const assert = require('assert');
 /* eslint-env jest */
 describe('Performance: time-to-first-byte audit', () => {
   it('fails when ttfb of root document is higher than 600ms', () => {
-    const networkRecords = [
-      {url: 'https://example.com/', requestId: '0', timing: {receiveHeadersEnd: 830, sendEnd: 200}},
-      {url: 'https://google.com/styles.css', requestId: '1', timing: {receiveHeadersEnd: 450, sendEnd: 200}},
-      {url: 'https://google.com/image.jpg', requestId: '2', timing: {receiveHeadersEnd: 600, sendEnd: 400}},
-    ];
+    const mainResource = {
+      url: 'https://example.com/',
+      requestId: '0',
+      timing: {receiveHeadersEnd: 830, sendEnd: 200},
+    };
+
     const artifacts = {
       devtoolsLogs: {[TimeToFirstByte.DEFAULT_PASS]: []},
-      requestNetworkRecords: () => Promise.resolve(networkRecords),
+      requestMainResource: () => Promise.resolve(mainResource),
       URL: {finalUrl: 'https://example.com/'},
     };
 
@@ -29,14 +30,15 @@ describe('Performance: time-to-first-byte audit', () => {
   });
 
   it('succeeds when ttfb of root document is lower than 600ms', () => {
-    const networkRecords = [
-      {url: 'https://example.com/', requestId: '0', timing: {receiveHeadersEnd: 400, sendEnd: 200}},
-      {url: 'https://google.com/styles.css', requestId: '1', timing: {receiveHeadersEnd: 850, sendEnd: 200}},
-      {url: 'https://google.com/image.jpg', requestId: '2', timing: {receiveHeadersEnd: 1000, sendEnd: 400}},
-    ];
+    const mainResource = {
+      url: 'https://example.com/',
+      requestId: '0',
+      timing: {receiveHeadersEnd: 400, sendEnd: 200},
+    };
+
     const artifacts = {
       devtoolsLogs: {[TimeToFirstByte.DEFAULT_PASS]: []},
-      requestNetworkRecords: () => Promise.resolve(networkRecords),
+      requestMainResource: () => Promise.resolve(mainResource),
       URL: {finalUrl: 'https://example.com/'},
     };
 
@@ -45,25 +47,4 @@ describe('Performance: time-to-first-byte audit', () => {
       assert.strictEqual(result.score, 1);
     });
   });
-
-  it('throws when somehow finalUrl is not in network records', async () => {
-    const networkRecords = [
-      {url: 'https://example.com/', requestId: '0', timing: {receiveHeadersEnd: 400, sendEnd: 200}},
-      {url: 'https://google.com/styles.css', requestId: '1', timing: {receiveHeadersEnd: 850, sendEnd: 200}},
-      {url: 'https://google.com/image.jpg', requestId: '2', timing: {receiveHeadersEnd: 1000, sendEnd: 400}},
-    ];
-    const badFinalUrl = 'https://badexample.com/';
-    const artifacts = {
-      devtoolsLogs: {[TimeToFirstByte.DEFAULT_PASS]: []},
-      requestNetworkRecords: () => Promise.resolve(networkRecords),
-      URL: {finalUrl: badFinalUrl},
-    };
-
-    try {
-      await TimeToFirstByte.audit(artifacts);
-      throw new Error('TimeToFirstByte did not throw');
-    } catch (e) {
-      assert.ok(e.message.includes(badFinalUrl));
-    }
-  });
 });