From 559579c4d79aa3051ae5723a5f5e9aaf763e8116 Mon Sep 17 00:00:00 2001 From: cjamcl Date: Fri, 31 May 2019 07:10:40 -0700 Subject: [PATCH 001/110] misc: release script should commit with format vX.Y.Z (#9090) --- lighthouse-core/scripts/release/prepare-commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lighthouse-core/scripts/release/prepare-commit.sh b/lighthouse-core/scripts/release/prepare-commit.sh index 1f7bd65c67c6..f143149e0c78 100755 --- a/lighthouse-core/scripts/release/prepare-commit.sh +++ b/lighthouse-core/scripts/release/prepare-commit.sh @@ -64,7 +64,7 @@ if [[ $(echo "$NEW_CONTRIBUTORS" | wc -l) -gt 1 ]]; then fi git add changelog.md lighthouse-core/test/results/ proto/ -git commit -m "$NEW_VERSION" +git commit -m "v$NEW_VERSION" echo "Version bump commit ready on the ${TXT_BOLD}$BRANCH_NAME${TXT_RESET} branch!" From 0eacf068b43f9306e9055c1d0ff19987d4fde56c Mon Sep 17 00:00:00 2001 From: Brendan Kenny Date: Fri, 31 May 2019 12:56:29 -0700 Subject: [PATCH 002/110] deps: update bundlesize, add more budgets (#9089) --- package.json | 14 +- yarn.lock | 609 ++++++++++++++++++++++----------------------------- 2 files changed, 278 insertions(+), 345 deletions(-) diff --git a/package.json b/package.json index 3fa91f0070b7..2af0149e182d 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "babel-plugin-syntax-object-rest-spread": "^6.13.0", "brfs": "^1.6.1", "browserify": "^16.2.3", - "bundlesize": "^0.14.4", + "bundlesize": "^0.17.2", "chalk": "^2.4.1", "codecov": "^3.2.0", "commitizen": "^2.10.1", @@ -180,11 +180,19 @@ "bundlesize": [ { "path": "./dist/extension/scripts/lighthouse-ext-bundle.js", - "threshold": "520 Kb" + "maxSize": "520 kB" + }, + { + "path": "./dist/lightrider/lighthouse-lr-bundle.js", + "maxSize": "1.1 MB" }, { "path": "./dist/viewer/src/viewer.js", - "threshold": "75 Kb" + "maxSize": "75 kB" + }, + { + "path": "./dist/lighthouse-dt-bundle.js", + "maxSize": "400 kB" } ], "nyc": { diff --git a/yarn.lock b/yarn.lock index 1546a5507ce0..db33cf0d9f32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -883,20 +883,6 @@ ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -amdefine@>=0.0.4: - version "1.0.0" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.0.tgz#fd17474700cb5cc9c2b709f0be9d23ce3c198c33" - integrity sha1-/RdHRwDLXMnCtwnwvp0jzjwZjDM= - angular@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/angular/-/angular-1.7.4.tgz#c1bf4884c2d470c06907737a1bf0835a9f646f31" @@ -973,6 +959,11 @@ append-transform@^1.0.0: dependencies: default-require-extensions "^2.0.0" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + archiver-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.0.0.tgz#5639818a8b5d89d0ffc51b72c39283cf4fea14a1" @@ -1009,6 +1000,14 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" @@ -1146,11 +1145,6 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async@^1.4.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - async@^2.0.0, async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" @@ -1158,18 +1152,6 @@ async@^2.0.0, async@^2.6.1: dependencies: lodash "^4.17.10" -async@^2.5.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== - dependencies: - lodash "^4.17.11" - -async@~0.2.6: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= - async@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" @@ -1207,12 +1189,12 @@ axios@0.15.3: dependencies: follow-redirects "1.0.0" -axios@^0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" - integrity sha1-uk+S8XFn37q0CYN4VFS5rBScPG0= +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI= dependencies: - follow-redirects "^1.2.3" + follow-redirects "^1.3.0" is-buffer "^1.1.5" babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: @@ -1502,6 +1484,14 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +brotli-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/brotli-size/-/brotli-size-0.1.0.tgz#a2c518096c7c1a75e9e66908a42cd9dc77d2b69f" + integrity sha512-5ny7BNvpe2TSmdafF1T9dnFYp3AIrJ8qJt29K0DQJzORlK38LBim/CmlY26JtreV6SWmXza7Oa+9m61SzvxR0Q== + dependencies: + duplexer "^0.1.1" + iltorb "^2.4.3" + browser-pack@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" @@ -1684,11 +1674,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== -buffer-shims@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - integrity sha1-mXjOMXOIxkmth5MCjDR37wRKi1E= - buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -1712,25 +1697,26 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -bundlesize@^0.14.4: - version "0.14.4" - resolved "https://registry.yarnpkg.com/bundlesize/-/bundlesize-0.14.4.tgz#ad53c4a1a4ba71810967575c550bc04f3d18d421" - integrity sha512-Qi04ADUB+FoeBD98XuSLNt54SW4onfMyuNHnyaHS6rq6/+D11RR+lzADoxFmf5ei9iu1sBqxdltAh6lbJGCT0Q== +bundlesize@^0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/bundlesize/-/bundlesize-0.17.2.tgz#d31a80ffe1591251411ad730442eb4e20790f827" + integrity sha512-cJAZ6wvs6IHQCnUn9kTme4GL+ahoICjcS0QPcGTj61Hl4bCc8wKkkVLUote4k/1yxa0+kUIrIo9wyNJ+XIciEw== dependencies: - axios "^0.16.2" - bytes "^2.5.0" + axios "^0.18.0" + brotli-size "0.1.0" + bytes "^3.1.0" ci-env "^1.4.0" - commander "^2.11.0" + commander "^2.20.0" github-build "^1.2.0" - glob "^7.1.2" - gzip-size "^3.0.0" + glob "^7.1.4" + gzip-size "^4.0.0" prettycli "^1.4.3" - read-pkg-up "^2.0.0" + read-pkg-up "^3.0.0" -bytes@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" - integrity sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo= +bytes@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== cache-base@^1.0.1: version "1.0.1" @@ -1799,11 +1785,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= - camelcase@^2.0.0, camelcase@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -1836,14 +1817,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1855,7 +1828,7 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@2.1.0, chalk@^2.0.0, chalk@^2.1.0: +chalk@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" integrity sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ== @@ -1864,16 +1837,7 @@ chalk@2.1.0, chalk@^2.0.0, chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -chalk@^2.0.1, chalk@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1896,6 +1860,11 @@ chardet@^0.4.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= +chownr@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + chrome-launcher@^0.10.7: version "0.10.7" resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.7.tgz#5e2a9e99f212e0501d9c7024802acd01a812f5d5" @@ -1969,15 +1938,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" integrity sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao= -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - cliui@^3.0.3: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -2061,15 +2021,10 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - -commander@^2.18.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@^2.18.0, commander@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== commander@~2.17.1: version "2.17.1" @@ -2193,6 +2148,11 @@ console-browserify@^1.1.0: dependencies: date-now "^0.1.4" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -2654,26 +2614,19 @@ dateformat@^1.0.11, dateformat@^1.0.12: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.3.3: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^2.2.0, debug@^2.4.5, debug@^2.6.8: - version "2.6.8" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" - integrity sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw= +debug@^3.1.0, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" + ms "^2.1.1" debug@^4.1.0, debug@^4.1.1: version "4.1.1" @@ -2682,7 +2635,7 @@ debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -2692,6 +2645,13 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + dedent@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.6.0.tgz#0e6da8f0ce52838ef5cec5c8f9396b0c1b64a3cb" @@ -2767,6 +2727,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + deps-sort@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" @@ -2804,6 +2769,11 @@ detect-indent@4.0.0, detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + detect-newline@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" @@ -3215,6 +3185,11 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expand-tilde@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" @@ -3540,12 +3515,12 @@ follow-redirects@1.0.0: dependencies: debug "^2.2.0" -follow-redirects@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.4.tgz#355e8f4d16876b43f577b0d5ce2668b9723214ea" - integrity sha512-Suw6KewLV2hReSyEOeql+UUkBVyiBm3ok1VPrVFRZnQInWpdoZbbiG5i8aJVSjTr0yQ4Ava0Sh6/joCg1Brdqw== +follow-redirects@^1.3.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== dependencies: - debug "^2.4.5" + debug "^3.2.6" for-in@^0.1.5: version "0.1.6" @@ -3631,7 +3606,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -function-bind@^1.0.2, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== @@ -3641,6 +3616,20 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + get-assigned-identifiers@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" @@ -3746,6 +3735,11 @@ github-build@^1.2.0: dependencies: axios "0.15.3" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -3774,7 +3768,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@7.1.1, glob@^7.0.5: +glob@7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" integrity sha1-gFIR3wT6rxxjo2ADBs31reULLsg= @@ -3786,22 +3780,10 @@ glob@7.1.1, glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.0, glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3903,21 +3885,11 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= - -graceful-fs@^4.1.15, graceful-fs@^4.1.9: +graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -graceful-fs@^4.1.2: - version "4.1.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.9.tgz#baacba37d19d11f9d146d3578bc99958c3787e29" - integrity sha1-uqy6N9GdEfnRRtNXi8mZWMN4fik= - "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -3933,30 +3905,20 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -gzip-size@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520" - integrity sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA= +gzip-size@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-4.1.0.tgz#8ae096257eabe7d69c45be2b67c448124ffb517c" + integrity sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw= dependencies: duplexer "^0.1.1" + pify "^3.0.0" -handlebars@^4.0.2: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= - dependencies: - async "^1.4.0" - optimist "^0.6.1" - source-map "^0.4.4" - optionalDependencies: - uglify-js "^2.6" - -handlebars@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" - integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== +handlebars@^4.0.2, handlebars@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== dependencies: - async "^2.5.0" + neo-async "^2.6.0" optimist "^0.6.1" source-map "^0.6.1" optionalDependencies: @@ -3997,6 +3959,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -4028,20 +3995,13 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.0: +has@^1.0.0, has@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - integrity sha1-hGFzP1OLCDfJNh45qauelwTcLyg= - dependencies: - function-bind "^1.0.2" - hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -4175,16 +4135,22 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3: - version "3.3.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" - integrity sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw== - -ignore@^3.3.5: +ignore@^3.3.3, ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== +iltorb@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/iltorb/-/iltorb-2.4.3.tgz#b489689d24c8a25a2cf170c515f97954edd45577" + integrity sha512-cr/kC07Cf9sW3TWH7yUxV2QkNjby4LMCsXGmxPCQs5x//QzTpF3GLPNY7L66G+DkNGaTRCgY+vYZ+dyAcuDOnQ== + dependencies: + detect-libc "^1.0.3" + nan "^2.13.2" + npmlog "^4.1.2" + prebuild-install "^5.3.0" + which-pm-runs "^1.0.0" + image-ssim@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" @@ -4383,12 +4349,7 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-buffer@^1.0.2, is-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" - integrity sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw= - -is-buffer@^1.1.0: +is-buffer@^1.0.2, is-buffer@^1.1.0, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -4711,11 +4672,6 @@ isarray@^2.0.4: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.4.tgz#38e7bcbb0f3ba1b7933c86ba1894ddfc3781bbb7" integrity sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA== -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" - integrity sha1-NvPiLmB1CSD15yQaR2qMakInWtA= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5446,11 +5402,6 @@ latest-version@^3.0.0: dependencies: package-json "^4.0.0" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= - lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -5495,14 +5446,7 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lighthouse-logger@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.0.0.tgz#c6abdfbbbf0b4a541ab33864802cbad8944bcc8c" - integrity sha1-xqvfu78LSlQaszhkgCy62JRLzIw= - dependencies: - debug "^2.6.8" - -lighthouse-logger@^1.2.0: +lighthouse-logger@^1.0.0, lighthouse-logger@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz#b76d56935e9c137e86a04741f6bb9b2776e886ca" integrity sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw== @@ -5521,16 +5465,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -5915,6 +5849,11 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -6003,6 +5942,11 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +nan@^2.13.2: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + nanomatch@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" @@ -6021,11 +5965,21 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" + integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + nested-error-stacks@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" @@ -6036,6 +5990,13 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-abi@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.8.0.tgz#bd2e88dbe6a6871e6dd08553e0605779325737ec" + integrity sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ== + dependencies: + semver "^5.4.1" + node-fetch@1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" @@ -6090,6 +6051,11 @@ node-notifier@^5.2.1: chalk "~0.4.0" underscore "~1.6.0" +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= + normalize-package-data@^2.3.0, normalize-package-data@^2.3.5: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" @@ -6149,6 +6115,16 @@ npm-run-posix-or-windows@^2.0.2: resolved "https://registry.yarnpkg.com/npm-run-posix-or-windows/-/npm-run-posix-or-windows-2.0.2.tgz#74e894702ae34ea338502d04b500c1dec836736e" integrity sha1-dOiUcCrjTqM4UC0EtQDB3sg2c24= +npmlog@^4.0.1, npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -6585,13 +6561,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -6681,6 +6650,28 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +prebuild-install@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^2.0.1" + rc "^1.2.7" + simple-get "^2.7.0" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -6787,6 +6778,22 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -6896,7 +6903,7 @@ raven@^2.2.1: timed-out "4.0.1" uuid "3.0.0" -rc@^1.0.1, rc@^1.1.6: +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -6929,13 +6936,13 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= dependencies: find-up "^2.0.0" - read-pkg "^2.0.0" + read-pkg "^3.0.0" read-pkg-up@^4.0.0: version "4.0.0" @@ -6954,15 +6961,6 @@ read-pkg@^1.0.0, read-pkg@^1.1.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -6972,7 +6970,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.3: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -6985,32 +6983,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.0, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^2.0.1: - version "2.1.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" - integrity sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA= - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - readable-stream@~2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" @@ -7260,13 +7232,6 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= - dependencies: - align-text "^0.1.1" - right-pad@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/right-pad/-/right-pad-1.0.1.tgz#8ca08c2cbb5b55e74dafa96bf7fd1a27d568c8d0" @@ -7421,7 +7386,7 @@ semver@^5.5.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== -set-blocking@^2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -7518,6 +7483,15 @@ simple-concat@^1.0.0: resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + sisteransi@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" @@ -7608,13 +7582,6 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - integrity sha1-66T12pwNyZneaAMti092FzZSA2s= - dependencies: - amdefine ">=0.0.4" - source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -7829,15 +7796,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - integrity sha1-Y1xUNsxypuDDh87KJ41OLuxSaH4= - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - -string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -7857,13 +7816,6 @@ string_decoder@~0.10.x: resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ== - dependencies: - safe-buffer "~5.1.0" - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -8003,7 +7955,17 @@ table@4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" -tar-stream@^1.5.0: +tar-fs@^1.13.0: + version "1.16.3" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2, tar-stream@^1.5.0: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== @@ -8276,16 +8238,6 @@ uglify-es@3.0.15: commander "~2.9.0" source-map "~0.5.1" -uglify-js@^2.6: - version "2.7.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.3.tgz#39b3a7329b89f5ec507e344c6e22568698ef4868" - integrity sha1-ObOnMpuJ9exQfjRMbiJWhpjvSGg= - dependencies: - async "~0.2.6" - source-map "~0.5.1" - uglify-to-browserify "~1.0.0" - yargs "~3.10.0" - uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" @@ -8294,11 +8246,6 @@ uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= - ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -8568,26 +8515,24 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.12: +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + +which@^1.2.12, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -which@^1.2.9: - version "1.2.11" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.11.tgz#c8b2eeea6b8c1659fa7c1dd4fdaabe9533dc5e8b" - integrity sha1-yLLu6muMFln6fB3U/aq+lTPcXos= - dependencies: - isexe "^1.1.1" - -which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: - isexe "^2.0.0" + string-width "^1.0.2 || 2" widest-line@^2.0.0: version "2.0.1" @@ -8596,11 +8541,6 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= - window-size@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" @@ -8629,11 +8569,6 @@ word-wrap@^1.0.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" @@ -8807,16 +8742,6 @@ yargs@^12.0.2, yargs@^12.0.5: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" From 450d36032124811125ffde513c13b85b0ee80883 Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Fri, 31 May 2019 21:25:02 -0500 Subject: [PATCH 003/110] core(manifest-parser): handle blob manifests (#9088) --- lighthouse-core/lib/manifest-parser.js | 53 +++++++--- .../test/lib/manifest-parser-test.js | 97 +++++++++++++------ 2 files changed, 107 insertions(+), 43 deletions(-) diff --git a/lighthouse-core/lib/manifest-parser.js b/lighthouse-core/lib/manifest-parser.js index 763910cfd4b0..64d4fd06b52d 100644 --- a/lighthouse-core/lib/manifest-parser.js +++ b/lighthouse-core/lib/manifest-parser.js @@ -16,7 +16,7 @@ const ALLOWED_DISPLAY_VALUES = [ ]; /** * All display-mode fallbacks, including when unset, lead to default display mode 'browser'. - * @see https://w3c.github.io/manifest/#dfn-default-display-mode + * @see https://www.w3.org/TR/2016/WD-appmanifest-20160825/#dfn-default-display-mode */ const DEFAULT_DISPLAY_MODE = 'browser'; @@ -111,7 +111,7 @@ function checkSameOrigin(url1, url2) { } /** - * https://w3c.github.io/manifest/#start_url-member + * https://www.w3.org/TR/2016/WD-appmanifest-20160825/#start_url-member * @param {*} jsonInput * @param {string} manifestUrl * @param {string} documentUrl @@ -151,7 +151,7 @@ function parseStartUrl(jsonInput, manifestUrl, documentUrl) { return { raw, value: documentUrl, - warning: 'ERROR: invalid start_url relative to ${manifestUrl}', + warning: `ERROR: invalid start_url relative to ${manifestUrl}`, }; } @@ -218,6 +218,7 @@ function parseOrientation(jsonInput) { } /** + * @see https://www.w3.org/TR/2016/WD-appmanifest-20160825/#src-member * @param {*} raw * @param {string} manifestUrl */ @@ -229,8 +230,14 @@ function parseIcon(raw, manifestUrl) { src.value = undefined; } if (src.value) { - // 9.4(4) - construct URL with manifest URL as the base - src.value = new URL(src.value, manifestUrl).href; + try { + // 9.4(4) - construct URL with manifest URL as the base + src.value = new URL(src.value, manifestUrl).href; + } catch (_) { + // 9.4 "This algorithm will return a URL or undefined." + src.warning = `ERROR: invalid icon url will be ignored: '${raw.src}'`; + src.value = undefined; + } } const type = parseString(raw.type, true); @@ -301,20 +308,31 @@ function parseIcons(jsonInput, manifestUrl) { }; } - // TODO(bckenny): spec says to skip icons missing `src`, so debug messages on - // individual icons are lost. Warn instead? - const value = raw + const parsedIcons = raw // 9.6(3)(1) .filter(icon => icon.src !== undefined) // 9.6(3)(2)(1) - .map(icon => parseIcon(icon, manifestUrl)) + .map(icon => parseIcon(icon, manifestUrl)); + + // NOTE: we still lose the specific message on these icons, but it's not possible to surface them + // without a massive change to the structure and paradigms of `manifest-parser`. + const ignoredIconsWithWarnings = parsedIcons + .filter(icon => { + const possibleWarnings = [icon.warning, icon.value.type.warning, icon.value.src.warning, + icon.value.sizes.warning, icon.value.density.warning].filter(Boolean); + const hasSrc = !!icon.value.src.value; + return !!possibleWarnings.length && !hasSrc; + }); + + const value = parsedIcons // 9.6(3)(2)(2) .filter(parsedIcon => parsedIcon.value.src.value !== undefined); return { raw, value, - warning: undefined, + warning: ignoredIconsWithWarnings.length ? + 'WARNING: Some icons were ignored due to warnings.' : undefined, }; } @@ -333,7 +351,7 @@ function parseApplication(raw) { appUrl.value = new URL(appUrl.value).href; } catch (e) { appUrl.value = undefined; - appUrl.warning = 'ERROR: invalid application URL ${raw.url}'; + appUrl.warning = `ERROR: invalid application URL ${raw.url}`; } } @@ -460,10 +478,21 @@ function parse(string, manifestUrl, documentUrl) { }; /* eslint-enable camelcase */ + /** @type {string|undefined} */ + let manifestUrlWarning; + try { + const manifestUrlParsed = new URL(manifestUrl); + if (!manifestUrlParsed.protocol.startsWith('http')) { + manifestUrlWarning = `WARNING: manifest URL not available over a valid network protocol`; + } + } catch (_) { + manifestUrlWarning = `ERROR: invalid manifest URL: '${manifestUrl}'`; + } + return { raw: string, value: manifest, - warning: undefined, + warning: manifestUrlWarning, }; } diff --git a/lighthouse-core/test/lib/manifest-parser-test.js b/lighthouse-core/test/lib/manifest-parser-test.js index 9f4fa38e405b..9a93de8a1940 100644 --- a/lighthouse-core/test/lib/manifest-parser-test.js +++ b/lighthouse-core/test/lib/manifest-parser-test.js @@ -11,6 +11,7 @@ const manifestStub = require('../fixtures/manifest.json'); const EXAMPLE_MANIFEST_URL = 'https://example.com/manifest.json'; const EXAMPLE_DOC_URL = 'https://example.com/index.html'; +const EXAMPLE_MANIFEST_BLOB_URL = 'blob:https://example.com/manifest.json'; /** * Simple manifest parsing helper when the manifest URLs aren't material to the @@ -27,32 +28,48 @@ function noUrlManifestParser(manifestSrc) { describe('Manifest Parser', function() { it('should not parse empty string input', function() { const parsedManifest = noUrlManifestParser(''); - assert.ok(parsedManifest.warning); + expect(parsedManifest.warning) + .toEqual('ERROR: file isn\'t valid JSON: SyntaxError: Unexpected end of JSON input'); }); it('accepts empty dictionary', function() { const parsedManifest = noUrlManifestParser('{}'); - assert(!parsedManifest.warning); - assert.equal(parsedManifest.value.name.value, undefined); - assert.equal(parsedManifest.value.short_name.value, undefined); - assert.equal(parsedManifest.value.start_url.value, EXAMPLE_DOC_URL); - assert.equal(parsedManifest.value.display.value, 'browser'); - assert.equal(parsedManifest.value.orientation.value, undefined); - assert.equal(parsedManifest.value.theme_color.value, undefined); - assert.equal(parsedManifest.value.background_color.value, undefined); - assert.ok(Array.isArray(parsedManifest.value.icons.value)); - assert.ok(parsedManifest.value.icons.value.length === 0); + expect(parsedManifest.warning).toBeUndefined(); + expect(parsedManifest.value.name.value).toBe(undefined); + expect(parsedManifest.value.short_name.value).toBe(undefined); + expect(parsedManifest.value.start_url.value).toBe(EXAMPLE_DOC_URL); + expect(parsedManifest.value.display.value).toBe('browser'); + expect(parsedManifest.value.orientation.value).toBe(undefined); + expect(parsedManifest.value.theme_color.value).toBe(undefined); + expect(parsedManifest.value.background_color.value).toBe(undefined); + expect(parsedManifest.value.icons.value).toHaveLength(0); // TODO: // related_applications // prefer_related_applications }); + it('should warn on invalid manifest parser URL', function() { + const parsedManifest = manifestParser('{}', 'not a URL', EXAMPLE_DOC_URL); + expect(parsedManifest.warning) + .toEqual('ERROR: invalid manifest URL: \'not a URL\''); + }); + + it('should warn on valid but non-(HTTP|HTTPS) manifest parser URL', function() { + const parsedManifest = manifestParser('{}', EXAMPLE_MANIFEST_BLOB_URL, EXAMPLE_DOC_URL); + expect(parsedManifest.warning) + .toEqual('WARNING: manifest URL not available over a valid network protocol'); + }); + describe('icon parsing', function() { // 9.7 it('gives an empty array and an error for erroneous icons entry', () => { - const parsedManifest = manifestParser('{"icons": {"16": "img/icons/icon16.png"}}', - EXAMPLE_MANIFEST_URL, EXAMPLE_DOC_URL); - assert.ok(!parsedManifest.warning); + const parsedManifest = manifestParser( + '{"icons": {"16": "img/icons/icon16.png"}}', + EXAMPLE_MANIFEST_URL, + EXAMPLE_DOC_URL + ); + + expect(parsedManifest.warning).toBeUndefined(); const icons = parsedManifest.value.icons; assert.ok(Array.isArray(icons.value)); assert.equal(icons.value.length, 0); @@ -60,9 +77,8 @@ describe('Manifest Parser', function() { }); it('gives an empty array and no error for missing icons entry', () => { - const parsedManifest = manifestParser('{}', - EXAMPLE_MANIFEST_URL, EXAMPLE_DOC_URL); - assert.ok(!parsedManifest.warning); + const parsedManifest = manifestParser('{}', EXAMPLE_MANIFEST_URL, EXAMPLE_DOC_URL); + expect(parsedManifest.warning).toBeUndefined(); const icons = parsedManifest.value.icons; assert.ok(Array.isArray(icons.value)); assert.equal(icons.value.length, 0); @@ -70,9 +86,12 @@ describe('Manifest Parser', function() { }); it('parses basic string', function() { - const parsedManifest = manifestParser('{"icons": [{"src": "192.png", "sizes": "192x192"}]}', - EXAMPLE_MANIFEST_URL, EXAMPLE_DOC_URL); - assert(!parsedManifest.warning); + const parsedManifest = manifestParser( + '{"icons": [{"src": "192.png", "sizes": "192x192"}]}', + EXAMPLE_MANIFEST_URL, + EXAMPLE_DOC_URL + ); + expect(parsedManifest.warning).toBeUndefined(); const icons = parsedManifest.value.icons; assert(!icons.warning); const icon192 = icons.value[0]; @@ -81,9 +100,12 @@ describe('Manifest Parser', function() { }); it('finds four icons in the stub manifest', function() { - const parsedManifest = manifestParser(JSON.stringify(manifestStub), EXAMPLE_MANIFEST_URL, - EXAMPLE_DOC_URL); - assert(!parsedManifest.warning); + const parsedManifest = manifestParser( + JSON.stringify(manifestStub), + EXAMPLE_MANIFEST_URL, + EXAMPLE_DOC_URL + ); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.icons.value.length, 4); }); @@ -110,6 +132,19 @@ describe('Manifest Parser', function() { assert.equal(icons.value.length, 0); }); + it('parses icons and discards any with invalid base URL values', () => { + const manifestSrc = JSON.stringify({ + icons: [{ + src: '/valid/path', + }], + }); + const parsedManifest = manifestParser(manifestSrc, EXAMPLE_MANIFEST_BLOB_URL, + EXAMPLE_DOC_URL); + const icons = parsedManifest.value.icons; + expect(icons.value).toHaveLength(0); + expect(icons.warning).toEqual('WARNING: Some icons were ignored due to warnings.'); + }); + it('parses icons and discards any with undefined or empty string src values', () => { const manifestSrc = JSON.stringify({ icons: [{ @@ -139,23 +174,23 @@ describe('Manifest Parser', function() { describe('name parsing', function() { it('parses basic string', function() { const parsedManifest = noUrlManifestParser('{"name":"foo"}'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.name.value, 'foo'); }); it('trims whitespaces', function() { const parsedManifest = noUrlManifestParser('{"name":" foo "}'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.name.value, 'foo'); }); it('doesn\'t parse non-string', function() { let parsedManifest = noUrlManifestParser('{"name": {} }'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.name.value, undefined); parsedManifest = noUrlManifestParser('{"name": 42 }'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.name.value, undefined); }); }); @@ -163,23 +198,23 @@ describe('Manifest Parser', function() { describe('short_name parsing', function() { it('parses basic string', function() { const parsedManifest = noUrlManifestParser('{"short_name":"foo"}'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.short_name.value, 'foo'); }); it('trims whitespaces', function() { const parsedManifest = noUrlManifestParser('{"short_name":" foo "}'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.short_name.value, 'foo'); }); it('doesn\'t parse non-string', function() { let parsedManifest = noUrlManifestParser('{"short_name": {} }'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.short_name.value, undefined); parsedManifest = noUrlManifestParser('{"short_name": 42 }'); - assert(!parsedManifest.warning); + expect(parsedManifest.warning).toBeUndefined(); assert.equal(parsedManifest.value.short_name.value, undefined); }); }); From 2cc59c7e11a02167dbedbae046ec5dc0c648529e Mon Sep 17 00:00:00 2001 From: cjamcl Date: Mon, 3 Jun 2019 11:01:09 -0700 Subject: [PATCH 004/110] devtools: rename audits2 to audits (#8985) --- clients/devtools-report-assets.js | 8 ++++---- lighthouse-core/report/html/readme.md | 2 +- lighthouse-core/scripts/compile-against-devtools.sh | 10 +++++----- lighthouse-core/scripts/roll-to-devtools.sh | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clients/devtools-report-assets.js b/clients/devtools-report-assets.js index a94320496734..58b80f645f2b 100644 --- a/clients/devtools-report-assets.js +++ b/clients/devtools-report-assets.js @@ -17,8 +17,8 @@ const cachedResources = Runtime.cachedResources; module.exports = { - REPORT_CSS: cachedResources['audits2/lighthouse/report.css'], - REPORT_JAVASCRIPT: cachedResources['audits2/lighthouse/report.js'], - REPORT_TEMPLATE: cachedResources['audits2/lighthouse/template.html'], - REPORT_TEMPLATES: cachedResources['audits2/lighthouse/templates.html'], + REPORT_CSS: cachedResources['audits/lighthouse/report.css'], + REPORT_JAVASCRIPT: cachedResources['audits/lighthouse/report.js'], + REPORT_TEMPLATE: cachedResources['audits/lighthouse/template.html'], + REPORT_TEMPLATES: cachedResources['audits/lighthouse/templates.html'], }; diff --git a/lighthouse-core/report/html/readme.md b/lighthouse-core/report/html/readme.md index 3f56c76fdb20..3cc71c1ca526 100644 --- a/lighthouse-core/report/html/readme.md +++ b/lighthouse-core/report/html/readme.md @@ -32,7 +32,7 @@ The renderer was designed to be portable across various environments. 1. _LH Chrome Extension_: It [creates the HTML as the runner finishes up](https://github.com/GoogleChrome/lighthouse/blob/440155cdda377c458c0efce006bc3a69ce2a351c/lighthouse-core/runner.js#L137-L138) and transforms it [into a blob url in the background page](https://github.com/GoogleChrome/lighthouse/blob/440155cdda377c458c0efce006bc3a69ce2a351c/lighthouse-extension/app/src/lighthouse-ext-background.js#L129-L143). 1. _LH CLI_: It [creates the HTML as the runner finishes up](https://github.com/GoogleChrome/lighthouse/blob/440155cdda377c458c0efce006bc3a69ce2a351c/lighthouse-core/runner.js#L137-L138) and [saves it to disk](https://github.com/GoogleChrome/lighthouse/blob/440155cdda377c458c0efce006bc3a69ce2a351c/lighthouse-cli/printer.js#L71-L92). -1. _Chrome DevTools Audits Panel_: The `renderer` files are rolled into the Chromium repo, and they execute within the DevTools context. The audits panel [receives the LHR object from a WebWorker](https://github.com/ChromeDevTools/devtools-frontend/blob/master/front_end/audits2/Audits2ProtocolService.js#L27-L35), through a `postMessage` and then runs [the renderer within DevTools UI](https://github.com/ChromeDevTools/devtools-frontend/blob/fee00605cada877c1f8e3aae758a0f8d05b64476/front_end/audits2/Audits2Panel.js#L519-L542), making a few upgrades ([one](https://github.com/ChromeDevTools/devtools-frontend/blob/fee00605cada877c1f8e3aae758a0f8d05b64476/front_end/audits2/Audits2Panel.js#L570-L583), [two](https://github.com/ChromeDevTools/devtools-frontend/blob/fee00605cada877c1f8e3aae758a0f8d05b64476/front_end/audits2/Audits2Panel.js#L596-L637)) and [simplifications](https://github.com/ChromeDevTools/devtools-frontend/blob/fee00605cada877c1f8e3aae758a0f8d05b64476/front_end/audits2/Audits2Panel.js#L275-L304). +1. _Chrome DevTools Audits Panel_: The `renderer` files are rolled into the Chromium repo, and they execute within the DevTools context. The audits panel [receives the LHR object from a WebWorker](https://github.com/ChromeDevTools/devtools-frontend/blob/aa1532c2f8bdc37c9886255644ed90ad01c61c77/front_end/audits/AuditsProtocolService.js#L27-L35), through a `postMessage` and then runs [the renderer within DevTools UI](https://github.com/ChromeDevTools/devtools-frontend/blob/aa1532c2f8bdc37c9886255644ed90ad01c61c77/front_end/audits/AuditsPanel.js#L123-L157), making a few [simplifications](https://github.com/ChromeDevTools/devtools-frontend/blob/master/front_end/audits/AuditsReportRenderer.js). 1. _Hosted [Lighthouse Viewer](https://googlechrome.github.io/lighthouse/viewer/)_: It's a webapp that has the renderer (along with some [additional features](https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-core/report/html/renderer/report-ui-features.js)) all compiled into a [`viewer.js`](https://googlechrome.github.io/lighthouse/viewer/src/viewer.js) file. Same [basic approach](https://github.com/GoogleChrome/lighthouse/blob/440155cdda377c458c0efce006bc3a69ce2a351c/lighthouse-viewer/app/src/lighthouse-report-viewer.js#L116-L117) there. ### Polyfills diff --git a/lighthouse-core/scripts/compile-against-devtools.sh b/lighthouse-core/scripts/compile-against-devtools.sh index d072579e84e2..49151e3ef637 100644 --- a/lighthouse-core/scripts/compile-against-devtools.sh +++ b/lighthouse-core/scripts/compile-against-devtools.sh @@ -13,7 +13,7 @@ set -x # This the text here will override the renderer/ files in in the scripts[] array: -# https://github.com/ChromeDevTools/devtools-frontend/blob/master/front_end/audits2/module.json#L20 +# https://github.com/ChromeDevTools/devtools-frontend/blob/master/front_end/audits/module.json#L20 # (Currently this doesnt include logger or report-features) files_to_include="\"lighthouse\/renderer\/util.js\", \"lighthouse\/renderer\/dom.js\", \"lighthouse\/renderer\/category-renderer.js\", \"lighthouse\/renderer\/performance-category-renderer.js\", \"lighthouse\/renderer\/crc-details-renderer.js\", \"lighthouse\/renderer\/details-renderer.js\", \"lighthouse\/renderer\/report-renderer.js\"," @@ -54,13 +54,13 @@ cd "$lhroot_path" || exit 1 yarn devtools "$frontend_path/front_end/" # -# monkeypatch the audits2 module.json to include any new files we're added that aren't present +# monkeypatch the audits module.json to include any new files we're added that aren't present # -audit2_modulejson_path="$frontend_path/front_end/audits2/module.json" +audit_modulejson_path="$frontend_path/front_end/audits/module.json" # remove existing renderer file mentions -sed -i='' 's/.*\/renderer\/.*//' $audit2_modulejson_path +sed -i='' 's/.*\/renderer\/.*//' $audit_modulejson_path # add in our hardcoded renderer file mentions -sed -i='' "s/\"Audits2Panel\.js\"/ $files_to_include \"Audits2Panel.js\"/" $audit2_modulejson_path +sed -i='' "s/\"AuditsPanel\.js\"/ $files_to_include \"AuditsPanel.js\"/" $audit_modulejson_path # compile, finally python "$frontend_path/scripts/compile_frontend.py" --protocol-externs-file "$protocol_path/externs/protocol_externs.js" diff --git a/lighthouse-core/scripts/roll-to-devtools.sh b/lighthouse-core/scripts/roll-to-devtools.sh index 963cb42c010a..5959fd902182 100755 --- a/lighthouse-core/scripts/roll-to-devtools.sh +++ b/lighthouse-core/scripts/roll-to-devtools.sh @@ -33,10 +33,10 @@ else fi report_dir="lighthouse-core/report/html" -fe_lh_dir="$frontend_dir/audits2/lighthouse" +fe_lh_dir="$frontend_dir/audits/lighthouse" lh_bg_js="dist/lighthouse-dt-bundle.js" -lh_worker_dir="$frontend_dir/audits2_worker/lighthouse" +lh_worker_dir="$frontend_dir/audits_worker/lighthouse" # copy lighthouse-dt-bundle (potentially stale) cp -pPR "$lh_bg_js" "$lh_worker_dir/lighthouse-dt-bundle.js" From f8552d5ff0cb0a38716236d8347eba31da50c76c Mon Sep 17 00:00:00 2001 From: Mitchell Simoens Date: Mon, 3 Jun 2019 16:48:24 -0400 Subject: [PATCH 005/110] docs(readme): Add gimbal integration (#9083) --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index f911924eb001..3732042aeccb 100644 --- a/readme.md +++ b/readme.md @@ -304,6 +304,7 @@ This section details services that have integrated Lighthouse data. If you're wo ## Related Projects Other awesome open source projects that use Lighthouse. +* **[Gimbal](https://labs.moduscreate.com/gimbal-web-performance-audit-budgeting)** - An [open source (MIT licensed)](https://github.com/ModusCreateOrg/gimbal) tool used to measure, analyze, and budget aspects of a web application. Gimbal also integrates reports with GitHub pull requests. * **[webpack-lighthouse-plugin](https://github.com/addyosmani/webpack-lighthouse-plugin)** - run Lighthouse from a Webpack build. * **[lighthouse-mocha-example](https://github.com/justinribeiro/lighthouse-mocha-example)** - gather performance metrics via Lighthouse and tests them in Mocha * **[pwmetrics](https://github.com/paulirish/pwmetrics/)** - gather performance metrics From 93387cd83db3f713125d0d515000f85b37607e23 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 4 Jun 2019 00:00:00 +0200 Subject: [PATCH 006/110] core(driver): security errors are no longer a fatal or pageload error (#8865) --- .../test/smokehouse/error-expectations.js | 4 +- lighthouse-core/gather/driver.js | 58 +--------- lighthouse-core/test/gather/driver-test.js | 102 ------------------ 3 files changed, 3 insertions(+), 161 deletions(-) diff --git a/lighthouse-cli/test/smokehouse/error-expectations.js b/lighthouse-cli/test/smokehouse/error-expectations.js index 04d804e5a613..55afc640f430 100644 --- a/lighthouse-cli/test/smokehouse/error-expectations.js +++ b/lighthouse-cli/test/smokehouse/error-expectations.js @@ -18,10 +18,10 @@ module.exports = [ }, }, { - errorCode: 'INSECURE_DOCUMENT_REQUEST', + errorCode: undefined, lhr: { requestedUrl: 'https://expired.badssl.com', - finalUrl: 'https://expired.badssl.com', + finalUrl: 'https://expired.badssl.com/', audits: {}, }, }, diff --git a/lighthouse-core/gather/driver.js b/lighthouse-core/gather/driver.js index 93f267a8ae85..a07c4d6d6295 100644 --- a/lighthouse-core/gather/driver.js +++ b/lighthouse-core/gather/driver.js @@ -903,53 +903,6 @@ class Driver { }; } - /** - * Return a promise that resolves when an insecure security state is encountered - * and a method to cancel internal listeners. - * @return {{promise: Promise, cancel: function(): void}} - * @private - */ - _monitorForInsecureState() { - /** @type {(() => void)} */ - let cancel = () => { - throw new Error('_monitorForInsecureState.cancel() called before it was defined'); - }; - - const promise = new Promise((resolve, reject) => { - /** - * @param {LH.Crdp.Security.SecurityStateChangedEvent} event - */ - const securityStateChangedListener = ({ - securityState, - explanations, - schemeIsCryptographic, - }) => { - if (securityState === 'insecure' && schemeIsCryptographic) { - cancel(); - const insecureDescriptions = explanations - .filter(exp => exp.securityState === 'insecure') - .map(exp => exp.description); - resolve(insecureDescriptions.join(' ')); - } - }; - let canceled = false; - cancel = () => { - if (canceled) return; - canceled = true; - this.off('Security.securityStateChanged', securityStateChangedListener); - // TODO(@patrickhulce): cancel() should really be a promise itself to handle things like this - this.sendCommand('Security.disable').catch(() => {}); - }; - this.on('Security.securityStateChanged', securityStateChangedListener); - this.sendCommand('Security.enable').catch(() => {}); - }); - - return { - promise, - cancel, - }; - } - /** * Returns whether the page appears to be hung. * @return {Promise} @@ -1001,13 +954,6 @@ class Driver { // CPU listener. Resolves when the CPU has been idle for cpuQuietThresholdMs after network idle. let waitForCPUIdle = this._waitForNothing(); - const monitorForInsecureState = this._monitorForInsecureState(); - const securityCheckPromise = monitorForInsecureState.promise.then(securityMessages => { - return function() { - throw new LHError(LHError.errors.INSECURE_DOCUMENT_REQUEST, {securityMessages}); - }; - }); - // Wait for both load promises. Resolves on cleanup function the clears load // timeout timer. const loadPromise = Promise.all([ @@ -1044,9 +990,8 @@ class Driver { }; }); - // Wait for security issue, load or timeout and run the cleanup function the winner returns. + // Wait for load or timeout and run the cleanup function the winner returns. const cleanupFn = await Promise.race([ - securityCheckPromise, loadPromise, maxTimeoutPromise, ]); @@ -1056,7 +1001,6 @@ class Driver { waitForLoadEvent.cancel(); waitForNetworkIdle.cancel(); waitForCPUIdle.cancel(); - monitorForInsecureState.cancel(); await cleanupFn(); } diff --git a/lighthouse-core/test/gather/driver-test.js b/lighthouse-core/test/gather/driver-test.js index d96ee191b1b9..dfe5ed6ba6af 100644 --- a/lighthouse-core/test/gather/driver-test.js +++ b/lighthouse-core/test/gather/driver-test.js @@ -675,108 +675,6 @@ describe('.gotoURL', () => { // Make sure we still cleaned up our listeners expect(driver._waitForLoadEvent.getMockCancelFn()).toHaveBeenCalled(); }); - - it('does not reject when page is secure', async () => { - const secureSecurityState = { - explanations: [], - securityState: 'secure', - }; - - driver.on = driver.once = createMockOnceFn() - .mockEvent('Security.securityStateChanged', secureSecurityState); - - const startUrl = 'https://www.example.com'; - const loadOptions = { - waitForLoad: true, - passContext: { - settings: { - maxWaitForLoad: 1, - }, - }, - }; - - const loadPromise = driver.gotoURL(startUrl, loadOptions); - await flushAllTimersAndMicrotasks(); - await loadPromise; - }); - - it('does not reject when page is insecure but http', async () => { - const secureSecurityState = { - explanations: [], - securityState: 'insecure', - schemeIsCryptographic: false, - }; - - driver.on = driver.once = createMockOnceFn() - .mockEvent('Security.securityStateChanged', secureSecurityState); - - const startUrl = 'https://www.example.com'; - const loadOptions = { - waitForLoad: true, - passContext: { - settings: { - maxWaitForLoad: 1, - }, - }, - }; - - const loadPromise = driver.gotoURL(startUrl, loadOptions); - await flushAllTimersAndMicrotasks(); - await loadPromise; - }); - - it('rejects when page is insecure', async () => { - const insecureSecurityState = { - explanations: [ - { - description: 'reason 1.', - securityState: 'insecure', - }, - { - description: 'blah.', - securityState: 'info', - }, - { - description: 'reason 2.', - securityState: 'insecure', - }, - ], - securityState: 'insecure', - schemeIsCryptographic: true, - }; - - driver.on = driver.once = createMockOnceFn(); - - const startUrl = 'https://www.example.com'; - const loadOptions = { - waitForLoad: true, - passContext: { - passConfig: { - networkQuietThresholdMs: 1, - }, - }, - }; - - // 2 assertions in the catch block and the 1 implicit in `findListener` - expect.assertions(3); - - try { - const loadPromise = driver.gotoURL(startUrl, loadOptions); - await flushAllTimersAndMicrotasks(); - - // Use `findListener` instead of `mockEvent` so we can control exactly when the promise resolves - const listener = driver.on.findListener('Security.securityStateChanged'); - listener(insecureSecurityState); - await flushAllTimersAndMicrotasks(); - await loadPromise; - } catch (err) { - expect(err).toHaveProperty('code', 'INSECURE_DOCUMENT_REQUEST'); - expect(err.friendlyMessage).toBeDisplayString( - 'The URL you have provided does not have a valid security certificate. ' + - 'reason 1. reason 2.' - ); - } - }); }); }); From 5debdde366042724dc102a6a5a75fd1f38f7222a Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Tue, 4 Jun 2019 10:41:42 -0500 Subject: [PATCH 007/110] docs(readme): alphabetize related projects (#9110) --- readme.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index 3732042aeccb..4acb02f5a75f 100644 --- a/readme.md +++ b/readme.md @@ -304,23 +304,24 @@ This section details services that have integrated Lighthouse data. If you're wo ## Related Projects Other awesome open source projects that use Lighthouse. +* **[Garie](https://github.com/boyney123/garie)** — An open source tool for monitoring performance using Lighthouse, PageSpeed Insights, [Prometheus](https://prometheus.io/), [Grafana](https://grafana.com/) and [Docker](https://www.docker.com/). * **[Gimbal](https://labs.moduscreate.com/gimbal-web-performance-audit-budgeting)** - An [open source (MIT licensed)](https://github.com/ModusCreateOrg/gimbal) tool used to measure, analyze, and budget aspects of a web application. Gimbal also integrates reports with GitHub pull requests. -* **[webpack-lighthouse-plugin](https://github.com/addyosmani/webpack-lighthouse-plugin)** - run Lighthouse from a Webpack build. -* **[lighthouse-mocha-example](https://github.com/justinribeiro/lighthouse-mocha-example)** - gather performance metrics via Lighthouse and tests them in Mocha -* **[pwmetrics](https://github.com/paulirish/pwmetrics/)** - gather performance metrics -* **[lighthouse-hue](https://github.com/ebidel/lighthouse-hue)** - set the color of Philips Hue lights based on a Lighthouse score - * **[lighthouse-magic-light](https://github.com/manekinekko/lighthouse-magic-light)** set the color of the MagicLight Bluetooth Smart Light Bulb based on Lighthouse score -* **[lighthouse-batch](https://www.npmjs.com/package/lighthouse-batch)** - run Lighthouse over a number of sites and generate a summary of their metrics/scores. +* **[lightcrawler](https://github.com/github/lightcrawler)** - Crawl a website and run each page found through Lighthouse. * **[lighthouse-badges](https://github.com/emazzotta/lighthouse-badges)** - Generate gh-badges (shields.io) based on Lighthouse performance. +* **[lighthouse-batch](https://www.npmjs.com/package/lighthouse-batch)** - run Lighthouse over a number of sites and generate a summary of their metrics/scores. +* **[lighthouse-ci](https://github.com/andreasonny83/lighthouse-ci)** - Run Lighthouse and assert scores satisfy your custom thresholds. * **[lighthouse-cron](https://github.com/thearegee/lighthouse-cron)** - Cron multiple batch Lighthouse audits and emit results for sending to remote server. -* **[lightcrawler](https://github.com/github/lightcrawler)** - Crawl a website and run each page found through Lighthouse. +* **[lighthouse-gh-reporter](https://github.com/carlesnunez/lighthouse-gh-reporter)** - Run Lighthouse in CI and report back in a comment on your pull requests +* **[lighthouse-hue](https://github.com/ebidel/lighthouse-hue)** - set the color of Philips Hue lights based on a Lighthouse score * **[lighthouse-lambda](https://github.com/joytocode/lighthouse-lambda)** - Run Lighthouse on AWS Lambda with prebuilt stable desktop Headless Chrome. -* **[Garie](https://github.com/boyney123/garie)** — An open source tool for monitoring performance using Lighthouse, PageSpeed Insights, [Prometheus](https://prometheus.io/), [Grafana](https://grafana.com/) and [Docker](https://www.docker.com/). -* **[lighthouse-ci](https://github.com/andreasonny83/lighthouse-ci)** - Run Lighthouse and assert scores satisfy your custom thresholds. +* **[lighthouse-magic-light](https://github.com/manekinekko/lighthouse-magic-light)** set the color of the MagicLight Bluetooth Smart Light Bulb based on Lighthouse score +* **[lighthouse-mocha-example](https://github.com/justinribeiro/lighthouse-mocha-example)** - gather performance metrics via Lighthouse and tests them in Mocha * **[lighthouse4u](https://github.com/godaddy/lighthouse4u)** - LH4U provides Google Lighthouse as a service, surfaced by both a friendly UI+API, and backed by Elastic Search for easy querying and visualization. -* **[lighthouse-gh-reporter](https://github.com/carlesnunez/lighthouse-gh-reporter)** - Run Lighthouse in CI and report back in a comment on your pull requests -* **[react-lighthouse-viewer](https://www.npmjs.com/package/react-lighthouse-viewer)** - Render a Lighthouse JSON report in a React Component. * **[performance-budgets](https://performance-budgets.netlify.com/)** - Easily assert Lighthouse budgets with Docker. +* **[pwmetrics](https://github.com/paulirish/pwmetrics/)** - gather performance metrics +* **[react-lighthouse-viewer](https://www.npmjs.com/package/react-lighthouse-viewer)** - Render a Lighthouse JSON report in a React Component. +* **[webpack-lighthouse-plugin](https://github.com/addyosmani/webpack-lighthouse-plugin)** - run Lighthouse from a Webpack build. + ## FAQ ### How does Lighthouse work? From 273b4a4785006dbbc7007104f0576dbe692536fa Mon Sep 17 00:00:00 2001 From: Brendan Kenny Date: Tue, 4 Jun 2019 12:43:39 -0700 Subject: [PATCH 008/110] docs: add instructions for testing with self-signed certificate (#9112) --- docs/readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/readme.md b/docs/readme.md index 4e376a975295..0cd05d05771a 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -115,6 +115,14 @@ instance with an open debugging port. 1. Navigate to your site and log in. 1. In a separate terminal tab, run `lighthouse http://mysite.com --port port-number` using the port number from chrome-debug. +## Testing on a site with an untrusted certificate + +When testing a site with an untrusted certificate, Chrome will be unable to load the page and so the Lighthouse report will mostly contain errors. + +If this certificate **is one you control** and is necessary for development (for instance, `localhost` with a self-signed certificate for local HTTP/2 testing), we recommend you _add the certificate to your locally-trusted certificate store_. In Chrome, see `Settings` > `Privacy and Security` > `Manage certificates` or consult instructions for adding to the certificate store in your operating system. + +Alternatively, you can instruct Chrome to ignore the invalid certificate by adding the Lighthouse CLI flag `--chrome-flags="--ignore-certificate-errors"`. However, you must be as careful with this flag as it's equivalent to browsing the web with TLS disabled. Any content loaded by the test page (e.g. third-party scripts or iframed ads) will *also* not be subject to certificate checks, [opening up avenues for MitM attacks](https://www.chromium.org/Home/chromium-security/education/tls#TOC-What-security-properties-does-TLS-give-me-). For these reasons, we recommend the earlier solution of adding the certificate to your local cert store. + ## Testing on a mobile device Lighthouse can run against a real mobile device. You can follow the [Remote Debugging on Android (Legacy Workflow)](https://developer.chrome.com/devtools/docs/remote-debugging-legacy) up through step 3.3, but the TL;DR is install & run adb, enable USB debugging, then port forward 9222 from the device to the machine with Lighthouse. From 7deb5ab2a43b128666a3a127b5032618472b6710 Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Tue, 4 Jun 2019 14:53:08 -0500 Subject: [PATCH 009/110] core(cli): accept flags from path (#9109) --- lighthouse-cli/cli-flags.js | 12 ++++++++++++ lighthouse-cli/test/cli/cli-flags-test.js | 19 +++++++++++++++++++ .../test/fixtures/cli-flags-path.json | 10 ++++++++++ readme.md | 2 ++ 4 files changed, 43 insertions(+) create mode 100644 lighthouse-cli/test/fixtures/cli-flags-path.json diff --git a/lighthouse-cli/cli-flags.js b/lighthouse-cli/cli-flags.js index 9b9ceb989cf2..9e7188f042e1 100644 --- a/lighthouse-cli/cli-flags.js +++ b/lighthouse-cli/cli-flags.js @@ -62,6 +62,17 @@ function getFlags(manualArgv) { 'lighthouse --only-categories=performance,pwa', 'Only run specific categories.') + /** + * Also accept a file for all of these flags. Yargs will merge in and override the file-based + * flags with the command-line flags. + * + * i.e. when command-line `--throttling-method=provided` and file `throttlingMethod: "devtools"`, + * throttlingMethod will be `provided`. + * + * @see https://github.com/yargs/yargs/blob/a6e67f15a61558d0ba28bfe53385332f0ce5d431/docs/api.md#config + */ + .config('cli-flags-path') + // List of options .group(['verbose', 'quiet'], 'Logging:') .describe({ @@ -78,6 +89,7 @@ function getFlags(manualArgv) { ], 'Configuration:') .describe({ + 'cli-flags-path': 'The path to a JSON file that contains the desired CLI flags to apply. Flags specified at the command line will still override the file-based ones.', // We don't allowlist specific locales. Why? So we can support the user who requests 'es-MX' (unsupported) and we'll fall back to 'es' (supported) 'locale': 'The locale/language the report should be formatted in', 'enable-error-reporting': diff --git a/lighthouse-cli/test/cli/cli-flags-test.js b/lighthouse-cli/test/cli/cli-flags-test.js index 431386a0f976..ed7d073acd74 100644 --- a/lighthouse-cli/test/cli/cli-flags-test.js +++ b/lighthouse-cli/test/cli/cli-flags-test.js @@ -29,6 +29,25 @@ describe('CLI bin', function() { }); }); + it('settings are accepted from a file path', () => { + const flags = getFlags([ + 'http://www.example.com', + `--cli-flags-path="${__dirname}/../fixtures/cli-flags-path.json"`, + '--budgets-path=path/to/my/budget-from-command-line.json', // this should override the config value + ].join(' ')); + + expect(flags).toMatchObject({ + budgetsPath: 'path/to/my/budget-from-command-line.json', + onlyCategories: ['performance', 'seo'], + chromeFlags: '--window-size 800,600', + throttlingMethod: 'devtools', + throttling: { + requestLatencyMs: 700, + cpuSlowdownMultiplier: 6, + }, + }); + }); + it('array values support csv when appropriate', () => { const flags = getFlags([ 'http://www.example.com', diff --git a/lighthouse-cli/test/fixtures/cli-flags-path.json b/lighthouse-cli/test/fixtures/cli-flags-path.json new file mode 100644 index 000000000000..7d993c9df5c9 --- /dev/null +++ b/lighthouse-cli/test/fixtures/cli-flags-path.json @@ -0,0 +1,10 @@ +{ + "budgetPath": "path/to/my/budget-from-config.json", + "onlyCategories": ["performance", "seo"], + "chromeFlags": "--window-size 800,600", + "throttling-method": "devtools", + "throttling": { + "requestLatencyMs": 700, + "cpuSlowdownMultiplier": 6 + } +} diff --git a/readme.md b/readme.md index 4acb02f5a75f..c0ce1e340842 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,8 @@ Output: Options: --help Show help [boolean] --version Show version number [boolean] + --cli-flags-path The path to a JSON file that contains the desired CLI flags to apply. + Flags specified at the command line will still override the file-based ones. --blocked-url-patterns Block any network requests to the specified URL patterns [array] --disable-storage-reset Disable clearing the browser cache and other storage APIs before a run [boolean] --throttling-method Controls throttling method [choices: "devtools", "provided", "simulate"] From 4bd3a58da90ea9f31fa3551b853b0bccc9e095ce Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Tue, 4 Jun 2019 14:56:14 -0500 Subject: [PATCH 010/110] misc: address release script feedback (#9111) --- docs/releasing.md | 22 ++++++++++--------- .../scripts/release/clean-pristine.sh | 17 -------------- .../scripts/release/prepare-commit.sh | 2 +- lighthouse-core/scripts/release/test.sh | 2 +- 4 files changed, 14 insertions(+), 29 deletions(-) delete mode 100755 lighthouse-core/scripts/release/clean-pristine.sh diff --git a/docs/releasing.md b/docs/releasing.md index eabdf233dd67..e65cc3475f88 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -44,24 +44,26 @@ bash ./lighthouse-core/scripts/release/test.sh # Package everything for publishing bash ./lighthouse-core/scripts/release/prepare-package.sh +# Make sure you're in the Lighthouse pristine repo we just tested. +cd ../lighthouse-pristine + +# Publish to NPM +npm publish + +# Publish viewer +yarn deploy-viewer + # Upload the extension -node build/build-extension.js package; cd dist/extension-package/ open https://chrome.google.com/webstore/developer/edit/blipmdconlkpinefehnmjammfjpmpbjk -echo "Upload the package zip to CWS dev dashboard" +cd dist/extension-package/ +echo "Upload the package zip to CWS dev dashboard..." # Be in lighthouse-extension-owners group # Open # Click _Edit_ on lighthouse # _Upload Updated Package_ -# Select `lighthouse-4.X.X.zip` +# Select `lighthouse-X.X.X.zip` # _Publish_ at the bottom -# Make sure you're in the Lighthouse pristine repo we just tested. -cd ../lighthouse-pristine -# Publish to NPM -npm publish -# Publish viewer -yarn deploy-viewer - # * Tell the world!!! * echo "Complete the _Release publicity_ tasks documented above" ``` diff --git a/lighthouse-core/scripts/release/clean-pristine.sh b/lighthouse-core/scripts/release/clean-pristine.sh deleted file mode 100755 index f4bf04a26e3a..000000000000 --- a/lighthouse-core/scripts/release/clean-pristine.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -DIRNAME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -LH_ROOT="$DIRNAME/../../.." -cd $LH_ROOT - -set -euxo pipefail - -# Setup a pristine git environment -cd ../lighthouse-pristine - -if [[ -z "$(git status --porcelain)" ]]; then - echo "Pristine repo already clean!" - exit 0 -fi - -git clean -fx diff --git a/lighthouse-core/scripts/release/prepare-commit.sh b/lighthouse-core/scripts/release/prepare-commit.sh index f143149e0c78..314831f223a0 100755 --- a/lighthouse-core/scripts/release/prepare-commit.sh +++ b/lighthouse-core/scripts/release/prepare-commit.sh @@ -70,7 +70,7 @@ echo "Version bump commit ready on the ${TXT_BOLD}$BRANCH_NAME${TXT_RESET} branc echo "${TXT_DIM}Press any key to see the git diff, CTRL+C to exit...${TXT_RESET}" read -n 1 -r unused_variable -git --no-pager diff HEAD^ +git diff HEAD^ echo "${TXT_DIM}Press any key to push to GitHub, CTRL+C to exit...${TXT_RESET}" read -n 1 -r unused_variable git push -u origin "$BRANCH_NAME" diff --git a/lighthouse-core/scripts/release/test.sh b/lighthouse-core/scripts/release/test.sh index 271a083466b4..fb568567c104 100755 --- a/lighthouse-core/scripts/release/test.sh +++ b/lighthouse-core/scripts/release/test.sh @@ -24,7 +24,7 @@ echo "Running the standard test suite..." yarn test echo "Running the smoke tests...." -yarn smoke +yarn smoke || yarn smoke || yarn smoke echo "Testing the CLI..." yarn start "https://example.com" --view From 952ae027a9dac4ae461411e8ee99cd4bb3c5910a Mon Sep 17 00:00:00 2001 From: Deepanjan Roy Date: Tue, 4 Jun 2019 20:09:13 -0400 Subject: [PATCH 011/110] new_audit: add cumulative-long-queuing-delay to JSON (#8975) --- .../test/cli/__snapshots__/index-test.js.snap | 7 + lighthouse-core/audits/metrics.js | 4 + .../metrics/cumulative-long-queuing-delay.js | 79 +++++++++++ .../metrics/cumulative-long-queuing-delay.js | 124 ++++++++++++++++++ .../lantern-cumulative-long-queuing-delay.js | 121 +++++++++++++++++ lighthouse-core/config/default-config.js | 3 +- .../audits/__snapshots__/metrics-test.js.snap | 1 + .../cumulative-long-queuing-delay-test.js | 32 +++++ .../cumulative-long-queuing-delay-test.js | 115 ++++++++++++++++ lighthouse-core/test/results/sample_v2.json | 32 +++++ proto/sample_v2_round_trip.json | 32 +++++ 11 files changed, 549 insertions(+), 1 deletion(-) create mode 100644 lighthouse-core/audits/metrics/cumulative-long-queuing-delay.js create mode 100644 lighthouse-core/computed/metrics/cumulative-long-queuing-delay.js create mode 100644 lighthouse-core/computed/metrics/lantern-cumulative-long-queuing-delay.js create mode 100644 lighthouse-core/test/audits/metrics/cumulative-long-queuing-delay-test.js create mode 100644 lighthouse-core/test/computed/metrics/cumulative-long-queuing-delay-test.js diff --git a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap index d2aa1fbba196..3983c1067232 100644 --- a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap +++ b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap @@ -42,6 +42,9 @@ Object { Object { "path": "metrics/estimated-input-latency", }, + Object { + "path": "metrics/cumulative-long-queuing-delay", + }, Object { "path": "metrics/max-potential-fid", }, @@ -710,6 +713,10 @@ Object { "id": "estimated-input-latency", "weight": 0, }, + Object { + "id": "cumulative-long-queuing-delay", + "weight": 0, + }, Object { "group": "load-opportunities", "id": "render-blocking-resources", diff --git a/lighthouse-core/audits/metrics.js b/lighthouse-core/audits/metrics.js index 20a124612cc5..374517c2137a 100644 --- a/lighthouse-core/audits/metrics.js +++ b/lighthouse-core/audits/metrics.js @@ -14,6 +14,7 @@ const FirstCPUIdle = require('../computed/metrics/first-cpu-idle.js'); const Interactive = require('../computed/metrics/interactive.js'); const SpeedIndex = require('../computed/metrics/speed-index.js'); const EstimatedInputLatency = require('../computed/metrics/estimated-input-latency.js'); +const CumulativeLongQueuingDelay = require('../computed/metrics/cumulative-long-queuing-delay.js'); class Metrics extends Audit { /** @@ -59,6 +60,7 @@ class Metrics extends Audit { const interactive = await requestOrUndefined(Interactive, metricComputationData); const speedIndex = await requestOrUndefined(SpeedIndex, metricComputationData); const estimatedInputLatency = await EstimatedInputLatency.request(metricComputationData, context); // eslint-disable-line max-len + const cumulativeLongQueuingDelay = await CumulativeLongQueuingDelay.request(metricComputationData, context); // eslint-disable-line max-len /** @type {UberMetricsItem} */ const metrics = { @@ -75,6 +77,7 @@ class Metrics extends Audit { speedIndexTs: speedIndex && speedIndex.timestamp, estimatedInputLatency: estimatedInputLatency.timing, estimatedInputLatencyTs: estimatedInputLatency.timestamp, + cumulativeLongQueuingDelay: cumulativeLongQueuingDelay.timing, // Include all timestamps of interest from trace of tab observedNavigationStart: traceOfTab.timings.navigationStart, @@ -137,6 +140,7 @@ class Metrics extends Audit { * @property {number=} speedIndexTs * @property {number} estimatedInputLatency * @property {number=} estimatedInputLatencyTs + * @property {number} cumulativeLongQueuingDelay * @property {number} observedNavigationStart * @property {number} observedNavigationStartTs * @property {number=} observedFirstPaint diff --git a/lighthouse-core/audits/metrics/cumulative-long-queuing-delay.js b/lighthouse-core/audits/metrics/cumulative-long-queuing-delay.js new file mode 100644 index 000000000000..dd0297ad8da6 --- /dev/null +++ b/lighthouse-core/audits/metrics/cumulative-long-queuing-delay.js @@ -0,0 +1,79 @@ +/** + * @license Copyright 2019 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const Audit = require('../audit.js'); +const CumulativeLQD = require('../../computed/metrics/cumulative-long-queuing-delay.js'); + +// TODO(deepanjanroy): i18n strings once metric is final. +const UIStringsNotExported = { + title: 'Cumulative Long Queuing Delay', + description: '[Experimental metric] Total time period between FCP and Time to Interactive ' + + 'during which queuing time for any input event would be higher than 50ms.', +}; + +class CumulativeLongQueuingDelay extends Audit { + /** + * @return {LH.Audit.Meta} + */ + static get meta() { + return { + id: 'cumulative-long-queuing-delay', + title: UIStringsNotExported.title, + description: UIStringsNotExported.description, + scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, + requiredArtifacts: ['traces', 'devtoolsLogs'], + }; + } + + /** + * @return {LH.Audit.ScoreOptions} + */ + static get defaultOptions() { + return { + // According to a cluster telemetry run over top 10k sites on mobile, 5th percentile was 0ms, + // 25th percentile was 270ms and median was 895ms. These numbers include 404 pages. Picking + // thresholds according to our 25/75-th rule will be quite harsh scoring (a single 350ms task) + // after FCP will yield a score of .5. The following coefficients are semi-arbitrarily picked + // to give 600ms jank a score of .5 and 100ms jank a score of .999. We can tweak these numbers + // in the future. See https://www.desmos.com/calculator/a7ib75kq3g + scoreMedian: 600, + scorePODR: 200, + }; + } + + /** + * Audits the page to calculate Cumulative Long Queuing Delay. + * + * We define Long Queuing Delay Region as any time interval in the loading timeline where queuing + * time for an input event would be longer than 50ms. For example, if there is a 110ms main thread + * task, the first 60ms of it is Long Queuing Delay Region, because any input event occuring in + * that region has to wait more than 50ms. Cumulative Long Queuing Delay is the sum of all Long + * Queuing Delay Regions between First Contentful Paint and Interactive Time (TTI). + * + * @param {LH.Artifacts} artifacts + * @param {LH.Audit.Context} context + * @return {Promise} + */ + static async audit(artifacts, context) { + const trace = artifacts.traces[Audit.DEFAULT_PASS]; + const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS]; + const metricComputationData = {trace, devtoolsLog, settings: context.settings}; + const metricResult = await CumulativeLQD.request(metricComputationData, context); + + return { + score: Audit.computeLogNormalScore( + metricResult.timing, + context.options.scorePODR, + context.options.scoreMedian + ), + numericValue: metricResult.timing, + displayValue: 10 * Math.round(metricResult.timing / 10) + '\xa0ms', + }; + } +} + +module.exports = CumulativeLongQueuingDelay; diff --git a/lighthouse-core/computed/metrics/cumulative-long-queuing-delay.js b/lighthouse-core/computed/metrics/cumulative-long-queuing-delay.js new file mode 100644 index 000000000000..65f9c7bdcc5a --- /dev/null +++ b/lighthouse-core/computed/metrics/cumulative-long-queuing-delay.js @@ -0,0 +1,124 @@ +/** + * @license Copyright 2019 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const makeComputedArtifact = require('../computed-artifact.js'); +const ComputedMetric = require('./metric.js'); +const LHError = require('../../lib/lh-error.js'); +const TracingProcessor = require('../../lib/traces/tracing-processor.js'); +const LanternCumulativeLongQueuingDelay = require('./lantern-cumulative-long-queuing-delay.js'); +const TimetoInteractive = require('./interactive.js'); + +/** + * @fileoverview This audit determines Cumulative Long Queuing Delay between FCP and TTI. + + * We define Long Queuing Delay Region as any time interval in the loading timeline where queuing + * time for an input event would be longer than 50ms. For example, if there is a 110ms main thread + * task, the first 60ms of it is Long Queuing Delay Region, because any input event occuring in + * that region has to wait more than 50ms. Cumulative Long Queuing Delay is the sum of all Long + * Queuing Delay Regions between First Contentful Paint and Interactive Time (TTI). + * + * This is a new metric designed to accompany Time to Interactive. TTI is strict and does not + * reflect incremental improvements to the site performance unless the improvement concerns the last + * long task. Cumulative Long Queuing Delay on the other hand is designed to be much more responsive + * to smaller improvements to main thread responsiveness. + */ +class CumulativeLongQueuingDelay extends ComputedMetric { + /** + * @return {number} + */ + static get LONG_QUEUING_DELAY_THRESHOLD() { + return 50; + } + /** + * @param {Array<{start: number, end: number, duration: number}>} topLevelEvents + * @param {number} fcpTimeInMs + * @param {number} interactiveTimeMs + * @return {number} + */ + static calculateSumOfLongQueuingDelay(topLevelEvents, fcpTimeInMs, interactiveTimeMs) { + if (interactiveTimeMs <= fcpTimeInMs) return 0; + + const threshold = CumulativeLongQueuingDelay.LONG_QUEUING_DELAY_THRESHOLD; + const longQueuingDelayRegions = []; + // First identifying the long queuing delay regions. + for (const event of topLevelEvents) { + // If the task is less than the delay threshold, it contains no Long Queuing Delay Region. + if (event.duration < threshold) continue; + // Otherwise, the duration of the task before the delay-threshold-sized interval at the end is + // considered Long Queuing Delay Region. Example assuming the threshold is 50ms: + // [ 250ms Task ] + // | Long Queuing Delay Region | Last 50ms | + // 200 ms + longQueuingDelayRegions.push({ + start: event.start, + end: event.end - threshold, + duration: event.duration - threshold, + }); + } + + let sumLongQueuingDelay = 0; + for (const region of longQueuingDelayRegions) { + // We only want to add up the Long Queuing Delay regions that fall between FCP and TTI. + // + // FCP is picked as the lower bound because there is little risk of user input happening + // before FCP so Long Queuing Qelay regions do not harm user experience. Developers should be + // optimizing to reach FCP as fast as possible without having to worry about task lengths. + // + // TTI is picked as the upper bound because we want a well defined end point so that the + // metric does not rely on how long we trace. + if (region.end < fcpTimeInMs) continue; + if (region.start > interactiveTimeMs) continue; + + // If a Long Queuing Delay Region spans the edges of our region of interest, we clip it to + // only include the part of the region that falls inside. + const clippedStart = Math.max(region.start, fcpTimeInMs); + const clippedEnd = Math.min(region.end, interactiveTimeMs); + const queuingDelayAfterClipping = clippedEnd - clippedStart; + + sumLongQueuingDelay += queuingDelayAfterClipping; + } + + return sumLongQueuingDelay; + } + + /** + * @param {LH.Artifacts.MetricComputationData} data + * @param {LH.Audit.Context} context + * @return {Promise} + */ + static computeSimulatedMetric(data, context) { + return LanternCumulativeLongQueuingDelay.request(data, context); + } + + /** + * @param {LH.Artifacts.MetricComputationData} data + * @param {LH.Audit.Context} context + * @return {Promise} + */ + static async computeObservedMetric(data, context) { + const {firstContentfulPaint} = data.traceOfTab.timings; + if (!firstContentfulPaint) { + throw new LHError(LHError.errors.NO_FCP); + } + + const interactiveTimeMs = (await TimetoInteractive.request(data, context)).timing; + + // Not using the start time argument of getMainThreadTopLevelEvents, because + // we need to clip the part of the task before the last 50ms properly. + const events = TracingProcessor.getMainThreadTopLevelEvents(data.traceOfTab); + + return { + timing: CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + firstContentfulPaint, + interactiveTimeMs + ), + }; + } +} + +module.exports = makeComputedArtifact(CumulativeLongQueuingDelay); diff --git a/lighthouse-core/computed/metrics/lantern-cumulative-long-queuing-delay.js b/lighthouse-core/computed/metrics/lantern-cumulative-long-queuing-delay.js new file mode 100644 index 000000000000..112b3539fb57 --- /dev/null +++ b/lighthouse-core/computed/metrics/lantern-cumulative-long-queuing-delay.js @@ -0,0 +1,121 @@ +/** + * @license Copyright 2019 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const makeComputedArtifact = require('../computed-artifact.js'); +const LanternMetric = require('./lantern-metric.js'); +const BaseNode = require('../../lib/dependency-graph/base-node.js'); +const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js'); +const LanternInteractive = require('./lantern-interactive.js'); + +/** @typedef {BaseNode.Node} Node */ + +class LanternCumulativeLongQueuingDelay extends LanternMetric { + /** + * @return {LH.Gatherer.Simulation.MetricCoefficients} + */ + static get COEFFICIENTS() { + return { + intercept: 0, + optimistic: 0.5, + pessimistic: 0.5, + }; + } + + /** + * @param {Node} dependencyGraph + * @return {Node} + */ + static getOptimisticGraph(dependencyGraph) { + return dependencyGraph; + } + + /** + * @param {Node} dependencyGraph + * @return {Node} + */ + static getPessimisticGraph(dependencyGraph) { + return dependencyGraph; + } + + /** + * @param {LH.Gatherer.Simulation.Result} simulation + * @param {Object} extras + * @return {LH.Gatherer.Simulation.Result} + */ + static getEstimateFromSimulation(simulation, extras) { + // Intentionally use the opposite FCP estimate. A pessimistic FCP is higher than equal to an + // optimistic FCP, which means potentially more tasks are excluded from the + // CumulativeLongQueuingDelay computation. So a more pessimistic FCP gives a more optimistic + // CumulativeLongQueuingDelay for the same work. + const fcpTimeInMs = extras.optimistic + ? extras.fcpResult.pessimisticEstimate.timeInMs + : extras.fcpResult.optimisticEstimate.timeInMs; + + // Similarly, we always have pessimistic TTI >= optimistic TTI. Therefore, picking optimistic + // TTI means our window of interest is smaller and thus potentially more tasks are excluded from + // CumulativeLongQueuingDelay computation, yielding a lower (more optimistic) + // CumulativeLongQueuingDelay value for the same work. + const interactiveTimeMs = extras.optimistic + ? extras.interactiveResult.optimisticEstimate.timeInMs + : extras.interactiveResult.pessimisticEstimate.timeInMs; + + // Require here to resolve circular dependency. + const CumulativeLongQueuingDelay = require('./cumulative-long-queuing-delay.js'); + const minDurationMs = CumulativeLongQueuingDelay.LONG_QUEUING_DELAY_THRESHOLD; + + const events = LanternCumulativeLongQueuingDelay.getTopLevelEvents( + simulation.nodeTimings, + minDurationMs + ); + + return { + timeInMs: CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + fcpTimeInMs, + interactiveTimeMs + ), + nodeTimings: simulation.nodeTimings, + }; + } + + /** + * @param {LH.Artifacts.MetricComputationDataInput} data + * @param {LH.Audit.Context} context + * @return {Promise} + */ + static async compute_(data, context) { + const fcpResult = await LanternFirstContentfulPaint.request(data, context); + const interactiveResult = await LanternInteractive.request(data, context); + return this.computeMetricWithGraphs(data, context, {fcpResult, interactiveResult}); + } + + /** + * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings + * @param {number} minDurationMs + */ + static getTopLevelEvents(nodeTimings, minDurationMs) { + /** @type {Array<{start: number, end: number, duration: number}>} + */ + const events = []; + + for (const [node, timing] of nodeTimings.entries()) { + if (node.type !== BaseNode.TYPES.CPU) continue; + // Filtering out events below minimum duration. + if (timing.duration < minDurationMs) continue; + + events.push({ + start: timing.startTime, + end: timing.endTime, + duration: timing.duration, + }); + } + + return events; + } +} + +module.exports = makeComputedArtifact(LanternCumulativeLongQueuingDelay); diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js index 33ac027e8e01..15916dda5d7f 100644 --- a/lighthouse-core/config/default-config.js +++ b/lighthouse-core/config/default-config.js @@ -170,6 +170,7 @@ const defaultConfig = { 'screenshot-thumbnails', 'final-screenshot', 'metrics/estimated-input-latency', + 'metrics/cumulative-long-queuing-delay', 'metrics/max-potential-fid', 'errors-in-console', 'time-to-first-byte', @@ -366,7 +367,7 @@ const defaultConfig = { {id: 'first-cpu-idle', weight: 2, group: 'metrics'}, {id: 'max-potential-fid', weight: 0, group: 'metrics'}, {id: 'estimated-input-latency', weight: 0}, // intentionally left out of metrics so it won't be displayed - + {id: 'cumulative-long-queuing-delay', weight: 0}, // intentionally left out of metrics so it won't be displayed {id: 'render-blocking-resources', weight: 0, group: 'load-opportunities'}, {id: 'uses-responsive-images', weight: 0, group: 'load-opportunities'}, {id: 'offscreen-images', weight: 0, group: 'load-opportunities'}, diff --git a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap index 0807e76b83cc..685d98388384 100644 --- a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap +++ b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap @@ -2,6 +2,7 @@ exports[`Performance: metrics evaluates valid input correctly 1`] = ` Object { + "cumulativeLongQueuingDelay": 748, "estimatedInputLatency": 78, "estimatedInputLatencyTs": undefined, "firstCPUIdle": 3351, diff --git a/lighthouse-core/test/audits/metrics/cumulative-long-queuing-delay-test.js b/lighthouse-core/test/audits/metrics/cumulative-long-queuing-delay-test.js new file mode 100644 index 000000000000..160322069358 --- /dev/null +++ b/lighthouse-core/test/audits/metrics/cumulative-long-queuing-delay-test.js @@ -0,0 +1,32 @@ +/** + * @license Copyright 2019 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const cLQDAudit = require('../../../audits/metrics/cumulative-long-queuing-delay.js'); +const options = cLQDAudit.defaultOptions; + +const pwaTrace = require('../../fixtures/traces/progressive-app-m60.json'); + +function generateArtifactsWithTrace(trace) { + return { + traces: {[cLQDAudit.DEFAULT_PASS]: trace}, + devtoolsLogs: {[cLQDAudit.DEFAULT_PASS]: []}, + }; +} +/* eslint-env jest */ + +describe('Performance: cumulative-long-queuing-delay audit', () => { + it('evaluates cumulative long queuing delay metric properly', async () => { + const artifacts = generateArtifactsWithTrace(pwaTrace); + const settings = {throttlingMethod: 'provided'}; + const context = {options, settings, computedCache: new Map()}; + const output = await cLQDAudit.audit(artifacts, context); + + expect(output.numericValue).toBeCloseTo(48.3, 1); + expect(output.score).toBe(1); + expect(output.displayValue).toBeDisplayString('50\xa0ms'); + }); +}); diff --git a/lighthouse-core/test/computed/metrics/cumulative-long-queuing-delay-test.js b/lighthouse-core/test/computed/metrics/cumulative-long-queuing-delay-test.js new file mode 100644 index 000000000000..8b02ada00c13 --- /dev/null +++ b/lighthouse-core/test/computed/metrics/cumulative-long-queuing-delay-test.js @@ -0,0 +1,115 @@ +/** + * @license Copyright 2019 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const CumulativeLongQueuingDelay = + require('../../../computed/metrics/cumulative-long-queuing-delay.js'); +const trace = require('../../fixtures/traces/progressive-app-m60.json'); +const devtoolsLog = require('../../fixtures/traces/progressive-app-m60.devtools.log.json'); + +/* eslint-env jest */ + +describe('Metrics: CumulativeLongQueuingDelay', () => { + it('should compute a simulated value', async () => { + const settings = {throttlingMethod: 'simulate'}; + const context = {settings, computedCache: new Map()}; + const result = await CumulativeLongQueuingDelay.request( + {trace, devtoolsLog, settings}, + context + ); + + expect({ + timing: Math.round(result.timing), + optimistic: Math.round(result.optimisticEstimate.timeInMs), + pessimistic: Math.round(result.pessimisticEstimate.timeInMs), + }).toMatchInlineSnapshot(` +Object { + "optimistic": 719, + "pessimistic": 777, + "timing": 748, +} +`); + }); + + it('should compute an observed value', async () => { + const settings = {throttlingMethod: 'provided'}; + const context = {settings, computedCache: new Map()}; + const result = await CumulativeLongQueuingDelay.request( + {trace, devtoolsLog, settings}, + context + ); + expect(result.timing).toBeCloseTo(48.3, 1); + }); + + describe('#calculateSumOfLongQueuingDelay', () => { + it('reports 0 when no task is longer than 50ms', () => { + const events = [ + {start: 1000, end: 1050, duration: 50}, + {start: 2000, end: 2010, duration: 10}, + ]; + + const fcpTimeMs = 500; + const interactiveTimeMs = 4000; + + expect(CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + fcpTimeMs, + interactiveTimeMs + )).toBe(0); + }); + + it('only looks at tasks within FMP and TTI', () => { + const events = [ + {start: 1000, end: 1060, duration: 60}, + {start: 2000, end: 2100, duration: 100}, + {start: 2300, end: 2450, duration: 150}, + {start: 2600, end: 2800, duration: 200}, + ]; + + const fcpTimeMs = 1500; + const interactiveTimeMs = 2500; + + expect(CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + fcpTimeMs, + interactiveTimeMs + )).toBe(150); + }); + + it('clips queuing delay regions properly', () => { + const fcpTimeMs = 1050; + const interactiveTimeMs = 2050; + + const events = [ + {start: 1000, end: 1110, duration: 110}, // Contributes 10ms. + {start: 2000, end: 2200, duration: 200}, // Contributes 50ms. + ]; + + expect(CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + fcpTimeMs, + interactiveTimeMs + )).toBe(60); + }); + + // This can happen in the lantern metric case, where we use the optimistic + // TTI and pessimistic FCP. + it('returns 0 if interactiveTime is earlier than FCP', () => { + const fcpTimeMs = 2050; + const interactiveTimeMs = 1050; + + const events = [ + {start: 500, end: 3000, duration: 2500}, + ]; + + expect(CumulativeLongQueuingDelay.calculateSumOfLongQueuingDelay( + events, + fcpTimeMs, + interactiveTimeMs + )).toBe(0); + }); + }); +}); diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 76532a9e9b2a..bfb2a297b9b2 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -191,6 +191,15 @@ "numericValue": 16, "displayValue": "20 ms" }, + "cumulative-long-queuing-delay": { + "id": "cumulative-long-queuing-delay", + "title": "Cumulative Long Queuing Delay", + "description": "[Experimental metric] Total time period between FCP and Time to Interactive during which queuing time for any input event would be higher than 50ms.", + "score": 1, + "scoreDisplayMode": "numeric", + "numericValue": 116.79800000000023, + "displayValue": "120 ms" + }, "max-potential-fid": { "id": "max-potential-fid", "title": "Max Potential First Input Delay", @@ -1248,6 +1257,7 @@ "speedIndex": 4417, "speedIndexTs": 185607736912, "estimatedInputLatency": 16, + "cumulativeLongQueuingDelay": 117, "observedNavigationStart": 0, "observedNavigationStartTs": 185603319912, "observedFirstPaint": 3969, @@ -3360,6 +3370,10 @@ "id": "estimated-input-latency", "weight": 0 }, + { + "id": "cumulative-long-queuing-delay", + "weight": 0 + }, { "id": "render-blocking-resources", "weight": 0, @@ -4216,6 +4230,24 @@ "duration": 100, "entryType": "measure" }, + { + "startTime": 0, + "name": "lh:audit:cumulative-long-queuing-delay", + "duration": 100, + "entryType": "measure" + }, + { + "startTime": 0, + "name": "lh:computed:CumulativeLongQueuingDelay", + "duration": 100, + "entryType": "measure" + }, + { + "startTime": 0, + "name": "lh:computed:Interactive", + "duration": 100, + "entryType": "measure" + }, { "startTime": 0, "name": "lh:audit:max-potential-fid", diff --git a/proto/sample_v2_round_trip.json b/proto/sample_v2_round_trip.json index f0f16a4de298..5e0e3279fa0f 100644 --- a/proto/sample_v2_round_trip.json +++ b/proto/sample_v2_round_trip.json @@ -377,6 +377,15 @@ "scoreDisplayMode": "informative", "title": "Minimize Critical Requests Depth" }, + "cumulative-long-queuing-delay": { + "description": "[Experimental metric] Total time period between FCP and Time to Interactive during which queuing time for any input event would be higher than 50ms.", + "displayValue": "120\u00a0ms", + "id": "cumulative-long-queuing-delay", + "numericValue": 116.79800000000023, + "score": 1.0, + "scoreDisplayMode": "numeric", + "title": "Cumulative Long Queuing Delay" + }, "custom-controls-labels": { "description": "Custom interactive controls have associated labels, provided by aria-label or aria-labelledby. [Learn more](https://developers.google.com/web/fundamentals/accessibility/how-to-review#try_it_with_a_screen_reader).", "id": "custom-controls-labels", @@ -1484,6 +1493,7 @@ "details": { "items": [ { + "cumulativeLongQueuingDelay": 117.0, "estimatedInputLatency": 16.0, "firstCPUIdle": 4927.0, "firstCPUIdleTs": 185608247190.0, @@ -3489,6 +3499,10 @@ "id": "estimated-input-latency", "weight": 0.0 }, + { + "id": "cumulative-long-queuing-delay", + "weight": 0.0 + }, { "group": "load-opportunities", "id": "render-blocking-resources", @@ -4112,6 +4126,24 @@ "name": "lh:computed:EstimatedInputLatency", "startTime": 0.0 }, + { + "duration": 100.0, + "entryType": "measure", + "name": "lh:audit:cumulative-long-queuing-delay", + "startTime": 0.0 + }, + { + "duration": 100.0, + "entryType": "measure", + "name": "lh:computed:CumulativeLongQueuingDelay", + "startTime": 0.0 + }, + { + "duration": 100.0, + "entryType": "measure", + "name": "lh:computed:Interactive", + "startTime": 0.0 + }, { "duration": 100.0, "entryType": "measure", From 43896afb37785c9cb9a9a3bd88e8841d8e729d15 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Wed, 5 Jun 2019 02:12:41 +0200 Subject: [PATCH 012/110] core(perf): speed up tap-target's isVisible() (#9056) --- .../test/fixtures/seo/seo-tap-targets.html | 18 ++++++++++ .../test/smokehouse/seo/expectations.js | 33 +++++++++++++++++++ .../gather/gatherers/seo/tap-targets.js | 32 ++---------------- lighthouse-core/lib/page-functions.js | 6 ++-- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/lighthouse-cli/test/fixtures/seo/seo-tap-targets.html b/lighthouse-cli/test/fixtures/seo/seo-tap-targets.html index 9f76e82d8a12..25bd225636c0 100644 --- a/lighthouse-cli/test/fixtures/seo/seo-tap-targets.html +++ b/lighthouse-cli/test/fixtures/seo/seo-tap-targets.html @@ -159,6 +159,24 @@

SEO Tap targets



+ + + +

+ diff --git a/lighthouse-viewer/app/src/viewer-ui-features.js b/lighthouse-viewer/app/src/viewer-ui-features.js index 0cb8a27e1f90..52f1b3407993 100644 --- a/lighthouse-viewer/app/src/viewer-ui-features.js +++ b/lighthouse-viewer/app/src/viewer-ui-features.js @@ -31,7 +31,7 @@ class ViewerUIFeatures extends ReportUIFeatures { // Disable option to save as gist if no callback for saving. if (!this._saveGistCallback) { - const saveGistItem = this._dom.find('.lh-export--gist', this._document); + const saveGistItem = this._dom.find('.lh-tools--gist', this._document); saveGistItem.setAttribute('disabled', 'true'); } } @@ -57,7 +57,7 @@ class ViewerUIFeatures extends ReportUIFeatures { } // Disable save-as-gist option after saving. - const saveGistItem = this._dom.find('.lh-export--gist', this._document); + const saveGistItem = this._dom.find('.lh-tools--gist', this._document); saveGistItem.setAttribute('disabled', 'true'); } } diff --git a/lighthouse-viewer/app/styles/viewer.css b/lighthouse-viewer/app/styles/viewer.css index 9ab58e78125c..a4925187f355 100644 --- a/lighthouse-viewer/app/styles/viewer.css +++ b/lighthouse-viewer/app/styles/viewer.css @@ -116,11 +116,11 @@ } /* open-in-viewer option hidden in Viewer */ -.lh-export__dropdown .lh-export--viewer { +.lh-tools__dropdown .lh-tools--viewer { display: none; } /* open-in-gist option visible in Viewer */ -.lh-export__dropdown .lh-export--gist { +.lh-tools__dropdown .lh-tools--gist { display: block !important; } From cb32e4ec022c0e7be6c0c394e7c2594c83201032 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 10 Jun 2019 10:51:51 -0400 Subject: [PATCH 026/110] docs(readme): related project: lighthouse-persist (#9161) --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index c0ce1e340842..50d447e5c40e 100644 --- a/readme.md +++ b/readme.md @@ -318,6 +318,7 @@ Other awesome open source projects that use Lighthouse. * **[lighthouse-lambda](https://github.com/joytocode/lighthouse-lambda)** - Run Lighthouse on AWS Lambda with prebuilt stable desktop Headless Chrome. * **[lighthouse-magic-light](https://github.com/manekinekko/lighthouse-magic-light)** set the color of the MagicLight Bluetooth Smart Light Bulb based on Lighthouse score * **[lighthouse-mocha-example](https://github.com/justinribeiro/lighthouse-mocha-example)** - gather performance metrics via Lighthouse and tests them in Mocha +* **[lighthouse-persist](https://github.com/foo-software/lighthouse-persist)** - Run Lighthouse and upload HTML reports to an AWS S3 bucket. * **[lighthouse4u](https://github.com/godaddy/lighthouse4u)** - LH4U provides Google Lighthouse as a service, surfaced by both a friendly UI+API, and backed by Elastic Search for easy querying and visualization. * **[performance-budgets](https://performance-budgets.netlify.com/)** - Easily assert Lighthouse budgets with Docker. * **[pwmetrics](https://github.com/paulirish/pwmetrics/)** - gather performance metrics From 0bb1e59963c078a4b564e54fd65c813b85eb8916 Mon Sep 17 00:00:00 2001 From: cjamcl Date: Tue, 11 Jun 2019 09:57:24 -0700 Subject: [PATCH 027/110] report: make tools menu focus-able (#9169) --- lighthouse-core/report/html/templates.html | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index ffa2f896fd4c..2e6d9cc3238c 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -262,6 +262,14 @@ height: var(--lh-tools-icon-size); cursor: pointer; margin-right: 5px; + /* This is actually a button element, but we want to style it like a transparent div. */ + display: flex; + background: none; + color: inherit; + border: none; + padding: 0; + font: inherit; + outline: inherit; } /* Some features in the tools dropdown menu don't work in the DevTools @@ -278,13 +286,10 @@ .dark .lh-tools__button svg { filter: invert(1); } - .lh-tools__button:focus, - .lh-tools__button.active { - outline: none; - } .lh-tools__button.active + .lh-tools__dropdown { opacity: 1; clip: rect(-1px, 187px, 242px, -3px); + visibility: visible; } .lh-tools__dropdown { position: absolute; @@ -298,6 +303,7 @@ box-shadow: 1px 1px 3px #ccc; min-width: 125px; clip: rect(0, 164px, 0, 0); + visibility: hidden; opacity: 0; transition: all 200ms cubic-bezier(0,0,0.2,1); } @@ -366,12 +372,12 @@
- +
Print Summary From a1bf2aff8aaf68b50840ba45fc17c19651e234c5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Tue, 11 Jun 2019 12:18:51 -0700 Subject: [PATCH 028/110] deps(security): bump extend from 3.0.0 to 3.0.2 (#9184) --- yarn.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 6bc1183b6128..050128c60cdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3224,12 +3224,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" - integrity sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ= - -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== From 162ab75475456f193130480e07a5fbd86f116759 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 11 Jun 2019 13:25:20 -0700 Subject: [PATCH 029/110] proto: update processForProto method signature, string -> LH.Result (#9016) --- clients/lightrider/lightrider-entry.js | 25 ++++++------- lighthouse-core/lib/proto-preprocessor.js | 14 ++++---- .../test/lib/proto-preprocessor-test.js | 33 ++++++++++------- lighthouse-core/test/report/proto-test.js | 35 +++++++++---------- 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/clients/lightrider/lightrider-entry.js b/clients/lightrider/lightrider-entry.js index 5bfb7ce78a02..49cfa55610ea 100644 --- a/clients/lightrider/lightrider-entry.js +++ b/clients/lightrider/lightrider-entry.js @@ -24,9 +24,9 @@ const LR_PRESETS = { * If configOverride is provided, lrDevice and categoryIDs are ignored. * @param {Connection} connection * @param {string} url - * @param {LH.Flags} flags Lighthouse flags, including `output` + * @param {LH.Flags} flags Lighthouse flags * @param {{lrDevice?: 'desktop'|'mobile', categoryIDs?: Array, logAssets: boolean, configOverride?: LH.Config.Json}} lrOpts Options coming from Lightrider - * @return {Promise|void>} + * @return {Promise} */ async function runLighthouseInLR(connection, url, flags, lrOpts) { const {lrDevice, categoryIDs, logAssets, configOverride} = lrOpts; @@ -52,22 +52,17 @@ async function runLighthouseInLR(connection, url, flags, lrOpts) { try { const runnerResult = await lighthouse(url, flags, config, connection); - if (!runnerResult) return; + if (!runnerResult) throw new Error('Lighthouse finished without a runnerResult'); - // pre process the LHR for proto - if (flags.output === 'json' && typeof runnerResult.report === 'string') { - // When LR is called with |internal: {keep_raw_response: true, save_lighthouse_assets: true}|, - // this code will log artifacts to raw_response.artifacts. - if (logAssets) { - // @ts-ignore - Regenerate the report, but tack on the artifacts. - runnerResult.lhr.artifacts = runnerResult.artifacts; - runnerResult.report = JSON.stringify(runnerResult.lhr); - } - - return preprocessor.processForProto(runnerResult.report); + // When LR is called with |internal: {keep_raw_response: true, save_lighthouse_assets: true}|, + // this code will log artifacts to raw_response.artifacts. + if (logAssets) { + // @ts-ignore - piggyback the artifacts on the LHR. + runnerResult.lhr.artifacts = runnerResult.artifacts; } - return runnerResult.report; + // pre process the LHR for proto + return JSON.stringify(preprocessor.processForProto(runnerResult.lhr)); } catch (err) { // If an error ruined the entire lighthouse run, attempt to return a meaningful error. let runtimeError; diff --git a/lighthouse-core/lib/proto-preprocessor.js b/lighthouse-core/lib/proto-preprocessor.js index 0db83e1fe345..7f5142b9563d 100644 --- a/lighthouse-core/lib/proto-preprocessor.js +++ b/lighthouse-core/lib/proto-preprocessor.js @@ -16,11 +16,13 @@ const fs = require('fs'); */ /** - * @param {string} result + * Transform an LHR into a proto-friendly, mostly-compatible LHR. + * @param {LH.Result} lhr + * @return {LH.Result} */ -function processForProto(result) { +function processForProto(lhr) { /** @type {LH.Result} */ - const reportJson = JSON.parse(result); + const reportJson = JSON.parse(JSON.stringify(lhr)); // Clean up the configSettings // Note: This is not strictly required for conversion if protobuf parsing is set to @@ -95,7 +97,7 @@ function processForProto(result) { removeStrings(reportJson); - return JSON.stringify(reportJson); + return reportJson; } // @ts-ignore claims always false, but this checks if cli or module @@ -113,9 +115,9 @@ if (require.main === module) { if (input && output) { // process the file - const report = processForProto(fs.readFileSync(input, 'utf-8')); + const report = processForProto(JSON.parse(fs.readFileSync(input, 'utf-8'))); // write to output from argv - fs.writeFileSync(output, report, 'utf-8'); + fs.writeFileSync(output, JSON.stringify(report), 'utf-8'); } } else { module.exports = { diff --git a/lighthouse-core/test/lib/proto-preprocessor-test.js b/lighthouse-core/test/lib/proto-preprocessor-test.js index ca1761c88a52..1057a0bbe641 100644 --- a/lighthouse-core/test/lib/proto-preprocessor-test.js +++ b/lighthouse-core/test/lib/proto-preprocessor-test.js @@ -5,10 +5,17 @@ */ 'use strict'; -const processForProto = require('../../lib/proto-preprocessor.js').processForProto; +const {processForProto} = require('../../lib/proto-preprocessor.js'); +const sampleJson = require('../results/sample_v2.json'); /* eslint-env jest */ describe('processing for proto', () => { + it('doesn\'t modify the input object', () => { + const input = JSON.parse(JSON.stringify(sampleJson)); + processForProto(input); + expect(input).toEqual(sampleJson); + }); + it('keeps only necessary configSettings', () => { const input = { 'configSettings': { @@ -44,9 +51,9 @@ describe('processing for proto', () => { 'onlyCategories': null, }, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).toMatchObject(expectation); + expect(output).toMatchObject(expectation); }); it('cleans up default runtimeErrors', () => { @@ -56,9 +63,9 @@ describe('processing for proto', () => { }, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).not.toHaveProperty('runtimeError'); + expect(output).not.toHaveProperty('runtimeError'); }); it('non-default runtimeErrors are untouched', () => { @@ -68,9 +75,9 @@ describe('processing for proto', () => { }, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).toMatchObject(input); + expect(output).toMatchObject(input); }); it('cleans up audits', () => { @@ -91,9 +98,9 @@ describe('processing for proto', () => { }, }, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).toMatchObject(expectation); + expect(output).toMatchObject(expectation); }); @@ -108,9 +115,9 @@ describe('processing for proto', () => { const expectation = { 'i18n': {}, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).toMatchObject(expectation); + expect(output).toMatchObject(expectation); }); it('removes empty strings', () => { @@ -151,8 +158,8 @@ describe('processing for proto', () => { ], }, }; - const output = processForProto(JSON.stringify(input)); + const output = processForProto(input); - expect(JSON.parse(output)).toMatchObject(expectation); + expect(output).toMatchObject(expectation); }); }); diff --git a/lighthouse-core/test/report/proto-test.js b/lighthouse-core/test/report/proto-test.js index a7d051c8b474..4425924c7992 100644 --- a/lighthouse-core/test/report/proto-test.js +++ b/lighthouse-core/test/report/proto-test.js @@ -5,60 +5,57 @@ */ 'use strict'; -const path = require('path'); -const fs = require('fs'); - -const sample = fs.readFileSync(path.resolve(__dirname, '../results/sample_v2.json')); +const sampleJson = require('../results/sample_v2.json'); const roundTripJson = require('../../../proto/sample_v2_round_trip.json'); const preprocessor = require('../../lib/proto-preprocessor.js'); /* eslint-env jest */ describe('round trip JSON comparison subsets', () => { - let sampleJson; + let processedLHR; beforeEach(() => { - sampleJson = JSON.parse(preprocessor.processForProto(sample)); + processedLHR = preprocessor.processForProto(sampleJson); }); it('has the same audit results and details (if applicable)', () => { - for (const auditId of Object.keys(sampleJson.audits)) { - expect(roundTripJson.audits[auditId]).toEqual(sampleJson.audits[auditId]); + for (const auditId of Object.keys(processedLHR.audits)) { + expect(roundTripJson.audits[auditId]).toEqual(processedLHR.audits[auditId]); } }); it('has the same i18n rendererFormattedStrings', () => { - expect(roundTripJson.i18n).toMatchObject(sampleJson.i18n); + expect(roundTripJson.i18n).toMatchObject(processedLHR.i18n); }); it('has the same top level values', () => { // Don't test all top level properties that are objects. - Object.keys(sampleJson).forEach(audit => { - if (typeof sampleJson[audit] === 'object' && !Array.isArray(sampleJson[audit])) { - delete sampleJson[audit]; + Object.keys(processedLHR).forEach(audit => { + if (typeof processedLHR[audit] === 'object' && !Array.isArray(processedLHR[audit])) { + delete processedLHR[audit]; } }); // Properties set to their type's default value will be omitted in the roundTripJson. // For an explicit list of properties, remove sampleJson values if set to a default. - if (Array.isArray(sampleJson.stackPacks) && sampleJson.stackPacks.length === 0) { - delete sampleJson.stackPacks; + if (Array.isArray(processedLHR.stackPacks) && processedLHR.stackPacks.length === 0) { + delete processedLHR.stackPacks; } - expect(roundTripJson).toMatchObject(sampleJson); + expect(roundTripJson).toMatchObject(processedLHR); }); it('has the same config values', () => { // Config settings from proto round trip should be a subset of the actual settings. - expect(sampleJson.configSettings).toMatchObject(roundTripJson.configSettings); + expect(processedLHR.configSettings).toMatchObject(roundTripJson.configSettings); }); }); describe('round trip JSON comparison to everything', () => { - let sampleJson; + let processedLHR; beforeEach(() => { - sampleJson = JSON.parse(preprocessor.processForProto(sample)); + processedLHR = preprocessor.processForProto(sampleJson); // Proto conversion turns empty summaries into null. This is OK, // and is handled in the PSI roundtrip just fine, but messes up the easy @@ -71,6 +68,6 @@ describe('round trip JSON comparison to everything', () => { }); it('has the same JSON overall', () => { - expect(sampleJson).toMatchObject(roundTripJson); + expect(processedLHR).toMatchObject(roundTripJson); }); }); From f8971e2f240ad73042218ade0f0d14999e4186d3 Mon Sep 17 00:00:00 2001 From: cjamcl Date: Tue, 11 Jun 2019 13:55:07 -0700 Subject: [PATCH 030/110] report: only print light theme (#9173) --- lighthouse-core/report/html/report-styles.css | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css index f7690d342391..62d1cb231ca9 100644 --- a/lighthouse-core/report/html/report-styles.css +++ b/lighthouse-core/report/html/report-styles.css @@ -144,37 +144,39 @@ --pwa-optimized-color-url: url('data:image/svg+xml;utf8,'); } -.lh-vars.dark { - --color-red-700: var(--color-red); - --color-green-700: var(--color-green); - --color-teal-600: var(--color-cyan-500); - --color-orange-700: var(--color-orange); - - --color-black-200: var(--color-black-800); - --color-black-400: var(--color-black-600); - --color-black-600: var(--color-black-500); - - --topbar-bg: var(--color-black); - --plugin-badge-bg: var(--color-black-800); - --env-item-bg: var(--color-black); - --report-secondary-border-color: var(--color-black-200); - - --body-background-color: var(--color-black-900); - --body-text-color: var(--color-black-100); - --secondary-text-color: var(--color-black-400); - - --plugin-icon-url: var(--plugin-icon-url-dark); - - --informative-color: var(--color-blue-200); - - --medium-50-gray: #757575; - --medium-75-gray: var(--color-white); - - --color-hover: rgba(0, 0, 0, 0.2); - - --pwa-fast-reliable-gray-url: var(--pwa-fast-reliable-gray-url-dark); - --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark); - --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark); +@media not print { + .lh-vars.dark { + --color-red-700: var(--color-red); + --color-green-700: var(--color-green); + --color-teal-600: var(--color-cyan-500); + --color-orange-700: var(--color-orange); + + --color-black-200: var(--color-black-800); + --color-black-400: var(--color-black-600); + --color-black-600: var(--color-black-500); + + --topbar-bg: var(--color-black); + --plugin-badge-bg: var(--color-black-800); + --env-item-bg: var(--color-black); + --report-secondary-border-color: var(--color-black-200); + + --body-background-color: var(--color-black-900); + --body-text-color: var(--color-black-100); + --secondary-text-color: var(--color-black-400); + + --plugin-icon-url: var(--plugin-icon-url-dark); + + --informative-color: var(--color-blue-200); + + --medium-50-gray: #757575; + --medium-75-gray: var(--color-white); + + --color-hover: rgba(0, 0, 0, 0.2); + + --pwa-fast-reliable-gray-url: var(--pwa-fast-reliable-gray-url-dark); + --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark); + --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark); + } } @media only screen and (max-width: 480px) { From 233f197c7ab12081c569fd61814802863a183290 Mon Sep 17 00:00:00 2001 From: Brendan Kenny Date: Tue, 11 Jun 2019 15:21:31 -0700 Subject: [PATCH 031/110] report: ensure SVG elements in have unique ids (#9151) --- .../html/renderer/pwa-category-renderer.js | 47 +++++++++++++++++++ lighthouse-core/report/html/templates.html | 8 ++-- .../renderer/pwa-category-renderer-test.js | 34 +++++++++++++- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lighthouse-core/report/html/renderer/pwa-category-renderer.js b/lighthouse-core/report/html/renderer/pwa-category-renderer.js index 0c96c60159b7..1b49cff5c0ce 100644 --- a/lighthouse-core/report/html/renderer/pwa-category-renderer.js +++ b/lighthouse-core/report/html/renderer/pwa-category-renderer.js @@ -18,6 +18,16 @@ /* globals self, Util, CategoryRenderer */ +/** + * An always-increasing counter for making unique SVG ID suffixes. + */ +const getUniqueSuffix = (() => { + let svgSuffix = 0; + return function() { + return svgSuffix++; + }; +})(); + class PwaCategoryRenderer extends CategoryRenderer { /** * @param {LH.ReportResult.Category} category @@ -62,6 +72,11 @@ class PwaCategoryRenderer extends CategoryRenderer { tmpl)); wrapper.href = `#${category.id}`; + // Correct IDs in case multiple instances end up in the page. + const svgRoot = tmpl.querySelector('svg'); + if (!svgRoot) throw new Error('no SVG element found in PWA score gauge template'); + PwaCategoryRenderer._makeSvgReferencesUnique(svgRoot); + const allGroups = this._getGroupIds(category.auditRefs); const passingGroupIds = this._getPassingGroupIds(category.auditRefs); @@ -147,6 +162,38 @@ class PwaCategoryRenderer extends CategoryRenderer { return auditsElem; } + + /** + * Alters SVG id references so multiple instances of an SVG element can coexist + * in a single page. If `svgRoot` has a `` block, gives all elements defined + * in it unique ids, then updates id references (``, + * `fill="url(#...)"`) to the altered ids in all descendents of `svgRoot`. + * @param {SVGElement} svgRoot + */ + static _makeSvgReferencesUnique(svgRoot) { + const defsEl = svgRoot.querySelector('defs'); + if (!defsEl) return; + + const idSuffix = getUniqueSuffix(); + const elementsToUpdate = defsEl.querySelectorAll('[id]'); + for (const el of elementsToUpdate) { + const oldId = el.id; + const newId = `${oldId}-${idSuffix}`; + el.id = newId; + + // Update all s. + const useEls = svgRoot.querySelectorAll(`use[href="#${oldId}"]`); + for (const useEl of useEls) { + useEl.setAttribute('href', `#${newId}`); + } + + // Update all fill="url(#...)"s. + const fillEls = svgRoot.querySelectorAll(`[fill="url(#${oldId})"]`); + for (const fillEl of fillEls) { + fillEl.setAttribute('fill', `url(#${newId})`); + } + } + } } if (typeof module !== 'undefined' && module.exports) { diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index 2e6d9cc3238c..50bbed8c2ec8 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -675,24 +675,24 @@ - + - + - + - + diff --git a/lighthouse-core/test/report/html/renderer/pwa-category-renderer-test.js b/lighthouse-core/test/report/html/renderer/pwa-category-renderer-test.js index 8bbe83b1d6a6..e71a81f5d1ad 100644 --- a/lighthouse-core/test/report/html/renderer/pwa-category-renderer-test.js +++ b/lighthouse-core/test/report/html/renderer/pwa-category-renderer-test.js @@ -242,7 +242,7 @@ describe('PwaCategoryRenderer', () => { describe('#renderScoreGauge', () => { it('renders an error score gauge in case of category error', () => { category.score = null; - const badgeGauge = pwaRenderer.renderScoreGauge(category); + const badgeGauge = pwaRenderer.renderScoreGauge(category, sampleResults.categoryGroups); // Not a PWA gauge. assert.strictEqual(badgeGauge.querySelector('.lh-gauge--pwa__wrapper'), null); @@ -251,5 +251,37 @@ describe('PwaCategoryRenderer', () => { assert.strictEqual(percentageElem.textContent, '?'); assert.strictEqual(percentageElem.title, Util.UIStrings.errorLabel); }); + + it('renders score gauges with unique ids for items in ', () => { + const gauge1 = pwaRenderer.renderScoreGauge(category, sampleResults.categoryGroups); + const gauge1Ids = [...gauge1.querySelectorAll('defs [id]')].map(el => el.id); + assert.ok(gauge1Ids.length > 3); + + const gauge2 = pwaRenderer.renderScoreGauge(category, sampleResults.categoryGroups); + const gauge2Ids = [...gauge2.querySelectorAll('defs [id]')].map(el => el.id); + assert.ok(gauge2Ids.length === gauge1Ids.length); + + /** Returns whether id is used by at least one or fill under `rootEl`. */ + function idInUseElOrFillAttr(rootEl, id) { + const isUse = rootEl.querySelector(`use[href="#${id}"]`); + const isFill = rootEl.querySelector(`[fill="url(#${id})"]`); + + return !!(isUse || isFill); + } + + // Check that each gauge1 ID is actually used in gauge1 and isn't used in gauge2. + for (const gauge1Id of gauge1Ids) { + assert.equal(idInUseElOrFillAttr(gauge1, gauge1Id), true); + assert.ok(!gauge2Ids.includes(gauge1Id)); + assert.equal(idInUseElOrFillAttr(gauge2, gauge1Id), false); + } + + // And that the reverse is true for gauge2 IDs. + for (const gauge2Id of gauge2Ids) { + assert.equal(idInUseElOrFillAttr(gauge1, gauge2Id), false); + assert.equal(idInUseElOrFillAttr(gauge2, gauge2Id), true); + assert.ok(!gauge1Ids.includes(gauge2Id)); + } + }); }); }); From 7bcd1b4c84110c83acaa4df18b0c82e905673868 Mon Sep 17 00:00:00 2001 From: Brendan Kenny Date: Tue, 11 Jun 2019 15:31:34 -0700 Subject: [PATCH 032/110] report: position sticky-header highlighter with css grid (#9186) --- lighthouse-core/report/html/renderer/report-ui-features.js | 5 ++--- lighthouse-core/report/html/templates.html | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index 213199757c28..df9583dacf84 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -314,9 +314,8 @@ class ReportUIFeatures { this.scoreScaleEl = this._dom.find('.lh-scorescale', this._document); this.stickyHeaderEl = this._dom.find('.lh-sticky-header', this._document); - // Position highlighter at first gauge; will be transformed on scroll. - const firstGauge = this._dom.find('.lh-gauge__wrapper', this.stickyHeaderEl); - this.highlightEl = this._dom.createChildOf(firstGauge, 'div', 'lh-highlighter'); + // Highlighter will be absolutely positioned at first gauge, then transformed on scroll. + this.highlightEl = this._dom.createChildOf(this.stickyHeaderEl, 'div', 'lh-highlighter'); } /** diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index 50bbed8c2ec8..0323cf54db7d 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -186,7 +186,8 @@ } .lh-sticky-header--visible { - display: flex; + display: grid; + grid-auto-flow: column; pointer-events: auto; } @@ -204,8 +205,10 @@ width: var(--score-container-width); height: 1px; background: var(--color-highlighter-bg); + /* Position at bottom of first gauge in sticky header. */ position: absolute; - bottom: -5px; + grid-column: 1; + bottom: -1px; } .lh-gauge__wrapper:first-of-type { From d18ad42edb165d05d55dd2a67e1b87746887fc07 Mon Sep 17 00:00:00 2001 From: cjamcl Date: Tue, 11 Jun 2019 17:27:47 -0700 Subject: [PATCH 033/110] report(devtools): enable report features (#9157) --- build/build-dt-report-resources.js | 4 ++-- .../report/html/renderer/report-ui-features.js | 8 ++++++-- lighthouse-core/report/html/templates.html | 9 --------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/build/build-dt-report-resources.js b/build/build-dt-report-resources.js index 0e568c59fbac..4793c6243e34 100644 --- a/build/build-dt-report-resources.js +++ b/build/build-dt-report-resources.js @@ -36,8 +36,8 @@ writeFile('templates.html', htmlReportAssets.REPORT_TEMPLATES); const pathToReportAssets = require.resolve('../clients/devtools-report-assets.js'); browserify(generatorFilename, {standalone: 'Lighthouse.ReportGenerator'}) - // Shims './html/html-report-assets' to resolve to devtools-report-assets. - .require(pathToReportAssets, {expose: './html/html-report-assets'}) + // Shims './html/html-report-assets.js' to resolve to devtools-report-assets.js + .require(pathToReportAssets, {expose: './html/html-report-assets.js'}) .bundle((err, src) => { if (err) throw err; fs.writeFileSync(bundleOutFile, src.toString()); diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index df9583dacf84..ab947a78f319 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -420,12 +420,12 @@ class ReportUIFeatures { case 'print-summary': this.collapseAllDetails(); this.closeToolsDropdown(); - self.print(); + this._print(); break; case 'print-expanded': this.expandAllDetails(); this.closeToolsDropdown(); - self.print(); + this._print(); break; case 'save-json': { const jsonStr = JSON.stringify(this.json, null, 2); @@ -462,6 +462,10 @@ class ReportUIFeatures { this._document.removeEventListener('keydown', this.onKeyDown); } + _print() { + self.print(); + } + /** * Keydown handler for the document. * @param {KeyboardEvent} e diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index 0323cf54db7d..01498480b615 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -274,15 +274,6 @@ font: inherit; outline: inherit; } - /* - Some features in the tools dropdown menu don't work in the DevTools - client. They could with some tweaks, but currently they don't. For example: - Saving as HTML/JSON - does not bring up a file dialog, as one would expect in DevTools. - also, it saves the AuditsPanel HTML, which is funky. - */ - .lh-devtools .lh-tools__button { - display: none; - } .lh-tools__button svg { fill: var(--lh-tools-icon-color); } From 8ff0330726c0652c2cbc06015f1349ac329bf924 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 11 Jun 2019 17:59:04 -0700 Subject: [PATCH 034/110] report: update permalink calculations for correct hash nav scroll position (#9188) --- lighthouse-core/report/html/report-styles.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css index 62d1cb231ca9..d1752a9dc00e 100644 --- a/lighthouse-core/report/html/report-styles.css +++ b/lighthouse-core/report/html/report-styles.css @@ -39,7 +39,6 @@ --display-value-gray: hsl(216, 5%, 39%); --report-width: calc(60 * var(--body-font-size)); --report-min-width: 400px; - --report-header-height: 161px; --lh-score-icon-background-size: 24px; --lh-tools-icon-size: var(--lh-score-icon-background-size); --lh-tools-icon-color: var(--medium-75-gray); @@ -1212,8 +1211,10 @@ https://css-tricks.com/hash-tag-links-padding/ */ .lh-category > .lh-permalink { - margin-top: calc((var(--report-header-height) + var(--default-padding)) * -1); - padding-bottom: calc(var(--report-header-height) + var(--default-padding)); + --sticky-header-height: calc(var(--gauge-circle-size) + var(--score-container-padding) * 2); + --topbar-plus-header: calc(var(--topbar-height) + var(--sticky-header-height)); + margin-top: calc(var(--topbar-plus-header) * -1); + padding-bottom: var(--topbar-plus-header); display: block; visibility: hidden; } From 0c4f2a72fabd6445c41b6d0183cc00f52c4d514f Mon Sep 17 00:00:00 2001 From: Justin Ribeiro Date: Wed, 12 Jun 2019 07:59:46 -0700 Subject: [PATCH 035/110] docs(readme): related project: lighthouse-jest-example (#9172) --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 50d447e5c40e..9008202926e7 100644 --- a/readme.md +++ b/readme.md @@ -315,6 +315,7 @@ Other awesome open source projects that use Lighthouse. * **[lighthouse-cron](https://github.com/thearegee/lighthouse-cron)** - Cron multiple batch Lighthouse audits and emit results for sending to remote server. * **[lighthouse-gh-reporter](https://github.com/carlesnunez/lighthouse-gh-reporter)** - Run Lighthouse in CI and report back in a comment on your pull requests * **[lighthouse-hue](https://github.com/ebidel/lighthouse-hue)** - set the color of Philips Hue lights based on a Lighthouse score +* **[lighthouse-jest-example](https://github.com/justinribeiro/lighthouse-jest-example)** - gather performance metrics via Lighthouse and assert results with Jest; uses Puppeteer to start Chrome with network emulation settings defined by WebPageTest. * **[lighthouse-lambda](https://github.com/joytocode/lighthouse-lambda)** - Run Lighthouse on AWS Lambda with prebuilt stable desktop Headless Chrome. * **[lighthouse-magic-light](https://github.com/manekinekko/lighthouse-magic-light)** set the color of the MagicLight Bluetooth Smart Light Bulb based on Lighthouse score * **[lighthouse-mocha-example](https://github.com/justinribeiro/lighthouse-mocha-example)** - gather performance metrics via Lighthouse and tests them in Mocha From 6c90731af4d7b4c2aca107da6c18edf6fab9584b Mon Sep 17 00:00:00 2001 From: Shane Exterkamp Date: Wed, 12 Jun 2019 11:40:26 -0400 Subject: [PATCH 036/110] i18n: add es-419 (#9171) --- lighthouse-core/lib/i18n/locales.js | 25 + lighthouse-core/lib/i18n/locales/es-419.json | 1064 ++++++++++++++++++ lighthouse-core/lib/i18n/locales/pt.json | 2 +- types/externs.d.ts | 2 +- 4 files changed, 1091 insertions(+), 2 deletions(-) create mode 100644 lighthouse-core/lib/i18n/locales/es-419.json diff --git a/lighthouse-core/lib/i18n/locales.js b/lighthouse-core/lib/i18n/locales.js index 273f778b72e6..37f76548cd8f 100644 --- a/lighthouse-core/lib/i18n/locales.js +++ b/lighthouse-core/lib/i18n/locales.js @@ -40,6 +40,31 @@ const locales = { 'el': require('./locales/el.json'), 'en-XA': require('./locales/en-XA.json'), // psuedolocalization 'es': require('./locales/es.json'), + 'es-419': require('./locales/es-419.json'), + // Aliases of es-419: https://raw.githubusercontent.com/unicode-cldr/cldr-core/master/supplemental/parentLocales.json + 'es-AR': require('./locales/es-419.json'), + 'es-BO': require('./locales/es-419.json'), + 'es-BR': require('./locales/es-419.json'), + 'es-BZ': require('./locales/es-419.json'), + 'es-CL': require('./locales/es-419.json'), + 'es-CO': require('./locales/es-419.json'), + 'es-CR': require('./locales/es-419.json'), + 'es-CU': require('./locales/es-419.json'), + 'es-DO': require('./locales/es-419.json'), + 'es-EC': require('./locales/es-419.json'), + 'es-GT': require('./locales/es-419.json'), + 'es-HN': require('./locales/es-419.json'), + 'es-MX': require('./locales/es-419.json'), + 'es-NI': require('./locales/es-419.json'), + 'es-PA': require('./locales/es-419.json'), + 'es-PE': require('./locales/es-419.json'), + 'es-PR': require('./locales/es-419.json'), + 'es-PY': require('./locales/es-419.json'), + 'es-SV': require('./locales/es-419.json'), + 'es-US': require('./locales/es-419.json'), + 'es-UY': require('./locales/es-419.json'), + 'es-VE': require('./locales/es-419.json'), + 'fi': require('./locales/fi.json'), 'fil': require('./locales/fil.json'), 'fr': require('./locales/fr.json'), // fr-CH identical, so it falls back into fr diff --git a/lighthouse-core/lib/i18n/locales/es-419.json b/lighthouse-core/lib/i18n/locales/es-419.json new file mode 100644 index 000000000000..2e594f377580 --- /dev/null +++ b/lighthouse-core/lib/i18n/locales/es-419.json @@ -0,0 +1,1064 @@ +{ + "lighthouse-core/audits/accessibility/accesskeys.js | description": { + "message": "Las claves de acceso permiten a los usuarios dirigirse rápidamente a una parte concreta de la página. Para facilitar una navegación correcta, las claves de acceso deben ser únicas. [Más información](https://dequeuniversity.com/rules/axe/3.1/accesskeys?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/accesskeys.js | failureTitle": { + "message": "Los valores de \"[accesskey]\" no son únicos" + }, + "lighthouse-core/audits/accessibility/accesskeys.js | title": { + "message": "Los valores de \"[accesskey]\" son únicos" + }, + "lighthouse-core/audits/accessibility/aria-allowed-attr.js | description": { + "message": "Cada función de ARIA admite un subconjunto determinado de atributos \"aria-*\". Si no coinciden, se invalidarán los atributos \"aria-*\". [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-allowed-attr?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-allowed-attr.js | failureTitle": { + "message": "Los atributos \"[aria-*]\" no se corresponden con sus funciones" + }, + "lighthouse-core/audits/accessibility/aria-allowed-attr.js | title": { + "message": "Los atributos \"[aria-*]\" se corresponden con sus funciones" + }, + "lighthouse-core/audits/accessibility/aria-required-attr.js | description": { + "message": "Algunas funciones de ARIA incluyen atributos obligatorios que describen el estado del elemento a los lectores de pantalla. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-required-attr?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-required-attr.js | failureTitle": { + "message": "\"[role]\" no incluyen todos los atributos \"[aria-*]\" necesarios" + }, + "lighthouse-core/audits/accessibility/aria-required-attr.js | title": { + "message": "\"[role]\" incluyen todos los atributos \"[aria-*]\" necesarios" + }, + "lighthouse-core/audits/accessibility/aria-required-children.js | description": { + "message": "Algunas funciones principales de ARIA deben contener funciones secundarias específicas para llevar a cabo las funciones de accesibilidad correspondientes. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-required-children?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-required-children.js | failureTitle": { + "message": "Faltan elementos con atributos \"[role]\" que requieren otros atributos \"[role]\" secundarios específicos." + }, + "lighthouse-core/audits/accessibility/aria-required-children.js | title": { + "message": "Se incluyeron los elementos con atributos \"[role]\" que requieren otros atributos \"[role]\" secundarios específicos" + }, + "lighthouse-core/audits/accessibility/aria-required-parent.js | description": { + "message": "Algunas funciones secundarias de ARIA se deben incluir dentro de funciones principales concretas para poder llevar a cabo las funciones de accesibilidad correspondientes. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-required-parent?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-required-parent.js | failureTitle": { + "message": "Los atributos \"[role]\" no se incluyen en los elementos principales necesarios" + }, + "lighthouse-core/audits/accessibility/aria-required-parent.js | title": { + "message": "Los atributos \"[role]\" están incluidos en los elementos principales correspondientes" + }, + "lighthouse-core/audits/accessibility/aria-roles.js | description": { + "message": "Las funciones de ARIA deben tener valores válidos para realizar las funciones de accesibilidad correspondientes. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-roles?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-roles.js | failureTitle": { + "message": "Los valores de \"[role]\" no son válidos" + }, + "lighthouse-core/audits/accessibility/aria-roles.js | title": { + "message": "Los valores de \"[role]\" son válidos" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr-value.js | description": { + "message": "Las tecnologías asistivas, como lectores de pantalla, no pueden interpretar atributos ARIA con valores no válidos. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr-value?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr-value.js | failureTitle": { + "message": "Los atributos \"[aria-*]\" no tienen valores válidos" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr-value.js | title": { + "message": "Los atributos \"[aria-*]\" tienen un valor válido" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr.js | description": { + "message": "Las tecnologías de asistencia, como los lectores de pantalla, no pueden interpretar los atributos ARIA cuyos valores no sean válidos. [Más información](https://dequeuniversity.com/rules/axe/3.1/aria-valid-attr?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr.js | failureTitle": { + "message": "Los atributos \"[aria-*]\" no son válidos o no están bien escritos" + }, + "lighthouse-core/audits/accessibility/aria-valid-attr.js | title": { + "message": "Los atributos \"[aria-*]\" son válidos y están bien escritos" + }, + "lighthouse-core/audits/accessibility/audio-caption.js | description": { + "message": "Los subtítulos permiten que los elementos de audio sean útiles para usuarios sordos o con problemas de audición, dado que proporcionan información fundamental, como identificar quién habla, lo que dicen y otros sonidos no verbales. [Más información](https://dequeuniversity.com/rules/axe/3.1/audio-caption?application=lighthouse)" + }, + "lighthouse-core/audits/accessibility/audio-caption.js | failureTitle": { + "message": "Falta un elemento \"\" con \"[kind=\"captions\"]\" en los elementos \"
diff --git a/lighthouse-core/test/report/html/renderer/crc-details-renderer-test.js b/lighthouse-core/test/report/html/renderer/crc-details-renderer-test.js index 79de69ef5d6d..f5d8ca14ce6a 100644 --- a/lighthouse-core/test/report/html/renderer/crc-details-renderer-test.js +++ b/lighthouse-core/test/report/html/renderer/crc-details-renderer-test.js @@ -13,6 +13,7 @@ const jsdom = require('jsdom'); const URL = require('../../../../lib/url-shim.js'); const Util = require('../../../../report/html/renderer/util.js'); const DOM = require('../../../../report/html/renderer/dom.js'); +const DetailsRenderer = require('../../../../report/html/renderer/details-renderer.js'); const CriticalRequestChainRenderer = require('../../../../report/html/renderer/crc-details-renderer.js'); @@ -75,12 +76,14 @@ const DETAILS = { describe('DetailsRenderer', () => { let dom; + let detailsRenderer; beforeAll(() => { global.URL = URL; global.Util = Util; const {document} = new jsdom.JSDOM(TEMPLATE_FILE).window; dom = new DOM(document); + detailsRenderer = new DetailsRenderer(dom); }); afterAll(() => { @@ -89,18 +92,25 @@ describe('DetailsRenderer', () => { }); it('renders tree structure', () => { - const el = CriticalRequestChainRenderer.render(dom, dom.document(), DETAILS); + const el = CriticalRequestChainRenderer.render(dom, dom.document(), DETAILS, detailsRenderer); const chains = el.querySelectorAll('.crc-node'); // Main request assert.equal(chains.length, 4, 'generates correct number of chain nodes'); - assert.equal(chains[0].querySelector('.crc-node__tree-hostname').textContent, '(example.com)'); + assert.ok(!chains[0].querySelector('.lh-text__url-host'), 'should be no origin for root url'); + assert.equal(chains[0].querySelector('.lh-text__url a').textContent, 'https://example.com'); + assert.equal(chains[0].querySelector('.lh-text__url a').href, 'https://example.com/'); + assert.equal(chains[0].querySelector('.lh-text__url a').rel, 'noopener'); + assert.equal(chains[0].querySelector('.lh-text__url a').target, '_blank'); // Children assert.ok(chains[1].querySelector('.crc-node__tree-marker .vert-right')); assert.equal(chains[1].querySelectorAll('.crc-node__tree-marker .right').length, 2); - assert.equal(chains[1].querySelector('.crc-node__tree-file').textContent, '/b.js'); - assert.equal(chains[1].querySelector('.crc-node__tree-hostname').textContent, '(example.com)'); + assert.equal(chains[1].querySelector('.lh-text__url a').textContent, '/b.js'); + assert.equal(chains[1].querySelector('.lh-text__url a').href, 'https://example.com/b.js'); + assert.equal(chains[1].querySelector('.lh-text__url a').rel, 'noopener'); + assert.equal(chains[1].querySelector('.lh-text__url a').target, '_blank'); + assert.equal(chains[1].querySelector('.lh-text__url-host').textContent, '(example.com)'); const durationNodes = chains[1].querySelectorAll('.crc-node__chain-duration'); assert.equal(durationNodes[0].textContent, ' - 5,000\xa0ms, '); // Note: actual transferSize is 2000 bytes but formatter formats to KBs. diff --git a/lighthouse-core/test/report/html/renderer/details-renderer-test.js b/lighthouse-core/test/report/html/renderer/details-renderer-test.js index 261172a7356c..ba7cf34c7dfd 100644 --- a/lighthouse-core/test/report/html/renderer/details-renderer-test.js +++ b/lighthouse-core/test/report/html/renderer/details-renderer-test.js @@ -405,7 +405,10 @@ describe('DetailsRenderer', () => { assert.equal(urlEl.localName, 'div'); assert.equal(urlEl.title, urlText); assert.equal(urlEl.dataset.url, urlText); - assert.ok(urlEl.firstChild.classList.contains('lh-text')); + assert.equal(urlEl.firstChild.nodeName, 'A'); + assert.equal(urlEl.firstChild.href, urlText); + assert.equal(urlEl.firstChild.rel, 'noopener'); + assert.equal(urlEl.firstChild.target, '_blank'); assert.equal(urlEl.textContent, displayUrlText); }); @@ -430,7 +433,7 @@ describe('DetailsRenderer', () => { assert.equal(urlEl.localName, 'div'); assert.equal(urlEl.title, urlText); assert.equal(urlEl.dataset.url, urlText); - assert.ok(urlEl.firstChild.classList.contains('lh-text')); + assert.equal(urlEl.firstChild.nodeName, 'A'); assert.equal(urlEl.textContent, displayUrlText); }); diff --git a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js index d706fc4f82fd..2beb09fec0b0 100644 --- a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js +++ b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js @@ -185,7 +185,7 @@ describe('ReportUIFeatures', () => { function getUrlsInTable() { return dom - .findAll('#uses-webp-images .lh-details .lh-text__url .lh-text:first-child', container) + .findAll('#uses-webp-images .lh-details .lh-text__url a:first-child', container) .map(el => el.textContent); } From 0da300a45d001887dd0a373c1eafcbd3e048c68d Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Sat, 29 Jun 2019 00:02:19 -0700 Subject: [PATCH 070/110] misc(build): create error-y LHR for the deploy (#9283) --- .../build-report-for-autodeployment.js | 97 +++++++++++++++++-- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/lighthouse-core/scripts/build-report-for-autodeployment.js b/lighthouse-core/scripts/build-report-for-autodeployment.js index 5bfab5d568d7..7fdc9d06a71a 100644 --- a/lighthouse-core/scripts/build-report-for-autodeployment.js +++ b/lighthouse-core/scripts/build-report-for-autodeployment.js @@ -14,32 +14,33 @@ const mkdirp = require('mkdirp').sync; const swapLocale = require('../lib/i18n/swap-locale.js'); const ReportGenerator = require('../../lighthouse-core/report/report-generator.js'); +const {defaultSettings} = require('../config/constants.js'); +const lighthouse = require('../index.js'); const lhr = /** @type {LH.Result} */ (require('../../lighthouse-core/test/results/sample_v2.json')); const DIST = path.join(__dirname, `../../dist`); -// Add a plugin to demo plugin rendering. -lhr.categories['lighthouse-plugin-someplugin'] = { - id: 'lighthouse-plugin-someplugin', - title: 'Plugin', - score: 0.5, - auditRefs: [], -}; - (async function() { + addPluginCategory(lhr); + const errorLhr = await generateErrorLHR(); + const filenameToLhr = { 'english': lhr, 'espanol': swapLocale(lhr, 'es').lhr, 'arabic': swapLocale(lhr, 'ar').lhr, + 'xl-accented': swapLocale(lhr, 'en-XL').lhr, + 'error': errorLhr, }; - mkdirp(DIST); - // Generate and write reports Object.entries(filenameToLhr).forEach(([filename, lhr]) => { let html = ReportGenerator.generateReportHtml(lhr); + // TODO: PSI is another variant to consider for (const variant of ['', '-devtools']) { if (variant === '-devtools') { + // TODO: Make the DevTools Audits panel "emulation" more comprehensive + // - the parent widget/vbox container with overflow + // - a more constrained/realistic default size html = html.replace(`"lh-root lh-vars"`, `"lh-root lh-vars lh-devtools"`); } const filepath = `${DIST}/${filename}${variant}/index.html`; @@ -49,3 +50,79 @@ lhr.categories['lighthouse-plugin-someplugin'] = { } }); })(); + +/** + * Add a plugin to demo plugin rendering. + * @param {LH.Result} lhr + */ +function addPluginCategory(lhr) { + lhr.categories['lighthouse-plugin-someplugin'] = { + id: 'lighthouse-plugin-someplugin', + title: 'Plugin', + score: 0.5, + auditRefs: [], + }; +} + +/** + * Generate an LHR with errors for the renderer to display. + * We'll write an "empty" artifacts file to disk, only to use it in auditMode. + * @return {Promise} + */ +async function generateErrorLHR() { + /** @type {LH.BaseArtifacts} */ + const artifacts = { + fetchTime: '2019-06-26T23:56:58.381Z', + LighthouseRunWarnings: [ + `Something went wrong with recording the trace over your page load. Please run Lighthouse again. (NO_FCP)`, // eslint-disable-line max-len + ], + TestedAsMobileDevice: true, + HostUserAgent: 'Mozilla/5.0 ErrorUserAgent Chrome/66', + NetworkUserAgent: 'Mozilla/5.0 ErrorUserAgent Chrome/66', + BenchmarkIndex: 1000, + WebAppManifest: null, + Stacks: [], + settings: defaultSettings, + URL: { + requestedUrl: 'http://fakeurl.com', + finalUrl: 'http://fakeurl.com', + }, + Timing: [], + PageLoadError: null, + devtoolsLogs: {}, + traces: {}, + }; + + // Save artifacts to disk then run `lighthouse -G` with them. + const TMP = `${DIST}/.tmp/`; + mkdirp(TMP); + fs.writeFileSync(`${TMP}/artifacts.json`, JSON.stringify(artifacts), 'utf-8'); + const errorRunnerResult = await lighthouse(artifacts.URL.requestedUrl, {auditMode: TMP}); + + if (!errorRunnerResult) throw new Error('Failed to run lighthouse on empty artifacts'); + const errorLhr = errorRunnerResult.lhr; + + // Add audit warnings to font-display + errorLhr.audits['font-display'].warnings = [ + 'Lighthouse was unable to automatically check the font-display value for the following URL: https://secure-ds.serving-sys.com/resources/PROD/html5/105657/20190307/1074580285/43862346571980472/fonts/IBMPlexSans-Light-Latin1.woff.', + 'Lighthouse was unable to automatically check the font-display value for the following URL: https://secure-ds.serving-sys.com/resources/PROD/html5/105657/20190307/1074580285/43862346571980472/fonts/IBMPlexSans-Bold-Latin1.woff.', + ]; + // perf/offscreen-images - set as passing but with a warning + const offscreenImagesAudit = errorLhr.audits['offscreen-images']; + offscreenImagesAudit.warnings = [ + 'Invalid image sizing information: https://cdn.cnn.com/cnn/.e1mo/img/4.0/vr/vr_new_asset.png', + ]; + offscreenImagesAudit.errorMessage = undefined; + offscreenImagesAudit.scoreDisplayMode = 'binary'; + offscreenImagesAudit.score = 1; + // pwa-apple-touch-icon - set as passing but with a warning + const appleTouchIconAudit = errorLhr.audits['apple-touch-icon']; + appleTouchIconAudit.warnings = [ + '`apple-touch-icon-precomposed` is out of date; `apple-touch-icon` is preferred.', + ]; + appleTouchIconAudit.errorMessage = undefined; + appleTouchIconAudit.scoreDisplayMode = 'binary'; + appleTouchIconAudit.score = 1; + + return errorLhr; +} From 29f56670d1061eedf68ba52bd8380aab9227e4b8 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Mon, 1 Jul 2019 13:18:17 -0700 Subject: [PATCH 071/110] report: remove unnecessary attribute in svg (#9301) --- lighthouse-core/report/html/templates.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index 7bb51410be08..34f1c9698149 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -34,10 +34,10 @@ From 6794e2e603aebe9ebfe979362c83ab5a620ef638 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Mon, 1 Jul 2019 14:37:56 -0700 Subject: [PATCH 072/110] deps(intl): move from devDep to dep (#9309) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a7effe65ebf..12f07f8d1ffc 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,6 @@ "gh-pages": "^2.0.1", "glob": "^7.1.3", "idb-keyval": "2.2.0", - "intl": "^1.2.5", "isomorphic-fetch": "^2.2.1", "jest": "^24.3.0", "jsdom": "^12.2.0", @@ -145,6 +144,7 @@ "details-element-polyfill": "2.2.0", "http-link-header": "^0.8.0", "inquirer": "^3.3.0", + "intl": "^1.2.5", "intl-messageformat": "^2.2.0", "intl-messageformat-parser": "^1.4.0", "jpeg-js": "0.1.2", From b751de512b3026fe7c5d35596afb362b1287a3f6 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Mon, 1 Jul 2019 14:55:05 -0700 Subject: [PATCH 073/110] deps(brfs): upgrade to 2.0.2 to resolve source map debug issue (#9312) --- build/build-bundle.js | 7 +- package.json | 2 +- yarn.lock | 155 +++++++++++++++++++++++++++++++----------- 3 files changed, 122 insertions(+), 42 deletions(-) diff --git a/build/build-bundle.js b/build/build-bundle.js index d7ade6ebf075..356f4c86c917 100644 --- a/build/build-bundle.js +++ b/build/build-bundle.js @@ -39,6 +39,7 @@ const isDevtools = file => path.basename(file).includes('devtools'); const isExtension = file => path.basename(file).includes('extension'); const BANNER = `// lighthouse, browserified. ${VERSION} (${COMMIT_HASH})\n`; +const DEBUG = false; // true for sourcemaps /** * Browserify starting at the file at entryPath. Contains entry-point-specific @@ -49,7 +50,7 @@ const BANNER = `// lighthouse, browserified. ${VERSION} (${COMMIT_HASH})\n`; * @return {Promise} */ async function browserifyFile(entryPath, distPath) { - let bundle = browserify(entryPath); // , {debug: true}); // for sourcemaps + let bundle = browserify(entryPath, {debug: DEBUG}); bundle // Transform the fs.readFile etc into inline strings. @@ -138,7 +139,9 @@ function minifyScript(filePath) { */ async function build(entryPath, distPath) { await browserifyFile(entryPath, distPath); - minifyScript(distPath); + if (!DEBUG) { + minifyScript(distPath); + } } /** diff --git a/package.json b/package.json index 12f07f8d1ffc..1b6e5bc1c715 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "babel-core": "^6.26.0", "babel-plugin-syntax-async-generators": "^6.13.0", "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "brfs": "^1.6.1", + "brfs": "^2.0.2", "browserify": "^16.2.3", "bundlesize": "^0.17.2", "chalk": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index da7774d54d66..d18514554fc3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -823,7 +823,7 @@ acorn@^3.0.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= -acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0: +acorn@^5.3.0, acorn@^5.5.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" integrity sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ== @@ -1020,6 +1020,11 @@ array-find-index@^1.0.1: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= +array-from@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" + integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= + array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" @@ -1404,14 +1409,14 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -brfs@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3" - integrity sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ== +brfs@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brfs/-/brfs-2.0.2.tgz#44237878fa82aa479ce4f5fe2c1796ec69f07845" + integrity sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ== dependencies: quote-stream "^1.0.1" resolve "^1.1.5" - static-module "^2.2.0" + static-module "^3.0.2" through2 "^2.0.0" brorand@^1.0.1: @@ -2407,6 +2412,14 @@ cz-customizable@^5.2.0: winston "2.1.0" word-wrap "1.1.0" +d@1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + dargs@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" @@ -2765,11 +2778,41 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: + version "0.10.50" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778" + integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "^1.0.0" + es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +es6-iterator@~2.0.1, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-map@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" @@ -2782,6 +2825,25 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +es6-set@^0.1.5, es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= + dependencies: + d "1" + es5-ext "~0.10.14" + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2921,11 +2983,24 @@ estraverse@~4.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" integrity sha1-9srKcokzqFDvkGYdDheYK6RxEaI= +estree-is-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/estree-is-function/-/estree-is-function-1.0.0.tgz#c0adc29806d7f18a74db7df0f3b2666702e37ad2" + integrity sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA== + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + events@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/events/-/events-2.1.0.tgz#2a9a1e18e6106e0e812aa9ebd4a819b3c29c0ba5" @@ -3082,16 +3157,6 @@ eyes@0.1.x: resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= -falafel@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c" - integrity sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw= - dependencies: - acorn "^5.0.0" - foreach "^2.0.5" - isarray "0.0.1" - object-keys "^1.0.6" - fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -3345,7 +3410,7 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -get-assigned-identifiers@^1.2.0: +get-assigned-identifiers@^1.1.0, get-assigned-identifiers@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== @@ -4228,11 +4293,6 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5481,6 +5541,11 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== +next-tick@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -5667,11 +5732,6 @@ object-inspect@~1.4.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.4.1.tgz#37ffb10e71adaf3748d05f713b4c9452f402cbc4" integrity sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw== -object-keys@^1.0.6: - version "1.0.12" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" - integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== - object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -6270,7 +6330,7 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -quote-stream@^1.0.1, quote-stream@~1.0.2: +quote-stream@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-1.0.2.tgz#84963f8c9c26b942e153feeb53aae74652b7e0b2" integrity sha1-hJY/jJwmuULhU/7rU6rnRlK34LI= @@ -6685,6 +6745,18 @@ saxes@^3.1.3: dependencies: xmlchars "^1.3.1" +scope-analyzer@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/scope-analyzer/-/scope-analyzer-2.0.5.tgz#72c9c6770c3e66984f84c7d3c7045998a1a7db8a" + integrity sha512-+U5H0417mnTEstCD5VwOYO7V4vYuSqwqjFap40ythe67bhMFL5C3UgPwyBv7KDJsqUBIKafOD57xMlh1rN7eaw== + dependencies: + array-from "^2.1.1" + es6-map "^0.1.5" + es6-set "^0.1.5" + es6-symbol "^3.1.1" + estree-is-function "^1.0.0" + get-assigned-identifiers "^1.1.0" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -6991,10 +7063,10 @@ stack-utils@^1.0.1: resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" integrity sha1-1PM6tU6OOHeLDKXP07OvsS22hiA= -static-eval@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.0.tgz#0e821f8926847def7b4b50cda5d55c04a9b13864" - integrity sha512-6flshd3F1Gwm+Ksxq463LtFd1liC77N/PX1FVVc3OzL3hAmo2fwHFbuArkcfi7s9rTNsLEhcRmXGFZhlgy40uw== +static-eval@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" + integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== dependencies: escodegen "^1.8.1" @@ -7006,24 +7078,24 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -static-module@^2.2.0: - version "2.2.5" - resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.5.tgz#bd40abceae33da6b7afb84a0e4329ff8852bfbbf" - integrity sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ== +static-module@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/static-module/-/static-module-3.0.3.tgz#cc2301ed3fe353e2d2a2195137013853676f9960" + integrity sha512-RDaMYaI5o/ym0GkCqL/PlD1Pn216omp8fY81okxZ6f6JQxWW5tptOw9reXoZX85yt/scYvbWIt6uoszeyf+/MQ== dependencies: + acorn-node "^1.3.0" concat-stream "~1.6.0" convert-source-map "^1.5.1" duplexer2 "~0.1.4" escodegen "~1.9.0" - falafel "^2.1.0" has "^1.0.1" magic-string "^0.22.4" merge-source-map "1.0.4" object-inspect "~1.4.0" - quote-stream "~1.0.2" readable-stream "~2.3.3" + scope-analyzer "^2.0.1" shallow-copy "~0.0.1" - static-eval "^2.0.0" + static-eval "^2.0.2" through2 "~2.0.3" stealthy-require@^1.1.0: @@ -7504,6 +7576,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/type/-/type-1.0.1.tgz#084c9a17fcc9151a2cdb1459905c2e45e4bb7d61" + integrity sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" From 9cef08299a2c69a3a81e8da802051b630dffb259 Mon Sep 17 00:00:00 2001 From: remexllee Date: Mon, 8 Jul 2019 18:17:02 -0400 Subject: [PATCH 074/110] tests: improve drag-and-drop coverage (#9314) --- lighthouse-viewer/test/drag-and-drop-test.js | 67 ++++++++++++++------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/lighthouse-viewer/test/drag-and-drop-test.js b/lighthouse-viewer/test/drag-and-drop-test.js index 641c14633af1..7b1d67c78110 100644 --- a/lighthouse-viewer/test/drag-and-drop-test.js +++ b/lighthouse-viewer/test/drag-and-drop-test.js @@ -7,8 +7,6 @@ /* eslint-env jest */ -const assert = require('assert'); - const testHelpers = require('./test-helpers.js'); // Called before other src import so code that relies on `document` and @@ -17,10 +15,6 @@ testHelpers.setupJsDomGlobals(); const DragAndDrop = require('../app/src/drag-and-drop.js'); -function assertUIReset() { - assert.ok(!document.querySelector('.drop_zone').classList.contains('dropping')); -} - describe('DragAndDrop', () => { beforeEach(function() { // Reconstruct page on every test so event listeners are clean. @@ -29,31 +23,62 @@ describe('DragAndDrop', () => { afterEach(testHelpers.cleanupJsDomGlobals); - // TODO: test drop event on document. Callback is not getting called - // because jsdom doesn't support clipboard API: https://github.com/tmpvar/jsdom/issues/1568/. - it.skip('document responds to drag and drop events', done => { - const callback = _ => { - assert.ok(true, 'file change callback is called after drop event'); - done(); + it('document responds to drop event with file', () => { + const mockCallback = jest.fn(); + new DragAndDrop(mockCallback); + + // create custom drop event with mock files in dataTransfer + const event = new window.CustomEvent('drop'); + event.dataTransfer = { + files: ['mock file'], }; + document.dispatchEvent(event); + expect(mockCallback).toBeCalledWith('mock file'); + }); - new DragAndDrop(callback); + it('document ignores drop event without file', () => { + const mockCallback = jest.fn(); + new DragAndDrop(mockCallback); document.dispatchEvent(new window.CustomEvent('drop')); + expect(mockCallback).not.toBeCalled(); + }); + + it('document responds to dragover event with file', () => { + const mockCallback = jest.fn(); + new DragAndDrop(mockCallback); + + const event = new window.CustomEvent('dragover'); + event.dataTransfer = { + files: ['mock file'], + }; + document.dispatchEvent(event); + expect(event.dataTransfer.dropEffect).toEqual('copy'); + }); + + it('document ignores dragover event without file', () => { + const mockCallback = jest.fn(); + new DragAndDrop(mockCallback); + + const event = new window.CustomEvent('dragover'); + document.dispatchEvent(event); + expect(event.dataTransfer).toBeUndefined(); }); - it('document responds to drag and drop events', () => { - // eslint-disable-next-line no-unused-vars - const dragAndDrop = new DragAndDrop(); + it('document responds to mouseleave event when not dragging', () => { + new DragAndDrop(jest.fn); document.dispatchEvent(new window.CustomEvent('mouseleave')); - assertUIReset(); + expect(document.querySelector('.drop_zone').classList.contains('dropping')).toBeFalsy(); + }); + + it('document responds to mouseleave and dragenter events', () => { + new DragAndDrop(jest.fn); document.dispatchEvent(new window.CustomEvent('dragenter')); - assert.ok(document.querySelector('.drop_zone').classList.contains('dropping')); + expect(document.querySelector('.drop_zone').classList.contains('dropping')).toBeTruthy(); - // TODO: see note above about drop event testing. - // document.dispatchEvent(new window.CustomEvent('drop')); - // assertUIReset(); + document.dispatchEvent(new window.CustomEvent('mouseleave')); + expect(document.querySelector('.drop_zone').classList.contains('dropping')).toBeFalsy(); }); }); From 25b309fcc67a99a7e265f9b849a8a499bda8f9e2 Mon Sep 17 00:00:00 2001 From: Brendan Kenny Date: Mon, 8 Jul 2019 16:14:02 -0700 Subject: [PATCH 075/110] core: localize invalid URL error message (#9334) --- lighthouse-core/index.js | 8 ------- lighthouse-core/runner.js | 11 ++++----- lighthouse-core/test/index-test.js | 36 ++++++++++++++++------------- lighthouse-core/test/runner-test.js | 20 +++++++++------- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/lighthouse-core/index.js b/lighthouse-core/index.js index 65b9ba1bbb3f..bc7093ad3f83 100644 --- a/lighthouse-core/index.js +++ b/lighthouse-core/index.js @@ -10,9 +10,6 @@ const log = require('lighthouse-logger'); const ChromeProtocol = require('./gather/connections/cri.js'); const Config = require('./config/config.js'); -const URL = require('./lib/url-shim.js'); -const LHError = require('./lib/lh-error.js'); - /** @typedef {import('./gather/connections/connection.js')} Connection */ /* @@ -39,11 +36,6 @@ const LHError = require('./lib/lh-error.js'); * @return {Promise} */ async function lighthouse(url, flags = {}, configJSON, connection) { - // verify the url is valid and that protocol is allowed - if (url && (!URL.isValid(url) || !URL.isProtocolAllowed(url))) { - throw new LHError(LHError.errors.INVALID_URL); - } - // set logging preferences, assume quiet flags.logLevel = flags.logLevel || 'error'; log.setLevel(flags.logLevel); diff --git a/lighthouse-core/runner.js b/lighthouse-core/runner.js index 689ed67996c1..029f89807a46 100644 --- a/lighthouse-core/runner.js +++ b/lighthouse-core/runner.js @@ -70,15 +70,12 @@ class Runner { throw new Error('Cannot run audit mode on different URL'); } } else { - if (typeof runOpts.url !== 'string' || runOpts.url.length === 0) { - throw new Error(`You must provide a url to the runner. '${runOpts.url}' provided.`); - } - - try { + // verify the url is valid and that protocol is allowed + if (runOpts.url && URL.isValid(runOpts.url) && URL.isProtocolAllowed(runOpts.url)) { // Use canonicalized URL (with trailing slashes and such) requestedUrl = new URL(runOpts.url).href; - } catch (e) { - throw new Error('The url provided should have a proper protocol and hostname.'); + } else { + throw new LHError(LHError.errors.INVALID_URL); } artifacts = await Runner._gatherArtifactsFromBrowser(requestedUrl, runOpts, connection); diff --git a/lighthouse-core/test/index-test.js b/lighthouse-core/test/index-test.js index e5c678c77154..c56e77851f6e 100644 --- a/lighthouse-core/test/index-test.js +++ b/lighthouse-core/test/index-test.js @@ -87,22 +87,26 @@ describe('Module Tests', function() { }); }); - it('should throw an error when the url is invalid', function() { - return lighthouse('https:/i-am-not-valid', {}, {}) - .then(() => { - throw new Error('Should not have resolved when url is invalid'); - }, err => { - assert.ok(err); - }); - }); - - it('should throw an error when the url is invalid protocol (file:///)', function() { - return lighthouse('file:///a/fake/index.html', {}, {}) - .then(() => { - throw new Error('Should not have resolved when url is file:///'); - }, err => { - assert.ok(err); - }); + it('should throw an error when the url is invalid', async () => { + expect.hasAssertions(); + try { + await lighthouse('i-am-not-valid', {}, {}); + } catch (err) { + expect(err.friendlyMessage) + .toBeDisplayString('The URL you have provided appears to be invalid.'); + expect(err.code).toEqual('INVALID_URL'); + } + }); + + it('should throw an error when the url is invalid protocol (file:///)', async () => { + expect.hasAssertions(); + try { + await lighthouse('file:///a/fake/index.html', {}, {}); + } catch (err) { + expect(err.friendlyMessage) + .toBeDisplayString('The URL you have provided appears to be invalid.'); + expect(err.code).toEqual('INVALID_URL'); + } }); it('should return formatted LHR when given no categories', function() { diff --git a/lighthouse-core/test/runner-test.js b/lighthouse-core/test/runner-test.js index bb9b38c6cb11..ccf4bf339401 100644 --- a/lighthouse-core/test/runner-test.js +++ b/lighthouse-core/test/runner-test.js @@ -514,20 +514,24 @@ describe('Runner', () => { }); - it('rejects when not given a URL', () => { - return Runner.run({}, {}).then(_ => assert.ok(false), _ => assert.ok(true)); + it('rejects when not given a URL', async () => { + const config = new Config({}); + await expect(Runner.run({}, {config})).rejects.toThrow('INVALID_URL'); }); - it('rejects when given a URL of zero length', () => { - return Runner.run({}, {url: ''}).then(_ => assert.ok(false), _ => assert.ok(true)); + it('rejects when given a URL of zero length', async () => { + const config = new Config({}); + await expect(Runner.run({}, {url: '', config})).rejects.toThrow('INVALID_URL'); }); - it('rejects when given a URL without protocol', () => { - return Runner.run({}, {url: 'localhost'}).then(_ => assert.ok(false), _ => assert.ok(true)); + it('rejects when given a URL without protocol', async () => { + const config = new Config({}); + await expect(Runner.run({}, {url: 'localhost', config})).rejects.toThrow('INVALID_URL'); }); - it('rejects when given a URL without hostname', () => { - return Runner.run({}, {url: 'https://'}).then(_ => assert.ok(false), _ => assert.ok(true)); + it('rejects when given a URL without hostname', async () => { + const config = new Config({}); + await expect(Runner.run({}, {url: 'https://', config})).rejects.toThrow('INVALID_URL'); }); it('only supports core audits with names matching their filename', () => { From 5e52dcca72b35943d14cc7c27613517c425250b9 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Tue, 9 Jul 2019 12:20:46 -0700 Subject: [PATCH 076/110] misc(build): adjust deployment filenames (#9338) --- .../scripts/build-report-for-autodeployment.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lighthouse-core/scripts/build-report-for-autodeployment.js b/lighthouse-core/scripts/build-report-for-autodeployment.js index 7fdc9d06a71a..1fd9c29046e5 100644 --- a/lighthouse-core/scripts/build-report-for-autodeployment.js +++ b/lighthouse-core/scripts/build-report-for-autodeployment.js @@ -11,6 +11,7 @@ const fs = require('fs'); const path = require('path'); const mkdirp = require('mkdirp').sync; +const rimraf = require('rimraf').sync; const swapLocale = require('../lib/i18n/swap-locale.js'); const ReportGenerator = require('../../lighthouse-core/report/report-generator.js'); @@ -27,7 +28,7 @@ const DIST = path.join(__dirname, `../../dist`); const filenameToLhr = { 'english': lhr, 'espanol': swapLocale(lhr, 'es').lhr, - 'arabic': swapLocale(lhr, 'ar').lhr, + 'ɑrabic': swapLocale(lhr, 'ar').lhr, 'xl-accented': swapLocale(lhr, 'en-XL').lhr, 'error': errorLhr, }; @@ -36,14 +37,14 @@ const DIST = path.join(__dirname, `../../dist`); Object.entries(filenameToLhr).forEach(([filename, lhr]) => { let html = ReportGenerator.generateReportHtml(lhr); // TODO: PSI is another variant to consider - for (const variant of ['', '-devtools']) { - if (variant === '-devtools') { + for (const variant of ['', '⌣.cdt.']) { + if (variant.includes('cdt')) { // TODO: Make the DevTools Audits panel "emulation" more comprehensive // - the parent widget/vbox container with overflow // - a more constrained/realistic default size html = html.replace(`"lh-root lh-vars"`, `"lh-root lh-vars lh-devtools"`); } - const filepath = `${DIST}/${filename}${variant}/index.html`; + const filepath = `${DIST}/${variant}${filename}/index.html`; mkdirp(path.dirname(filepath)); fs.writeFileSync(filepath, html, {encoding: 'utf-8'}); console.log('✅', filepath, 'written.'); @@ -124,5 +125,6 @@ async function generateErrorLHR() { appleTouchIconAudit.scoreDisplayMode = 'binary'; appleTouchIconAudit.score = 1; + rimraf(TMP); return errorLhr; } From 4c658d272705cc68f1b55a898a2c7fb5f881b57c Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Tue, 9 Jul 2019 16:03:24 -0700 Subject: [PATCH 077/110] tests(smokehouse): assert on expected array length (#9292) Co-Authored-By: Brendan Kenny --- .../smokehouse/byte-efficiency/expectations.js | 3 +++ .../test/smokehouse/error-expectations.js | 14 ++++++++++---- .../test/smokehouse/smokehouse-report.js | 12 ++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js index 649b674e44ae..7b69fdae3841 100644 --- a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js +++ b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js @@ -140,6 +140,9 @@ module.exports = [ transferSize: 53181, resourceSize: 52997, }, + { + url: 'http://localhost:10200/favicon.ico', + }, ], }, }, diff --git a/lighthouse-cli/test/smokehouse/error-expectations.js b/lighthouse-cli/test/smokehouse/error-expectations.js index 57c3e60cb073..7030f03f02a2 100644 --- a/lighthouse-cli/test/smokehouse/error-expectations.js +++ b/lighthouse-cli/test/smokehouse/error-expectations.js @@ -5,6 +5,12 @@ */ 'use strict'; +// Just using `[]` actually asserts for an empty array. +// Use this expectation object to assert an array with at least one element. +const NONEMPTY_ARRAY = { + length: '>0', +}; + /** * Expected Lighthouse audit values for sites with various errors. */ @@ -24,10 +30,10 @@ module.exports = [ artifacts: { PageLoadError: {code: 'PAGE_HUNG'}, devtoolsLogs: { - 'pageLoadError-defaultPass': [/* ... */], + 'pageLoadError-defaultPass': NONEMPTY_ARRAY, }, traces: { - 'pageLoadError-defaultPass': {traceEvents: [/* ... */]}, + 'pageLoadError-defaultPass': {traceEvents: NONEMPTY_ARRAY}, }, }, }, @@ -46,10 +52,10 @@ module.exports = [ artifacts: { PageLoadError: {code: 'INSECURE_DOCUMENT_REQUEST'}, devtoolsLogs: { - 'pageLoadError-defaultPass': [/* ... */], + 'pageLoadError-defaultPass': NONEMPTY_ARRAY, }, traces: { - 'pageLoadError-defaultPass': {traceEvents: [/* ... */]}, + 'pageLoadError-defaultPass': {traceEvents: NONEMPTY_ARRAY}, }, }, }, diff --git a/lighthouse-cli/test/smokehouse/smokehouse-report.js b/lighthouse-cli/test/smokehouse/smokehouse-report.js index 5f670a38a394..37fe6d26a357 100644 --- a/lighthouse-cli/test/smokehouse/smokehouse-report.js +++ b/lighthouse-cli/test/smokehouse/smokehouse-report.js @@ -98,6 +98,18 @@ function findDifference(path, actual, expected) { } } + // If the expected value is an array, assert the length as well. + // This still allows for asserting that the first n elements of an array are specified elements, + // but requires using an object literal (ex: {0: x, 1: y, 2: z} matches [x, y, z, q, w, e] and + // {0: x, 1: y, 2: z, length: 5} does not match [x, y, z]. + if (Array.isArray(expected) && actual.length !== expected.length) { + return { + path: `${path}.length`, + actual, + expected, + }; + } + return null; } From 7317676af233627869796ef96b66bdf405298882 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Wed, 10 Jul 2019 12:35:46 -0700 Subject: [PATCH 078/110] deps: chrome-launcher@0.11.1 (#9339) --- .../scripts/manual-chrome-launcher.js | 21 ++++++++++++------- package.json | 2 +- yarn.lock | 18 ++++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lighthouse-core/scripts/manual-chrome-launcher.js b/lighthouse-core/scripts/manual-chrome-launcher.js index 2e13cc4c978c..80ce39cf913a 100755 --- a/lighthouse-core/scripts/manual-chrome-launcher.js +++ b/lighthouse-core/scripts/manual-chrome-launcher.js @@ -1,7 +1,6 @@ #!/usr/bin/env node 'use strict'; - /** * @fileoverview Script to launch a clean Chrome instance on-demand. * @@ -14,29 +13,35 @@ * chrome-debug --enable-extensions */ -const {launch} = require('chrome-launcher'); +const {Launcher, launch} = require('chrome-launcher'); const args = process.argv.slice(2); -let chromeFlags; +const chromeFlags = []; let startingUrl; let port; -let enableExtensions; +let ignoreDefaultFlags; if (args.length) { - chromeFlags = args.filter(flag => flag.startsWith('--')); + const providedFlags = args.filter(flag => flag.startsWith('--')); - const portFlag = chromeFlags.find(flag => flag.startsWith('--port=')); + const portFlag = providedFlags.find(flag => flag.startsWith('--port=')); if (portFlag) port = parseInt(portFlag.replace('--port=', ''), 10); - enableExtensions = !!chromeFlags.find(flag => flag === '--enable-extensions'); + const enableExtensions = !!providedFlags.find(flag => flag === '--enable-extensions'); + // The basic pattern for enabling Chrome extensions + if (enableExtensions) { + ignoreDefaultFlags = true; + chromeFlags.push(...Launcher.defaultFlags().filter(flag => flag !== '--disable-extensions')); + } + chromeFlags.push(...providedFlags); startingUrl = args.find(flag => !flag.startsWith('--')); } launch({ startingUrl, port, - enableExtensions, + ignoreDefaultFlags, chromeFlags, }) // eslint-disable-next-line no-console diff --git a/package.json b/package.json index 1b6e5bc1c715..9fd297a150c2 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ }, "dependencies": { "axe-core": "3.2.2", - "chrome-launcher": "^0.10.7", + "chrome-launcher": "^0.11.1", "configstore": "^3.1.1", "cssstyle": "1.2.1", "details-element-polyfill": "2.2.0", diff --git a/yarn.lock b/yarn.lock index d18514554fc3..fe05320f0fc4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1788,13 +1788,13 @@ chownr@^1.0.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== -chrome-launcher@^0.10.7: - version "0.10.7" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.7.tgz#5e2a9e99f212e0501d9c7024802acd01a812f5d5" - integrity sha512-IoQLp64s2n8OQuvKZwt77CscVj3UlV2Dj7yZtd1EBMld9mSdGcsGy9fN5hd/r4vJuWZR09it78n1+A17gB+AIQ== +chrome-launcher@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.11.1.tgz#ccc5bd971c76cdd263d17acacaeb762454c1af92" + integrity sha512-Om9LtiJ+FIh8sfhx8HaN4Petj75dIVeTBNUbXIXPIS5W3y9dyNRGmChcl0Z5trQkcy+8XDJA3NWicYdpZeF+DA== dependencies: "@types/node" "*" - is-wsl "^1.1.0" + is-wsl "^2.1.0" lighthouse-logger "^1.0.0" mkdirp "0.5.1" rimraf "^2.6.1" @@ -4288,10 +4288,10 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +is-wsl@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.0.tgz#94369bbeb2249ef07b831b1b08590e686330ccbb" + integrity sha512-pFTjpv/x5HRj8kbZ/Msxi9VrvtOMRBqaDi3OIcbwPI3OuH+r3lLxVWukLITBaOGJIbA/w2+M1eVmVa4XNQlAmQ== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" From fa9bda4e3244fdb17fceaeed62fb3ca5c08e7997 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Wed, 10 Jul 2019 14:40:55 -0700 Subject: [PATCH 079/110] report: show disabled checkbox when all/no urls are third-party (#9299) --- .../html/renderer/report-ui-features.js | 11 ++++++++--- lighthouse-core/report/html/templates.html | 4 +++- .../html/renderer/report-ui-features-test.js | 19 +++++++++---------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js index ab947a78f319..3ad38e014e13 100644 --- a/lighthouse-core/report/html/renderer/report-ui-features.js +++ b/lighthouse-core/report/html/renderer/report-ui-features.js @@ -234,12 +234,11 @@ class ReportUIFeatures { tablesWithUrls.forEach((tableEl, index) => { const urlItems = this._getUrlItems(tableEl); const thirdPartyRows = this._getThirdPartyRows(tableEl, urlItems, this.json.finalUrl); - // If all or none of the rows are 3rd party, no checkbox! - if (thirdPartyRows.size === urlItems.length || !thirdPartyRows.size) return; // create input box const filterTemplate = this._dom.cloneTemplate('#tmpl-lh-3p-filter', this._templateContext); - const filterInput = this._dom.find('input', filterTemplate); + const filterInput = + /** @type {HTMLInputElement} */ (this._dom.find('input', filterTemplate)); const id = `lh-3p-filter-label--${index}`; filterInput.id = id; @@ -265,6 +264,12 @@ class ReportUIFeatures { this._dom.find('.lh-3p-ui-string', filterTemplate).textContent = Util.UIStrings.thirdPartyResourcesLabel; + // If all or none of the rows are 3rd party, disable the checkbox. + if (thirdPartyRows.size === urlItems.length || !thirdPartyRows.size) { + filterInput.disabled = true; + filterInput.checked = thirdPartyRows.size === urlItems.length; + } + // Finally, add checkbox to the DOM. if (!tableEl.parentNode) return; // Keep tsc happy. tableEl.parentNode.insertBefore(filterTemplate, tableEl); diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index 34f1c9698149..26687d46d844 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -786,10 +786,12 @@ padding: 6px; } .lh-3p-filter-label, .lh-3p-filter-input { - cursor: pointer; vertical-align: middle; user-select: none; } + .lh-3p-filter-input:disabled + .lh-3p-ui-string { + text-decoration: line-through; + }