Repository: GoogleChrome/lighthouse
Pull request #10631 (2020-04-24 15:15:19)

docs(readme): add variability and throttling to FAQ
**Summary**
How on earth was "lighthouse architecture" in our FAQs but these two weren't? 😆 

**Related Issues/PRs**
https://github.com/GoogleChrome/lighthouse/issues/10629
https://github.com/GoogleChrome/lighthouse/issues/10628
and about a billion others I'm tired of answering...




Patch:
diff --git a/lighthouse-core/audits/legacy-javascript.js b/lighthouse-core/audits/legacy-javascript.js
index 0f1ed78a4..62d5eb242 100644
--- a/lighthouse-core/audits/legacy-javascript.js
+++ b/lighthouse-core/audits/legacy-javascript.js
@@ -18,6 +18,7 @@
 const Audit = require('./audit.js');
 const NetworkRecords = require('../computed/network-records.js');
 const MainResource = require('../computed/main-resource.js');
+const JSBundles = require('../computed/js-bundles.js');
 const URL = require('../lib/url-shim.js');
 const i18n = require('../lib/i18n/i18n.js');
 
@@ -107,7 +108,7 @@ class LegacyJavascript extends Audit {
       scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
       description: str_(UIStrings.description),
       title: str_(UIStrings.title),
-      requiredArtifacts: ['devtoolsLogs', 'ScriptElements', 'URL'],
+      requiredArtifacts: ['devtoolsLogs', 'ScriptElements', 'SourceMaps', 'URL'],
     };
   }
 
@@ -159,97 +160,103 @@ class LegacyJavascript extends Audit {
     return expression;
   }
 
+  static getPolyfillData() {
+    return [
+      /* eslint-disable max-len */
+      {module: 'es6.array.fill', name: 'Array.prototype.fill'},
+      {module: 'es6.array.filter', name: 'Array.prototype.filter'},
+      {module: 'es6.array.find', name: 'Array.prototype.find'},
+      {module: 'es6.array.find-index', name: 'Array.prototype.findIndex'},
+      {module: 'es6.array.for-each', name: 'Array.prototype.forEach'},
+      {module: 'es6.array.from', name: 'Array.from'},
+      {module: 'es6.array.is-array', name: 'Array.isArray'},
+      {module: 'es6.array.last-index-of', name: 'Array.prototype.lastIndexOf'},
+      {module: 'es6.array.map', name: 'Array.prototype.map'},
+      {module: 'es6.array.of', name: 'Array.of'},
+      {module: 'es6.array.reduce', name: 'Array.prototype.reduce'},
+      {module: 'es6.array.reduce-right', name: 'Array.prototype.reduceRight'},
+      {module: 'es6.array.some', name: 'Array.prototype.some'},
+      {module: 'es6.date.now', name: 'Date.now'},
+      {module: 'es6.date.to-iso-string', name: 'Date.prototype.toISOString'},
+      {module: 'es6.date.to-json', name: 'Date.prototype.toJSON'},
+      {module: 'es6.date.to-string', name: 'Date.prototype.toString'},
+      {module: 'es6.function.name', name: 'Function.prototype.name'},
+      {module: 'es6.map', name: 'Map'},
+      {module: 'es6.number.is-integer', name: 'Number.isInteger'},
+      {module: 'es6.number.is-safe-integer', name: 'Number.isSafeInteger'},
+      {module: 'es6.number.parse-float', name: 'Number.parseFloat'},
+      {module: 'es6.number.parse-int', name: 'Number.parseInt'},
+      {module: 'es6.object.assign', name: 'Object.assign'},
+      {module: 'es6.object.create', name: 'Object.create'},
+      {module: 'es6.object.define-properties', name: 'Object.defineProperties'},
+      {module: 'es6.object.define-property', name: 'Object.defineProperty'},
+      {module: 'es6.object.freeze', name: 'Object.freeze'},
+      {module: 'es6.object.get-own-property-descriptor', name: 'Object.getOwnPropertyDescriptor'},
+      {module: 'es6.object.get-own-property-names', name: 'Object.getOwnPropertyNames'},
+      {module: 'es6.object.get-prototype-of', name: 'Object.getPrototypeOf'},
+      {module: 'es6.object.is-extensible', name: 'Object.isExtensible'},
+      {module: 'es6.object.is-frozen', name: 'Object.isFrozen'},
+      {module: 'es6.object.is-sealed', name: 'Object.isSealed'},
+      {module: 'es6.object.keys', name: 'Object.keys'},
+      {module: 'es6.object.prevent-extensions', name: 'Object.preventExtensions'},
+      {module: 'es6.object.seal', name: 'Object.seal'},
+      {module: 'es6.object.set-prototype-of', name: 'Object.setPrototypeOf'},
+      {module: 'es6.promise', name: 'Promise'},
+      {module: 'es6.reflect.apply', name: 'Reflect.apply'},
+      {module: 'es6.reflect.construct', name: 'Reflect.construct'},
+      {module: 'es6.reflect.define-property', name: 'Reflect.defineProperty'},
+      {module: 'es6.reflect.delete-property', name: 'Reflect.deleteProperty'},
+      {module: 'es6.reflect.get', name: 'Reflect.get'},
+      {module: 'es6.reflect.get-own-property-descriptor', name: 'Reflect.getOwnPropertyDescriptor'},
+      {module: 'es6.reflect.get-prototype-of', name: 'Reflect.getPrototypeOf'},
+      {module: 'es6.reflect.has', name: 'Reflect.has'},
+      {module: 'es6.reflect.is-extensible', name: 'Reflect.isExtensible'},
+      {module: 'es6.reflect.own-keys', name: 'Reflect.ownKeys'},
+      {module: 'es6.reflect.prevent-extensions', name: 'Reflect.preventExtensions'},
+      {module: 'es6.reflect.set', name: 'Reflect.set'},
+      {module: 'es6.reflect.set-prototype-of', name: 'Reflect.setPrototypeOf'},
+      {module: 'es6.set', name: 'Set'},
+      {module: 'es6.string.code-point-at', name: 'String.prototype.codePointAt'},
+      {module: 'es6.string.ends-with', name: 'String.prototype.endsWith'},
+      {module: 'es6.string.from-code-point', name: 'String.fromCodePoint'},
+      {module: 'es6.string.includes', name: 'String.prototype.includes'},
+      {module: 'es6.string.raw', name: 'String.raw'},
+      {module: 'es6.string.repeat', name: 'String.prototype.repeat'},
+      {module: 'es6.string.starts-with', name: 'String.prototype.startsWith'},
+      {module: 'es6.string.trim', name: 'String.prototype.trim'},
+      {module: 'es6.typed.array-buffer', name: 'ArrayBuffer'},
+      {module: 'es6.typed.data-view', name: 'DataView'},
+      {module: 'es6.typed.float32-array', name: 'Float32Array'},
+      {module: 'es6.typed.float64-array', name: 'Float64Array'},
+      {module: 'es6.typed.int16-array', name: 'Int16Array'},
+      {module: 'es6.typed.int32-array', name: 'Int32Array'},
+      {module: 'es6.typed.int8-array', name: 'Int8Array'},
+      {module: 'es6.typed.uint16-array', name: 'Uint16Array'},
+      {module: 'es6.typed.uint32-array', name: 'Uint32Array'},
+      {module: 'es6.typed.uint8-array', name: 'Uint8Array'},
+      {module: 'es6.typed.uint8-clamped-array', name: 'Uint8ClampedArray'},
+      {module: 'es6.weak-map', name: 'WeakMap'},
+      {module: 'es6.weak-set', name: 'WeakSet'},
+      {module: 'es7.array.includes', name: 'Array.prototype.includes'},
+      {module: 'es7.object.entries', name: 'Object.entries'},
+      {module: 'es7.object.get-own-property-descriptors', name: 'Object.getOwnPropertyDescriptors'},
+      {module: 'es7.object.values', name: 'Object.values'},
+      {module: 'es7.string.pad-end', name: 'String.prototype.padEnd'},
+      {module: 'es7.string.pad-start', name: 'String.prototype.padStart'},
+      /* eslint-enable max-len */
+    ];
+  }
+
   /**
    * @return {Pattern[]}
    */
   static getPolyfillPatterns() {
-    return [
-      'Array.fill',
-      'Array.from',
-      'Array.isArray',
-      'Array.of',
-      'Array.prototype.filter',
-      'Array.prototype.find',
-      'Array.prototype.findIndex',
-      'Array.prototype.forEach',
-      'Array.prototype.includes',
-      'Array.prototype.lastIndexOf',
-      'Array.prototype.map',
-      'Array.prototype.reduce',
-      'Array.prototype.reduceRight',
-      'Array.prototype.some',
-      'ArrayBuffer',
-      'DataView',
-      'Date.now',
-      'Date.prototype.toISOString',
-      'Date.prototype.toJSON',
-      'Date.prototype.toString',
-      'Float32Array',
-      'Float64Array',
-      'Function.prototype.name',
-      'Int16Array',
-      'Int32Array',
-      'Int8Array',
-      'Map',
-      'Number.isInteger',
-      'Number.isSafeInteger',
-      'Number.parseFloat',
-      'Number.parseInt',
-      'Object.assign',
-      'Object.create',
-      'Object.defineProperties',
-      'Object.defineProperty',
-      'Object.entries',
-      'Object.freeze',
-      'Object.getOwnPropertyDescriptor',
-      'Object.getOwnPropertyDescriptors',
-      'Object.getOwnPropertyNames',
-      'Object.getPrototypeOf',
-      'Object.isExtensible',
-      'Object.isFrozen',
-      'Object.isSealed',
-      'Object.keys',
-      'Object.preventExtensions',
-      'Object.seal',
-      'Object.setPrototypeOf',
-      'Object.values',
-      'Promise',
-      'Reflect.apply',
-      'Reflect.construct',
-      'Reflect.defineProperty',
-      'Reflect.deleteProperty',
-      'Reflect.get',
-      'Reflect.getOwnPropertyDescriptor',
-      'Reflect.getPrototypeOf',
-      'Reflect.has',
-      'Reflect.isExtensible',
-      'Reflect.ownKeys',
-      'Reflect.preventExtensions',
-      'Reflect.set',
-      'Reflect.setPrototypeOf',
-      'Set',
-      'String.fromCodePoint',
-      'String.prototype.codePointAt',
-      'String.prototype.endsWith',
-      'String.prototype.includes',
-      'String.prototype.padEnd',
-      'String.prototype.padStart',
-      'String.prototype.repeat',
-      'String.prototype.startsWith',
-      'String.prototype.trim',
-      'String.raw',
-      'Uint16Array',
-      'Uint32Array',
-      'Uint8Array',
-      'Uint8ClampedArray',
-      'WeakMap',
-      'WeakSet',
-    ].map(polyfillName => {
-      const parts = polyfillName.split('.');
+    return this.getPolyfillData().map(({name}) => {
+      const parts = name.split('.');
       const object = parts.length > 1 ? parts.slice(0, parts.length - 1).join('.') : null;
       const property = parts[parts.length - 1];
       return {
-        name: polyfillName,
+        name,
         expression: this.buildPolyfillExpression(object, property),
       };
     });
@@ -276,23 +283,46 @@ class LegacyJavascript extends Audit {
   }
 
   /**
-   * Returns a collection of match results grouped by script url and with a mapping
-   * to determine the order in which the matches were discovered.
+   * Returns a collection of match results grouped by script url.
    *
    * @param {CodePatternMatcher} matcher
    * @param {LH.GathererArtifacts['ScriptElements']} scripts
    * @param {LH.Artifacts.NetworkRequest[]} networkRecords
+   * @param {LH.Artifacts.Bundle[]} bundles
    * @return {Map<string, PatternMatchResult[]>}
    */
-  static detectCodePatternsAcrossScripts(matcher, scripts, networkRecords) {
+  static detectAcrossScripts(matcher, scripts, networkRecords, bundles) {
     /** @type {Map<string, PatternMatchResult[]>} */
     const urlToMatchResults = new Map();
+    const polyfillData = this.getPolyfillData();
 
     for (const {requestId, content} of Object.values(scripts)) {
       if (!content) continue;
       const networkRecord = networkRecords.find(record => record.requestId === requestId);
       if (!networkRecord) continue;
+
+      // Start with pattern matching against the downloaded script.
       const matches = matcher.match(content);
+
+      // If it's a bundle with source maps, add in the polyfill modules by name too.
+      const bundle = bundles.find(b => b.script.src === networkRecord.url);
+      if (bundle) {
+        for (const {module, name} of polyfillData) {
+          // Skip if the pattern matching found a match for this polyfill.
+          if (matches.some(m => m.name === name)) continue;
+
+          const source = bundle.rawMap.sources.find(source => source.endsWith(`${module}.js`));
+          if (!source) continue;
+
+          const mapping = bundle.map.mappings().find(m => m.sourceURL === source);
+          if (mapping) {
+            matches.push({name, line: mapping.lineNumber, column: mapping.columnNumber});
+          } else {
+            matches.push({name, line: 0, column: 0});
+          }
+        }
+      }
+
       if (!matches.length) continue;
       urlToMatchResults.set(networkRecord.url, matches);
     }
@@ -312,6 +342,7 @@ class LegacyJavascript extends Audit {
       URL: artifacts.URL,
       devtoolsLog,
     }, context);
+    const bundles = await JSBundles.request(artifacts, context);
 
     /** @type {Array<{url: string, signals: string[], locations: LH.Audit.Details.SourceLocationValue[]}>} */
     const tableRows = [];
@@ -324,7 +355,7 @@ class LegacyJavascript extends Audit {
     ]);
 
     const urlToMatchResults =
-      this.detectCodePatternsAcrossScripts(matcher, artifacts.ScriptElements, networkRecords);
+      this.detectAcrossScripts(matcher, artifacts.ScriptElements, networkRecords, bundles);
     urlToMatchResults.forEach((matches, url) => {
       /** @type {typeof tableRows[number]} */
       const row = {url, signals: [], locations: []};
diff --git a/lighthouse-core/scripts/legacy-javascript/README.md b/lighthouse-core/scripts/legacy-javascript/README.md
index 74cd54181..27a0eb614 100644
--- a/lighthouse-core/scripts/legacy-javascript/README.md
+++ b/lighthouse-core/scripts/legacy-javascript/README.md
@@ -5,7 +5,7 @@ Creates many projects using specific babel transforms / polyfills (called varian
 Run:
 
 ```sh
-yarn install
+yarn
 node run.js
 # STAGE=build|audit|all to just build the audits or run LegacyJavascript on them. Defaults to both (`all`).
 ```
diff --git a/lighthouse-core/scripts/legacy-javascript/run.js b/lighthouse-core/scripts/legacy-javascript/run.js
index 591e56cb3..d29c03abb 100644
--- a/lighthouse-core/scripts/legacy-javascript/run.js
+++ b/lighthouse-core/scripts/legacy-javascript/run.js
@@ -34,122 +34,7 @@ const STAGE = process.env.STAGE || 'all';
 const mainCode = fs.readFileSync(`${__dirname}/main.js`, 'utf-8');
 
 const plugins = LegacyJavascript.getTransformPatterns().map(pattern => pattern.name);
-
-// TODO(cjamcl): Get this from `LegacyJavascript`. Data isn't structured ideally yet, but should be
-// done when SourceMap support is in.
-const polyfills = [
-  'es6.array.copy-within',
-  'es6.array.every',
-  'es6.array.fill',
-  'es6.array.filter',
-  'es6.array.find-index',
-  'es6.array.find',
-  'es6.array.for-each',
-  'es6.array.from',
-  'es6.array.index-of',
-  'es6.array.is-array',
-  'es6.array.iterator',
-  'es6.array.last-index-of',
-  'es6.array.map',
-  'es6.array.of',
-  'es6.array.reduce-right',
-  'es6.array.reduce',
-  'es6.array.some',
-  'es6.array.species',
-  'es6.date.now',
-  'es6.date.to-iso-string',
-  'es6.date.to-json',
-  'es6.date.to-primitive',
-  'es6.date.to-string',
-  'es6.function.bind',
-  'es6.function.has-instance',
-  'es6.function.name',
-  'es6.map',
-  'es6.math.acosh',
-  'es6.math.asinh',
-  'es6.math.atanh',
-  'es6.math.cbrt',
-  'es6.math.clz32',
-  'es6.math.cosh',
-  'es6.math.expm1',
-  'es6.math.fround',
-  'es6.math.hypot',
-  'es6.math.imul',
-  'es6.math.log10',
-  'es6.math.log1p',
-  'es6.math.log2',
-  'es6.math.sign',
-  'es6.math.sinh',
-  'es6.math.tanh',
-  'es6.math.trunc',
-  'es6.number.constructor',
-  'es6.number.epsilon',
-  'es6.number.is-integer',
-  'es6.number.is-safe-integer',
-  'es6.number.max-safe-integer',
-  'es6.number.min-safe-integer',
-  'es6.number.parse-float',
-  'es6.number.parse-int',
-  'es6.object.assign',
-  'es6.object.create',
-  'es6.object.define-properties',
-  'es6.object.define-property',
-  'es6.object.freeze',
-  'es6.object.get-own-property-descriptor',
-  'es6.object.get-own-property-names',
-  'es6.object.get-prototype-of',
-  'es6.object.is-extensible',
-  'es6.object.is-frozen',
-  'es6.object.is-sealed',
-  'es6.object.keys',
-  'es6.object.prevent-extensions',
-  'es6.object.seal',
-  'es6.object.set-prototype-of',
-  'es6.object.to-string',
-  'es6.promise',
-  'es6.reflect.apply',
-  'es6.reflect.construct',
-  'es6.reflect.define-property',
-  'es6.reflect.delete-property',
-  'es6.reflect.get-own-property-descriptor',
-  'es6.reflect.get-prototype-of',
-  'es6.reflect.get',
-  'es6.reflect.has',
-  'es6.reflect.is-extensible',
-  'es6.reflect.own-keys',
-  'es6.reflect.prevent-extensions',
-  'es6.reflect.set-prototype-of',
-  'es6.reflect.set',
-  'es6.set',
-  'es6.string.code-point-at',
-  'es6.string.ends-with',
-  'es6.string.from-code-point',
-  'es6.string.includes',
-  'es6.string.iterator',
-  'es6.string.raw',
-  'es6.string.repeat',
-  'es6.string.starts-with',
-  'es6.string.trim',
-  'es6.typed.array-buffer',
-  'es6.typed.data-view',
-  'es6.typed.float32-array',
-  'es6.typed.float64-array',
-  'es6.typed.int16-array',
-  'es6.typed.int32-array',
-  'es6.typed.int8-array',
-  'es6.typed.uint16-array',
-  'es6.typed.uint32-array',
-  'es6.typed.uint8-array',
-  'es6.typed.uint8-clamped-array',
-  'es6.weak-map',
-  'es6.weak-set',
-  'es7.array.includes',
-  'es7.object.entries',
-  'es7.object.get-own-property-descriptors',
-  'es7.object.values',
-  'es7.string.pad-end',
-  'es7.string.pad-start',
-];
+const polyfills = LegacyJavascript.getPolyfillData().map(d => d.module);
 
 /**
  * @param {string} command
@@ -191,7 +76,8 @@ async function createVariant(options) {
     fs.writeFileSync(`${dir}/.babelrc`, JSON.stringify(babelrc || {}, null, 2));
     // Not used in this script, but useful for running Lighthouse manually.
     // Just need to start a web server first.
-    fs.writeFileSync(`${dir}/index.html`, `<title>${name}</title><script src=main.bundle.min.js>`);
+    fs.writeFileSync(`${dir}/index.html`,
+      `<title>${name}</title><script src=main.bundle.min.js></script><p>${name}</p>`);
 
     // Note: No babelrc will make babel a glorified `cp`.
     runCommand('yarn', [
@@ -200,6 +86,7 @@ async function createVariant(options) {
       '--config-file', `${dir}/.babelrc`,
       '--ignore', 'node_modules/**/*.js',
       '-o', `${dir}/main.transpiled.js`,
+      '--source-maps', 'inline',
     ]);
 
     // Transform any require statements (like for core-js) into a big bundle.
@@ -207,6 +94,7 @@ async function createVariant(options) {
       'browserify',
       `${dir}/main.transpiled.js`,
       '-o', `${dir}/main.bundle.js`,
+      '--debug', // source maps
     ]);
 
     // Minify.
@@ -214,51 +102,78 @@ async function createVariant(options) {
       'terser',
       `${dir}/main.bundle.js`,
       '-o', `${dir}/main.bundle.min.js`,
+      '--source-map', 'content="inline",url="main.bundle.min.js.map"',
     ]);
   }
 
   if (STAGE === 'audit' || STAGE === 'all') {
-    // Instead of running Lighthouse, use LegacyJavascript directly. Requires some setup.
-    // Much faster than running Lighthouse.
-    const documentUrl = 'http://localhost/index.html'; // These URLs don't matter.
-    const scriptUrl = 'https://localhost/main.bundle.min.js';
-    const networkRecords = [
-      {url: documentUrl},
-      {url: scriptUrl},
-    ];
-    const devtoolsLogs = networkRecordsToDevtoolsLog(networkRecords);
-    const jsRequestWillBeSentEvent = devtoolsLogs.find(e =>
-      e.method === 'Network.requestWillBeSent' && e.params.request.url === scriptUrl);
-    if (!jsRequestWillBeSentEvent) throw new Error('jsRequestWillBeSentEvent is undefined');
-    // @ts-ignore - the log event is not narrowed to 'Network.requestWillBeSent' event from find
-    const jsRequestId = jsRequestWillBeSentEvent.params.requestId;
-    const code = fs.readFileSync(`${dir}/main.bundle.min.js`, 'utf-8').toString();
-    /** @type {Pick<LH.Artifacts, 'devtoolsLogs'|'URL'|'ScriptElements'>} */
-    const artifacts = {
-      URL: {finalUrl: documentUrl, requestedUrl: documentUrl},
-      devtoolsLogs: {
-        [LegacyJavascript.DEFAULT_PASS]: devtoolsLogs,
-      },
-      ScriptElements: [
-        // @ts-ignore - partial ScriptElement excluding unused DOM properties
-        {requestId: jsRequestId, content: code},
-      ],
-    };
-    // @ts-ignore: partial Artifacts.
-    const legacyJavascriptResults = await LegacyJavascript.audit(artifacts, {
-      computedCache: new Map(),
-    });
+    const code = fs.readFileSync(`${dir}/main.bundle.min.js`, 'utf-8');
+    const map = JSON.parse(fs.readFileSync(`${dir}/main.bundle.min.js.map`, 'utf-8'));
+
+    let legacyJavascriptResults;
+
+    legacyJavascriptResults = await getLegacyJavascriptResults(code, map, {sourceMaps: true});
     fs.writeFileSync(`${dir}/legacy-javascript.json`,
+      // @ts-ignore: Items will exist.
+      JSON.stringify(legacyJavascriptResults.details.items, null, 2));
+
+    legacyJavascriptResults = await getLegacyJavascriptResults(code, map, {sourceMaps: false});
+    fs.writeFileSync(`${dir}/legacy-javascript-nomaps.json`,
+      // @ts-ignore: Items will exist.
       JSON.stringify(legacyJavascriptResults.details.items, null, 2));
   }
 }
 
-function makeSummary() {
+/**
+ * @param {string} code
+ * @param {LH.Artifacts.RawSourceMap} map
+ * @param {{sourceMaps: boolean}} _
+ * @return {Promise<LH.Audit.Product>}
+ */
+function getLegacyJavascriptResults(code, map, {sourceMaps}) {
+  // Instead of running Lighthouse, use LegacyJavascript directly. Requires some setup.
+  // Much faster than running Lighthouse.
+  const documentUrl = 'http://localhost/index.html'; // These URLs don't matter.
+  const scriptUrl = 'https://localhost/main.bundle.min.js';
+  const networkRecords = [
+    {url: documentUrl},
+    {url: scriptUrl},
+  ];
+  const devtoolsLogs = networkRecordsToDevtoolsLog(networkRecords);
+  const jsRequestWillBeSentEvent = devtoolsLogs.find(e =>
+    e.method === 'Network.requestWillBeSent' && e.params.request.url === scriptUrl);
+  if (!jsRequestWillBeSentEvent) throw new Error('jsRequestWillBeSentEvent is undefined');
+  // @ts-ignore - the log event is not narrowed to 'Network.requestWillBeSent' event from find
+  const jsRequestId = jsRequestWillBeSentEvent.params.requestId;
+
+  /** @type {Pick<LH.Artifacts, 'devtoolsLogs'|'URL'|'ScriptElements'|'SourceMaps'>} */
+  const artifacts = {
+    URL: {finalUrl: documentUrl, requestedUrl: documentUrl},
+    devtoolsLogs: {
+      [LegacyJavascript.DEFAULT_PASS]: devtoolsLogs,
+    },
+    ScriptElements: [
+      // @ts-ignore - partial ScriptElement excluding unused DOM properties
+      {src: scriptUrl, requestId: jsRequestId, content: code},
+    ],
+    SourceMaps: [],
+  };
+  if (sourceMaps) artifacts.SourceMaps = [{scriptUrl, map}];
+  // @ts-ignore: partial Artifacts.
+  return LegacyJavascript.audit(artifacts, {
+    computedCache: new Map(),
+  });
+}
+
+/**
+ * @param {string} legacyJavascriptFilename
+ */
+function makeSummary(legacyJavascriptFilename) {
   let totalSignals = 0;
   const variants = [];
   for (const dir of glob.sync('*/*', {cwd: VARIANT_DIR})) {
     /** @type {Array<{signals: string[]}>} */
-    const legacyJavascriptItems = require(`${VARIANT_DIR}/${dir}/legacy-javascript.json`);
+    const legacyJavascriptItems = require(`${VARIANT_DIR}/${dir}/${legacyJavascriptFilename}`);
     const signals = legacyJavascriptItems.reduce((acc, cur) => {
       totalSignals += cur.signals.length;
       return acc.concat(cur.signals);
@@ -349,7 +264,10 @@ async function main() {
 
   removeCoreJs();
 
-  const summary = makeSummary();
+  let summary;
+
+  // Summary of using source maps and pattern matching.
+  summary = makeSummary('legacy-javascript.json');
   fs.writeFileSync(`${__dirname}/summary-signals.json`, JSON.stringify(summary, null, 2));
   console.log({
     totalSignals: summary.totalSignals,
@@ -357,6 +275,10 @@ async function main() {
   });
   console.table(summary.variants);
 
+  // Summary of using only pattern matching.
+  summary = makeSummary('legacy-javascript-nomaps.json');
+  fs.writeFileSync(`${__dirname}/summary-signals-nomaps.json`, JSON.stringify(summary, null, 2));
+
   createSummarySizes();
 }
 
diff --git a/lighthouse-core/scripts/legacy-javascript/summary-signals-nomaps.json b/lighthouse-core/scripts/legacy-javascript/summary-signals-nomaps.json
new file mode 100644
index 000000000..80c99eb6b
--- /dev/null
+++ b/lighthouse-core/scripts/legacy-javascript/summary-signals-nomaps.json
@@ -0,0 +1,715 @@
+{
+  "totalSignals": 205,
+  "variantsMissingSignals": [
+    "core-js-2-only-polyfill/es6-array-filter",
+    "core-js-2-only-polyfill/es6-array-map",
+    "core-js-2-only-polyfill/es6-array-reduce",
+    "core-js-2-only-polyfill/es6-array-reduce-right",
+    "core-js-2-only-polyfill/es6-array-some",
+    "core-js-2-only-polyfill/es6-date-to-string",
+    "core-js-2-only-polyfill/es6-function-name",
+    "core-js-2-only-polyfill/es6-object-freeze",
+    "core-js-2-only-polyfill/es6-object-get-own-property-descriptor",
+    "core-js-2-only-polyfill/es6-object-get-own-property-names",
+    "core-js-2-only-polyfill/es6-object-get-prototype-of",
+    "core-js-2-only-polyfill/es6-object-is-extensible",
+    "core-js-2-only-polyfill/es6-object-is-frozen",
+    "core-js-2-only-polyfill/es6-object-is-sealed",
+    "core-js-2-only-polyfill/es6-object-keys",
+    "core-js-2-only-polyfill/es6-object-prevent-extensions",
+    "core-js-2-only-polyfill/es6-object-seal",
+    "core-js-2-only-polyfill/es6-reflect-define-property",
+    "core-js-2-only-polyfill/es6-string-trim",
+    "core-js-2-preset-env-esmodules/true",
+    "core-js-3-only-polyfill/es6-array-filter",
+    "core-js-3-only-polyfill/es6-array-map",
+    "core-js-3-only-polyfill/es6-array-reduce",
+    "core-js-3-only-polyfill/es6-array-reduce-right",
+    "core-js-3-only-polyfill/es6-array-some",
+    "core-js-3-only-polyfill/es6-date-to-string",
+    "core-js-3-only-polyfill/es6-function-name",
+    "core-js-3-only-polyfill/es6-object-freeze",
+    "core-js-3-only-polyfill/es6-object-get-own-property-descriptor",
+    "core-js-3-only-polyfill/es6-object-get-own-property-names",
+    "core-js-3-only-polyfill/es6-object-get-prototype-of",
+    "core-js-3-only-polyfill/es6-object-is-extensible",
+    "core-js-3-only-polyfill/es6-object-is-frozen",
+    "core-js-3-only-polyfill/es6-object-is-sealed",
+    "core-js-3-only-polyfill/es6-object-keys",
+    "core-js-3-only-polyfill/es6-object-prevent-extensions",
+    "core-js-3-only-polyfill/es6-object-seal",
+    "core-js-3-only-polyfill/es6-reflect-define-property",
+    "core-js-3-only-polyfill/es6-string-trim",
+    "core-js-3-preset-env-esmodules/true"
+  ],
+  "variants": [
+    {
+      "name": "core-js-2-only-polyfill/es6-array-fill",
+      "signals": "Array.prototype.fill"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-filter",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-find",
+      "signals": "Array.prototype.find"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-find-index",
+      "signals": "Array.prototype.findIndex"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-for-each",
+      "signals": "Array.prototype.forEach"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-from",
+      "signals": "Array.from"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-is-array",
+      "signals": "Array.isArray"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-last-index-of",
+      "signals": "Array.prototype.lastIndexOf"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-map",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-of",
+      "signals": "Array.of"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-reduce",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-reduce-right",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-array-some",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-date-now",
+      "signals": "Date.now"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-date-to-iso-string",
+      "signals": "Date.prototype.toISOString"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-date-to-json",
+      "signals": "Date.prototype.toJSON"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-date-to-string",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-function-name",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-map",
+      "signals": "Map"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-number-is-integer",
+      "signals": "Number.isInteger"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-number-is-safe-integer",
+      "signals": "Number.isSafeInteger"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-number-parse-float",
+      "signals": "Number.parseFloat"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-number-parse-int",
+      "signals": "Number.parseInt"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-assign",
+      "signals": "Object.assign"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-create",
+      "signals": "Object.create"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-define-properties",
+      "signals": "Object.defineProperties"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-define-property",
+      "signals": "Object.defineProperty"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-freeze",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-get-own-property-descriptor",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-get-own-property-names",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-get-prototype-of",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-is-extensible",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-is-frozen",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-is-sealed",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-keys",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-prevent-extensions",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-seal",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-object-set-prototype-of",
+      "signals": "Object.setPrototypeOf"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-promise",
+      "signals": "Promise"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-apply",
+      "signals": "Reflect.apply"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-construct",
+      "signals": "Reflect.construct"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-define-property",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-delete-property",
+      "signals": "Reflect.deleteProperty"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-get",
+      "signals": "Reflect.get"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-get-own-property-descriptor",
+      "signals": "Reflect.getOwnPropertyDescriptor"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-get-prototype-of",
+      "signals": "Reflect.getPrototypeOf"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-has",
+      "signals": "Reflect.has"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-is-extensible",
+      "signals": "Reflect.isExtensible"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-own-keys",
+      "signals": "Reflect.ownKeys"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-prevent-extensions",
+      "signals": "Reflect.preventExtensions"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-set",
+      "signals": "Reflect.set"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-reflect-set-prototype-of",
+      "signals": "Reflect.setPrototypeOf"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-set",
+      "signals": "Set"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-code-point-at",
+      "signals": "String.prototype.codePointAt"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-ends-with",
+      "signals": "String.prototype.endsWith"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-from-code-point",
+      "signals": "String.fromCodePoint"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-includes",
+      "signals": "String.prototype.includes"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-raw",
+      "signals": "String.raw"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-repeat",
+      "signals": "String.prototype.repeat"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-starts-with",
+      "signals": "String.prototype.startsWith"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-string-trim",
+      "signals": ""
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-array-buffer",
+      "signals": "ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-data-view",
+      "signals": "ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-float32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Float32Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-float64-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Float64Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-int16-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int16Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-int32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int32Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-int8-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int8Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-uint16-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint16Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-uint32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint32Array"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-uint8-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-typed-uint8-clamped-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint8ClampedArray"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-weak-map",
+      "signals": "WeakMap"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es6-weak-set",
+      "signals": "WeakSet"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-array-includes",
+      "signals": "Array.prototype.includes"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-object-entries",
+      "signals": "Object.entries"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-object-get-own-property-descriptors",
+      "signals": "Object.getOwnPropertyDescriptors"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-object-values",
+      "signals": "Object.values"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-string-pad-end",
+      "signals": "String.prototype.padEnd"
+    },
+    {
+      "name": "core-js-2-only-polyfill/es7-string-pad-start",
+      "signals": "String.prototype.padStart"
+    },
+    {
+      "name": "core-js-2-preset-env-esmodules/false",
+      "signals": "@babel/plugin-transform-classes, @babel/plugin-transform-regenerator, @babel/plugin-transform-spread"
+    },
+    {
+      "name": "core-js-2-preset-env-esmodules/true",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-fill",
+      "signals": "Array.prototype.fill"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-filter",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-find",
+      "signals": "Array.prototype.find"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-find-index",
+      "signals": "Array.prototype.findIndex"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-for-each",
+      "signals": "Array.prototype.forEach"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-from",
+      "signals": "Array.from"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-is-array",
+      "signals": "Array.isArray"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-last-index-of",
+      "signals": "Array.prototype.lastIndexOf"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-map",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-of",
+      "signals": "Array.of"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-reduce",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-reduce-right",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-array-some",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-date-now",
+      "signals": "Date.now"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-date-to-iso-string",
+      "signals": "Date.prototype.toISOString"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-date-to-json",
+      "signals": "Date.prototype.toJSON"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-date-to-string",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-function-name",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-map",
+      "signals": "Map"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-number-is-integer",
+      "signals": "Number.isInteger"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-number-is-safe-integer",
+      "signals": "Number.isSafeInteger"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-number-parse-float",
+      "signals": "Number.parseFloat"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-number-parse-int",
+      "signals": "Number.parseInt"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-assign",
+      "signals": "Object.assign"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-create",
+      "signals": "Object.create"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-define-properties",
+      "signals": "Object.defineProperties"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-define-property",
+      "signals": "Object.defineProperty"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-freeze",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-get-own-property-descriptor",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-get-own-property-names",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-get-prototype-of",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-is-extensible",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-is-frozen",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-is-sealed",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-keys",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-prevent-extensions",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-seal",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-object-set-prototype-of",
+      "signals": "Object.setPrototypeOf"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-promise",
+      "signals": "Promise"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-apply",
+      "signals": "Reflect.apply"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-construct",
+      "signals": "Reflect.construct"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-define-property",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-delete-property",
+      "signals": "Reflect.deleteProperty"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-get",
+      "signals": "Reflect.get"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-get-own-property-descriptor",
+      "signals": "Reflect.getOwnPropertyDescriptor"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-get-prototype-of",
+      "signals": "Reflect.getPrototypeOf"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-has",
+      "signals": "Reflect.has"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-is-extensible",
+      "signals": "Reflect.isExtensible"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-own-keys",
+      "signals": "Reflect.ownKeys"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-prevent-extensions",
+      "signals": "Reflect.preventExtensions"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-set",
+      "signals": "Reflect.set"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-reflect-set-prototype-of",
+      "signals": "Reflect.setPrototypeOf"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-set",
+      "signals": "Set"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-code-point-at",
+      "signals": "String.prototype.codePointAt"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-ends-with",
+      "signals": "String.prototype.endsWith"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-from-code-point",
+      "signals": "String.fromCodePoint"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-includes",
+      "signals": "String.prototype.includes"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-raw",
+      "signals": "String.raw"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-repeat",
+      "signals": "String.prototype.repeat"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-starts-with",
+      "signals": "String.prototype.startsWith"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-string-trim",
+      "signals": ""
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-array-buffer",
+      "signals": "ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-data-view",
+      "signals": "ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-float32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Float32Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-float64-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Float64Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-int16-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int16Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-int32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int32Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-int8-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Int8Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-uint16-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint16Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-uint32-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint32Array"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-uint8-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-typed-uint8-clamped-array",
+      "signals": "Uint8Array, Object.getOwnPropertyDescriptor, ArrayBuffer, DataView, Uint8ClampedArray"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-weak-map",
+      "signals": "WeakMap"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es6-weak-set",
+      "signals": "WeakSet"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-array-includes",
+      "signals": "Array.prototype.includes"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-object-entries",
+      "signals": "Object.entries"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-object-get-own-property-descriptors",
+      "signals": "Object.getOwnPropertyDescriptors"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-object-values",
+      "signals": "Object.values"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-string-pad-end",
+      "signals": "String.prototype.padEnd"
+    },
+    {
+      "name": "core-js-3-only-polyfill/es7-string-pad-start",
+      "signals": "String.prototype.padStart"
+    },
+    {
+      "name": "core-js-3-preset-env-esmodules/false",
+      "signals": "@babel/plugin-transform-classes, @babel/plugin-transform-regenerator, @babel/plugin-transform-spread"
+    },
+    {
+      "name": "core-js-3-preset-env-esmodules/true",
+      "signals": ""
+    },
+    {
+      "name": "only-plugin/-babel-plugin-transform-classes",
+      "signals": "@babel/plugin-transform-classes"
+    },
+    {
+      "name": "only-plugin/-babel-plugin-transform-regenerator",
+      "signals": "@babel/plugin-transform-regenerator"
+    },
+    {
+      "name": "only-plugin/-babel-plugin-transform-spread",
+      "signals": "@babel/plugin-transform-spread"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/lighthouse-core/scripts/legacy-javascript/summary-signals.json b/lighthouse-core/scripts/legacy-javascript/summary-signals.json
index e5967863f..af3a7b838 100644
--- a/lighthouse-core/scripts/legacy-javascript/summary-signals.json
+++ b/lighthouse-core/scripts/legacy-javascript/summary-signals.json
@@ -1,125 +1,17 @@
 {
-  "totalSignals": 205,
+  "totalSignals": 243,
   "variantsMissingSignals": [
-    "core-js-2-only-polyfill/es6-array-copy-within",
-    "core-js-2-only-polyfill/es6-array-every",
-    "core-js-2-only-polyfill/es6-array-filter",
-    "core-js-2-only-polyfill/es6-array-index-of",
-    "core-js-2-only-polyfill/es6-array-iterator",
-    "core-js-2-only-polyfill/es6-array-map",
-    "core-js-2-only-polyfill/es6-array-reduce",
-    "core-js-2-only-polyfill/es6-array-reduce-right",
-    "core-js-2-only-polyfill/es6-array-some",
-    "core-js-2-only-polyfill/es6-array-species",
-    "core-js-2-only-polyfill/es6-date-to-primitive",
-    "core-js-2-only-polyfill/es6-date-to-string",
-    "core-js-2-only-polyfill/es6-function-bind",
-    "core-js-2-only-polyfill/es6-function-has-instance",
-    "core-js-2-only-polyfill/es6-function-name",
-    "core-js-2-only-polyfill/es6-math-acosh",
-    "core-js-2-only-polyfill/es6-math-asinh",
-    "core-js-2-only-polyfill/es6-math-atanh",
-    "core-js-2-only-polyfill/es6-math-cbrt",
-    "core-js-2-only-polyfill/es6-math-clz32",
-    "core-js-2-only-polyfill/es6-math-cosh",
-    "core-js-2-only-polyfill/es6-math-expm1",
-    "core-js-2-only-polyfill/es6-math-fround",
-    "core-js-2-only-polyfill/es6-math-hypot",
-    "core-js-2-only-polyfill/es6-math-imul",
-    "core-js-2-only-polyfill/es6-math-log10",
-    "core-js-2-only-polyfill/es6-math-log1p",
-    "core-js-2-only-polyfill/es6-math-log2",
-    "core-js-2-only-polyfill/es6-math-sign",
-    "core-js-2-only-polyfill/es6-math-sinh",
-    "core-js-2-only-polyfill/es6-math-tanh",
-    "core-js-2-only-polyfill/es6-math-trunc",
-    "core-js-2-only-polyfill/es6-number-constructor",
-    "core-js-2-only-polyfill/es6-number-epsilon",
-    "core-js-2-only-polyfill/es6-number-max-safe-integer",
-    "core-js-2-only-polyfill/es6-number-min-safe-integer",
-    "core-js-2-only-polyfill/es6-object-freeze",
-    "core-js-2-only-polyfill/es6-object-get-own-property-descriptor",
-    "core-js-2-only-polyfill/es6-object-get-own-property-names",
-    "core-js-2-only-polyfill/es6-object-get-prototype-of",
-    "core-js-2-only-polyfill/es6-object-is-extensible",
-    "core-js-2-only-polyfill/es6-object-is-frozen",
-    "core-js-2-only-polyfill/es6-object-is-sealed",
-    "core-js-2-only-polyfill/es6-object-keys",
-    "core-js-2-only-polyfill/es6-object-prevent-extensions",
-    "core-js-2-only-polyfill/es6-object-seal",
-    "core-js-2-only-polyfill/es6-object-to-string",
-    "core-js-2-only-polyfill/es6-reflect-define-property",
-    "core-js-2-only-polyfill/es6-string-iterator",
-    "core-js-2-only-polyfill/es6-string-trim",
     "core-js-2-preset-env-esmodules/true",
-    "core-js-3-only-polyfill/es6-array-copy-within",
-    "core-js-3-only-polyfill/es6-array-every",
-    "core-js-3-only-polyfill/es6-array-filter",
-    "core-js-3-only-polyfill/es6-array-index-of",
-    "core-js-3-only-polyfill/es6-array-iterator",
-    "core-js-3-only-polyfill/es6-array-map",
-    "core-js-3-only-polyfill/es6-array-reduce",
-    "core-js-3-only-polyfill/es6-array-reduce-right",
-    "core-js-3-only-polyfill/es6-array-some",
-    "core-js-3-only-polyfill/es6-array-species",
-    "core-js-3-only-polyfill/es6-date-to-primitive",
-    "core-js-3-only-polyfill/es6-date-to-string",
-    "core-js-3-only-polyfill/es6-function-bind",
-    "core-js-3-only-polyfill/es6-function-has-instance",
-    "core-js-3-only-polyfill/es6-function-name",
-    "core-js-3-only-polyfill/es6-math-acosh",
-    "core-js-3-only-polyfill/es6-math-asinh",
-    "core-js-3-only-polyfill/es6-math-atanh",
-    "core-js-3-only-polyfill/es6-math-cbrt",
-    "core-js-3-only-polyfill/es6-math-clz32",
-    "core-js-3-only-polyfill/es6-math-cosh",
-    "core-js-3-only-polyfill/es6-math-expm1",
-    "core-js-3-only-polyfill/es6-math-fround",
-    "core-js-3-only-polyfill/es6-math-hypot",
-    "core-js-3-only-polyfill/es6-math-imul",
-    "core-js-3-only-polyfill/es6-math-log10",
-    "core-js-3-only-polyfill/es6-math-log1p",
-    "core-js-3-only-polyfill/es6-math-log2",
-    "core-js-3-only-polyfill/es6-math-sign",
-    "core-js-3-only-polyfill/es6-math-sinh",
-    "core-js-3-only-polyfill/es6-math-tanh",
-    "core-js-3-only-polyfill/es6-math-trunc",
-    "core-js-3-only-polyfill/es6-number-constructor",
-    "core-js-3-only-polyfill/es6-number-epsilon",
-    "core-js-3-only-polyfill/es6-number-max-safe-integer",
-    "core-js-3-only-polyfill/es6-number-min-safe-integer",
-    "core-js-3-only-polyfill/es6-object-freeze",
-    "core-js-3-only-polyfill/es6-object-get-own-property-descriptor",
-    "core-js-3-only-polyfill/es6-object-get-own-property-names",
-    "core-js-3-only-polyfill/es6-object-get-prototype-of",
-    "core-js-3-only-polyfill/es6-object-is-extensible",
-    "core-js-3-only-polyfill/es6-object-is-frozen",
-    "core-js-3-only-polyfill/es6-object-is-sealed",
-    "core-js-3-only-polyfill/es6-object-keys",
-    "core-js-3-only-polyfill/es6-object-prevent-extensions",
-    "core-js-3-only-polyfill/es6-object-seal",
-    "core-js-3-only-polyfill/es6-object-to-string",
-    "core-js-3-only-polyfill/es6-reflect-define-property",
-    "core-js-3-only-polyfill/es6-string-iterator",
-    "core-js-3-only-polyfill/es6-string-trim",
     "core-js-3-preset-env-esmodules/true"
   ],
   "variants": [
-    {
-      "name": "core-js-2-only-polyfill/es6-array-copy-within",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-array-every",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-array-fill",
-      "signals": "Array.fill"
+      "signals": "Array.prototype.fill"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-filter",
-      "signals": ""
+      "signals": "Array.prototype.filter"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-find",
@@ -137,25 +29,17 @@
       "name": "core-js-2-only-polyfill/es6-array-from",
       "signals": "Array.from"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-array-index-of",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-array-is-array",
       "signals": "Array.isArray"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-array-iterator",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-array-last-index-of",
       "signals": "Array.prototype.lastIndexOf"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-map",
-      "signals": ""
+      "signals": "Array.prototype.map"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-of",
@@ -163,19 +47,15 @@
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-reduce",
-      "signals": ""
+      "signals": "Array.prototype.reduce"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-reduce-right",
-      "signals": ""
+      "signals": "Array.prototype.reduceRight"
     },
     {
       "name": "core-js-2-only-polyfill/es6-array-some",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-array-species",
-      "signals": ""
+      "signals": "Array.prototype.some"
     },
     {
       "name": "core-js-2-only-polyfill/es6-date-now",
@@ -189,106 +69,18 @@
       "name": "core-js-2-only-polyfill/es6-date-to-json",
       "signals": "Date.prototype.toJSON"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-date-to-primitive",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-date-to-string",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-function-bind",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-function-has-instance",
-      "signals": ""
+      "signals": "Date.prototype.toString"
     },
     {
       "name": "core-js-2-only-polyfill/es6-function-name",
-      "signals": ""
+      "signals": "Function.prototype.name"
     },
     {
       "name": "core-js-2-only-polyfill/es6-map",
       "signals": "Map"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-acosh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-asinh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-atanh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-cbrt",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-clz32",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-cosh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-expm1",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-fround",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-hypot",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-imul",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-log10",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-log1p",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-log2",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-sign",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-sinh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-tanh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-math-trunc",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-number-constructor",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-number-epsilon",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-number-is-integer",
       "signals": "Number.isInteger"
@@ -297,14 +89,6 @@
       "name": "core-js-2-only-polyfill/es6-number-is-safe-integer",
       "signals": "Number.isSafeInteger"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-number-max-safe-integer",
-      "signals": ""
-    },
-    {
-      "name": "core-js-2-only-polyfill/es6-number-min-safe-integer",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-number-parse-float",
       "signals": "Number.parseFloat"
@@ -331,52 +115,48 @@
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-freeze",
-      "signals": ""
+      "signals": "Object.freeze"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-get-own-property-descriptor",
-      "signals": ""
+      "signals": "Object.getOwnPropertyDescriptor"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-get-own-property-names",
-      "signals": ""
+      "signals": "Object.getOwnPropertyNames"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-get-prototype-of",
-      "signals": ""
+      "signals": "Object.getPrototypeOf"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-is-extensible",
-      "signals": ""
+      "signals": "Object.isExtensible"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-is-frozen",
-      "signals": ""
+      "signals": "Object.isFrozen"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-is-sealed",
-      "signals": ""
+      "signals": "Object.isSealed"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-keys",
-      "signals": ""
+      "signals": "Object.keys"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-prevent-extensions",
-      "signals": ""
+      "signals": "Object.preventExtensions"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-seal",
-      "signals": ""
+      "signals": "Object.seal"
     },
     {
       "name": "core-js-2-only-polyfill/es6-object-set-prototype-of",
       "signals": "Object.setPrototypeOf"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-object-to-string",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-promise",
       "signals": "Promise"
@@ -391,7 +171,7 @@
     },
     {
       "name": "core-js-2-only-polyfill/es6-reflect-define-property",
-      "signals": ""
+      "signals": "Reflect.defineProperty"
     },
     {
       "name": "core-js-2-only-polyfill/es6-reflect-delete-property",
@@ -453,10 +233,6 @@
       "name": "core-js-2-only-polyfill/es6-string-includes",
       "signals": "String.prototype.includes"
     },
-    {
-      "name": "core-js-2-only-polyfill/es6-string-iterator",
-      "signals": ""
-    },
     {
       "name": "core-js-2-only-polyfill/es6-string-raw",
       "signals": "String.raw"
@@ -471,7 +247,7 @@
     },
     {
       "name": "core-js-2-only-polyfill/es6-string-trim",
-      "signals": ""
+      "signals": "String.prototype.trim"
     },
     {
       "name": "core-js-2-only-polyfill/es6-typed-array-buffer",
@@ -557,21 +333,13 @@
       "name": "core-js-2-preset-env-esmodules/true",
       "signals": ""
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-array-copy-within",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-array-every",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-array-fill",
-      "signals": "Array.fill"
+      "signals": "Array.prototype.fill"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-filter",
-      "signals": ""
+      "signals": "Array.prototype.filter"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-find",
@@ -589,25 +357,17 @@
       "name": "core-js-3-only-polyfill/es6-array-from",
       "signals": "Array.from"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-array-index-of",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-array-is-array",
       "signals": "Array.isArray"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-array-iterator",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-array-last-index-of",
       "signals": "Array.prototype.lastIndexOf"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-map",
-      "signals": ""
+      "signals": "Array.prototype.map"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-of",
@@ -615,19 +375,15 @@
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-reduce",
-      "signals": ""
+      "signals": "Array.prototype.reduce"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-reduce-right",
-      "signals": ""
+      "signals": "Array.prototype.reduceRight"
     },
     {
       "name": "core-js-3-only-polyfill/es6-array-some",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-array-species",
-      "signals": ""
+      "signals": "Array.prototype.some"
     },
     {
       "name": "core-js-3-only-polyfill/es6-date-now",
@@ -641,106 +397,18 @@
       "name": "core-js-3-only-polyfill/es6-date-to-json",
       "signals": "Date.prototype.toJSON"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-date-to-primitive",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-date-to-string",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-function-bind",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-function-has-instance",
-      "signals": ""
+      "signals": "Date.prototype.toString"
     },
     {
       "name": "core-js-3-only-polyfill/es6-function-name",
-      "signals": ""
+      "signals": "Function.prototype.name"
     },
     {
       "name": "core-js-3-only-polyfill/es6-map",
       "signals": "Map"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-acosh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-asinh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-atanh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-cbrt",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-clz32",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-cosh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-expm1",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-fround",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-hypot",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-imul",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-log10",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-log1p",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-log2",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-sign",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-sinh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-tanh",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-math-trunc",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-number-constructor",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-number-epsilon",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-number-is-integer",
       "signals": "Number.isInteger"
@@ -749,14 +417,6 @@
       "name": "core-js-3-only-polyfill/es6-number-is-safe-integer",
       "signals": "Number.isSafeInteger"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-number-max-safe-integer",
-      "signals": ""
-    },
-    {
-      "name": "core-js-3-only-polyfill/es6-number-min-safe-integer",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-number-parse-float",
       "signals": "Number.parseFloat"
@@ -783,52 +443,48 @@
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-freeze",
-      "signals": ""
+      "signals": "Object.freeze"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-get-own-property-descriptor",
-      "signals": ""
+      "signals": "Object.getOwnPropertyDescriptor"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-get-own-property-names",
-      "signals": ""
+      "signals": "Object.getOwnPropertyNames"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-get-prototype-of",
-      "signals": ""
+      "signals": "Object.getPrototypeOf"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-is-extensible",
-      "signals": ""
+      "signals": "Object.isExtensible"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-is-frozen",
-      "signals": ""
+      "signals": "Object.isFrozen"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-is-sealed",
-      "signals": ""
+      "signals": "Object.isSealed"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-keys",
-      "signals": ""
+      "signals": "Object.keys"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-prevent-extensions",
-      "signals": ""
+      "signals": "Object.preventExtensions"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-seal",
-      "signals": ""
+      "signals": "Object.seal"
     },
     {
       "name": "core-js-3-only-polyfill/es6-object-set-prototype-of",
       "signals": "Object.setPrototypeOf"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-object-to-string",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-promise",
       "signals": "Promise"
@@ -843,7 +499,7 @@
     },
     {
       "name": "core-js-3-only-polyfill/es6-reflect-define-property",
-      "signals": ""
+      "signals": "Reflect.defineProperty"
     },
     {
       "name": "core-js-3-only-polyfill/es6-reflect-delete-property",
@@ -905,10 +561,6 @@
       "name": "core-js-3-only-polyfill/es6-string-includes",
       "signals": "String.prototype.includes"
     },
-    {
-      "name": "core-js-3-only-polyfill/es6-string-iterator",
-      "signals": ""
-    },
     {
       "name": "core-js-3-only-polyfill/es6-string-raw",
       "signals": "String.raw"
@@ -923,7 +575,7 @@
     },
     {
       "name": "core-js-3-only-polyfill/es6-string-trim",
-      "signals": ""
+      "signals": "String.prototype.trim"
     },
     {
       "name": "core-js-3-only-polyfill/es6-typed-array-buffer",
diff --git a/lighthouse-core/scripts/legacy-javascript/summary-sizes.txt b/lighthouse-core/scripts/legacy-javascript/summary-sizes.txt
index 2aa40a40e..9fb2da643 100644
--- a/lighthouse-core/scripts/legacy-javascript/summary-sizes.txt
+++ b/lighthouse-core/scripts/legacy-javascript/summary-sizes.txt
@@ -1,238 +1,176 @@
 core-js-2-only-polyfill
-  47738        es6-typed-uint8-clamped-array/main.bundle.min.js
-  47718        es6-typed-float64-array/main.bundle.min.js
-  47718        es6-typed-float32-array/main.bundle.min.js
-  47714        es6-typed-uint32-array/main.bundle.min.js
-  47714        es6-typed-uint16-array/main.bundle.min.js
-  47710        es6-typed-uint8-array/main.bundle.min.js
-  47710        es6-typed-int32-array/main.bundle.min.js
-  47710        es6-typed-int16-array/main.bundle.min.js
-  47706        es6-typed-int8-array/main.bundle.min.js
-  29514        es6-map/main.bundle.min.js
-  29420        es6-set/main.bundle.min.js
-  27277        es6-weak-map/main.bundle.min.js
-  24645        es6-promise/main.bundle.min.js
-  23127        es6-typed-array-buffer/main.bundle.min.js
-  22881        es6-weak-set/main.bundle.min.js
-  20885        es6-typed-data-view/main.bundle.min.js
-  17640        es6-array-iterator/main.bundle.min.js
-  17387        es6-number-constructor/main.bundle.min.js
-  17329        es6-string-iterator/main.bundle.min.js
-  14880        es6-reflect-construct/main.bundle.min.js
-  12738        es7-object-get-own-property-descriptors/main.bundle.min.js
-  12329        es6-object-create/main.bundle.min.js
-  12184        es6-array-from/main.bundle.min.js
-  11963        es6-object-assign/main.bundle.min.js
-  11575        es6-object-get-own-property-names/main.bundle.min.js
-  11412        es6-array-find-index/main.bundle.min.js
-  11385        es6-array-find/main.bundle.min.js
-  11295        es7-object-entries/main.bundle.min.js
-  11290        es7-object-values/main.bundle.min.js
-  11240        es6-array-for-each/main.bundle.min.js
-  11213        es6-array-filter/main.bundle.min.js
-  11206        es6-array-every/main.bundle.min.js
-  11199        es6-array-some/main.bundle.min.js
-  11192        es6-array-map/main.bundle.min.js
-  11187        es6-object-keys/main.bundle.min.js
-  11159        es6-reflect-own-keys/main.bundle.min.js
-  11146        es6-object-define-properties/main.bundle.min.js
-  10840        es6-reflect-set/main.bundle.min.js
-  10362        es6-reflect-get/main.bundle.min.js
-  10323        es7-array-includes/main.bundle.min.js
-   9992        es6-array-index-of/main.bundle.min.js
-   9974        es6-string-ends-with/main.bundle.min.js
-   9928        es6-string-starts-with/main.bundle.min.js
-   9916        es6-array-copy-within/main.bundle.min.js
-   9840        es6-reflect-set-prototype-of/main.bundle.min.js
-   9726        es6-array-fill/main.bundle.min.js
-   9706        es6-array-reduce-right/main.bundle.min.js
-   9682        es6-object-set-prototype-of/main.bundle.min.js
-   9680        es6-array-reduce/main.bundle.min.js
-   9561        es7-string-pad-start/main.bundle.min.js
-   9554        es7-string-pad-end/main.bundle.min.js
-   9532        es6-object-get-own-property-descriptor/main.bundle.min.js
-   9458        es6-array-last-index-of/main.bundle.min.js
-   9315        es6-string-includes/main.bundle.min.js
-   9196        es6-reflect-delete-property/main.bundle.min.js
-   9173        es6-reflect-get-own-property-descriptor/main.bundle.min.js
-   9120        es6-object-prevent-extensions/main.bundle.min.js
-   9093        es6-number-parse-int/main.bundle.min.js
-   9087        es6-number-parse-float/main.bundle.min.js
-   9041        es6-object-freeze/main.bundle.min.js
-   9027        es6-object-seal/main.bundle.min.js
-   9009        es6-object-get-prototype-of/main.bundle.min.js
-   8843        es6-string-raw/main.bundle.min.js
-   8792        es6-function-bind/main.bundle.min.js
-   8667        es6-reflect-get-prototype-of/main.bundle.min.js
-   8593        es6-string-trim/main.bundle.min.js
-   8445        es6-string-from-code-point/main.bundle.min.js
-   8423        es6-date-to-iso-string/main.bundle.min.js
-   8413        es6-string-code-point-at/main.bundle.min.js
-   8219        es6-math-fround/main.bundle.min.js
-   8217        es6-string-repeat/main.bundle.min.js
-   8193        es6-array-of/main.bundle.min.js
-   8191        es6-date-to-json/main.bundle.min.js
-   8004        es6-reflect-define-property/main.bundle.min.js
-   7998        es6-object-is-extensible/main.bundle.min.js
-   7984        es6-math-sinh/main.bundle.min.js
-   7970        es6-object-is-sealed/main.bundle.min.js
-   7970        es6-object-is-frozen/main.bundle.min.js
-   7942        es6-reflect-apply/main.bundle.min.js
-   7907        es6-math-tanh/main.bundle.min.js
-   7906        es6-math-acosh/main.bundle.min.js
-   7876        es6-number-is-safe-integer/main.bundle.min.js
-   7821        es6-math-expm1/main.bundle.min.js
-   7814        es6-array-is-array/main.bundle.min.js
-   7786        es6-math-hypot/main.bundle.min.js
-   7763        es6-reflect-prevent-extensions/main.bundle.min.js
-   7752        es6-math-imul/main.bundle.min.js
-   7743        es6-number-is-integer/main.bundle.min.js
-   7702        es6-math-cbrt/main.bundle.min.js
-   7693        es6-reflect-is-extensible/main.bundle.min.js
-   7654        es6-math-log1p/main.bundle.min.js
-   7631        es6-math-sign/main.bundle.min.js
-   7628        es6-math-asinh/main.bundle.min.js
-   7608        es6-object-define-property/main.bundle.min.js
-   7592        es6-math-atanh/main.bundle.min.js
-   7551        es6-math-clz32/main.bundle.min.js
-   7539        es6-reflect-has/main.bundle.min.js
-   7533        es6-math-cosh/main.bundle.min.js
-   7531        es6-math-trunc/main.bundle.min.js
-   7530        es6-number-min-safe-integer/main.bundle.min.js
-   7529        es6-number-max-safe-integer/main.bundle.min.js
-   7523        es6-math-log10/main.bundle.min.js
-   7516        es6-math-log2/main.bundle.min.js
-   7506        es6-date-now/main.bundle.min.js
-   7501        es6-number-epsilon/main.bundle.min.js
-   6915        es6-object-to-string/main.bundle.min.js
-   5994        es6-function-has-instance/main.bundle.min.js
-   5993        es6-date-to-string/main.bundle.min.js
-   5422        es6-date-to-primitive/main.bundle.min.js
-   4774        es6-array-species/main.bundle.min.js
-   3410        es6-function-name/main.bundle.min.js
+  47782        es6-typed-uint8-clamped-array/main.bundle.min.js
+  47762        es6-typed-float64-array/main.bundle.min.js
+  47762        es6-typed-float32-array/main.bundle.min.js
+  47758        es6-typed-uint32-array/main.bundle.min.js
+  47758        es6-typed-uint16-array/main.bundle.min.js
+  47754        es6-typed-uint8-array/main.bundle.min.js
+  47754        es6-typed-int32-array/main.bundle.min.js
+  47754        es6-typed-int16-array/main.bundle.min.js
+  47750        es6-typed-int8-array/main.bundle.min.js
+  29558        es6-map/main.bundle.min.js
+  29464        es6-set/main.bundle.min.js
+  27321        es6-weak-map/main.bundle.min.js
+  24689        es6-promise/main.bundle.min.js
+  23171        es6-typed-array-buffer/main.bundle.min.js
+  22925        es6-weak-set/main.bundle.min.js
+  20929        es6-typed-data-view/main.bundle.min.js
+  14924        es6-reflect-construct/main.bundle.min.js
+  12782        es7-object-get-own-property-descriptors/main.bundle.min.js
+  12373        es6-object-create/main.bundle.min.js
+  12228        es6-array-from/main.bundle.min.js
+  12007        es6-object-assign/main.bundle.min.js
+  11619        es6-object-get-own-property-names/main.bundle.min.js
+  11456        es6-array-find-index/main.bundle.min.js
+  11429        es6-array-find/main.bundle.min.js
+  11339        es7-object-entries/main.bundle.min.js
+  11334        es7-object-values/main.bundle.min.js
+  11284        es6-array-for-each/main.bundle.min.js
+  11257        es6-array-filter/main.bundle.min.js
+  11243        es6-array-some/main.bundle.min.js
+  11236        es6-array-map/main.bundle.min.js
+  11231        es6-object-keys/main.bundle.min.js
+  11203        es6-reflect-own-keys/main.bundle.min.js
+  11190        es6-object-define-properties/main.bundle.min.js
+  10884        es6-reflect-set/main.bundle.min.js
+  10406        es6-reflect-get/main.bundle.min.js
+  10367        es7-array-includes/main.bundle.min.js
+  10018        es6-string-ends-with/main.bundle.min.js
+   9972        es6-string-starts-with/main.bundle.min.js
+   9884        es6-reflect-set-prototype-of/main.bundle.min.js
+   9770        es6-array-fill/main.bundle.min.js
+   9750        es6-array-reduce-right/main.bundle.min.js
+   9726        es6-object-set-prototype-of/main.bundle.min.js
+   9724        es6-array-reduce/main.bundle.min.js
+   9605        es7-string-pad-start/main.bundle.min.js
+   9598        es7-string-pad-end/main.bundle.min.js
+   9576        es6-object-get-own-property-descriptor/main.bundle.min.js
+   9502        es6-array-last-index-of/main.bundle.min.js
+   9359        es6-string-includes/main.bundle.min.js
+   9240        es6-reflect-delete-property/main.bundle.min.js
+   9217        es6-reflect-get-own-property-descriptor/main.bundle.min.js
+   9164        es6-object-prevent-extensions/main.bundle.min.js
+   9137        es6-number-parse-int/main.bundle.min.js
+   9131        es6-number-parse-float/main.bundle.min.js
+   9085        es6-object-freeze/main.bundle.min.js
+   9071        es6-object-seal/main.bundle.min.js
+   9053        es6-object-get-prototype-of/main.bundle.min.js
+   8887        es6-string-raw/main.bundle.min.js
+   8711        es6-reflect-get-prototype-of/main.bundle.min.js
+   8637        es6-string-trim/main.bundle.min.js
+   8489        es6-string-from-code-point/main.bundle.min.js
+   8467        es6-date-to-iso-string/main.bundle.min.js
+   8457        es6-string-code-point-at/main.bundle.min.js
+   8261        es6-string-repeat/main.bundle.min.js
+   8237        es6-array-of/main.bundle.min.js
+   8235        es6-date-to-json/main.bundle.min.js
+   8048        es6-reflect-define-property/main.bundle.min.js
+   8042        es6-object-is-extensible/main.bundle.min.js
+   8014        es6-object-is-sealed/main.bundle.min.js
+   8014        es6-object-is-frozen/main.bundle.min.js
+   7986        es6-reflect-apply/main.bundle.min.js
+   7920        es6-number-is-safe-integer/main.bundle.min.js
+   7858        es6-array-is-array/main.bundle.min.js
+   7807        es6-reflect-prevent-extensions/main.bundle.min.js
+   7787        es6-number-is-integer/main.bundle.min.js
+   7737        es6-reflect-is-extensible/main.bundle.min.js
+   7652        es6-object-define-property/main.bundle.min.js
+   7583        es6-reflect-has/main.bundle.min.js
+   7550        es6-date-now/main.bundle.min.js
+   6037        es6-date-to-string/main.bundle.min.js
+   3454        es6-function-name/main.bundle.min.js
 
 core-js-2-preset-env-esmodules
-  2813         false/main.bundle.min.js
-  1308         true/main.bundle.min.js
+  2857         false/main.bundle.min.js
+  1352         true/main.bundle.min.js
 
 core-js-3-only-polyfill
-  47737        es6-typed-uint8-clamped-array/main.bundle.min.js
-  47717        es6-typed-float64-array/main.bundle.min.js
-  47717        es6-typed-float32-array/main.bundle.min.js
-  47713        es6-typed-uint32-array/main.bundle.min.js
-  47713        es6-typed-uint16-array/main.bundle.min.js
-  47709        es6-typed-uint8-array/main.bundle.min.js
-  47709        es6-typed-int32-array/main.bundle.min.js
-  47709        es6-typed-int16-array/main.bundle.min.js
-  47705        es6-typed-int8-array/main.bundle.min.js
-  29516        es6-map/main.bundle.min.js
-  29422        es6-set/main.bundle.min.js
-  27278        es6-weak-map/main.bundle.min.js
-  24645        es6-promise/main.bundle.min.js
-  23127        es6-typed-array-buffer/main.bundle.min.js
-  22880        es6-weak-set/main.bundle.min.js
-  20885        es6-typed-data-view/main.bundle.min.js
-  17642        es6-array-iterator/main.bundle.min.js
-  17387        es6-number-constructor/main.bundle.min.js
-  17329        es6-string-iterator/main.bundle.min.js
-  14882        es6-reflect-construct/main.bundle.min.js
-  12740        es7-object-get-own-property-descriptors/main.bundle.min.js
-  12329        es6-object-create/main.bundle.min.js
-  12185        es6-array-from/main.bundle.min.js
-  11962        es6-object-assign/main.bundle.min.js
-  11574        es6-object-get-own-property-names/main.bundle.min.js
-  11412        es6-array-find-index/main.bundle.min.js
-  11385        es6-array-find/main.bundle.min.js
-  11294        es7-object-entries/main.bundle.min.js
-  11289        es7-object-values/main.bundle.min.js
-  11239        es6-array-for-each/main.bundle.min.js
-  11212        es6-array-filter/main.bundle.min.js
-  11205        es6-array-every/main.bundle.min.js
-  11198        es6-array-some/main.bundle.min.js
-  11191        es6-array-map/main.bundle.min.js
-  11186        es6-object-keys/main.bundle.min.js
-  11158        es6-reflect-own-keys/main.bundle.min.js
-  11145        es6-object-define-properties/main.bundle.min.js
-  10839        es6-reflect-set/main.bundle.min.js
-  10361        es6-reflect-get/main.bundle.min.js
-  10324        es7-array-includes/main.bundle.min.js
-   9991        es6-array-index-of/main.bundle.min.js
-   9973        es6-string-ends-with/main.bundle.min.js
-   9927        es6-string-starts-with/main.bundle.min.js
-   9915        es6-array-copy-within/main.bundle.min.js
-   9839        es6-reflect-set-prototype-of/main.bundle.min.js
-   9725        es6-array-fill/main.bundle.min.js
-   9705        es6-array-reduce-right/main.bundle.min.js
-   9681        es6-object-set-prototype-of/main.bundle.min.js
-   9679        es6-array-reduce/main.bundle.min.js
-   9561        es7-string-pad-start/main.bundle.min.js
-   9554        es7-string-pad-end/main.bundle.min.js
-   9531        es6-object-get-own-property-descriptor/main.bundle.min.js
-   9457        es6-array-last-index-of/main.bundle.min.js
-   9314        es6-string-includes/main.bundle.min.js
-   9195        es6-reflect-delete-property/main.bundle.min.js
-   9172        es6-reflect-get-own-property-descriptor/main.bundle.min.js
-   9119        es6-object-prevent-extensions/main.bundle.min.js
-   9094        es6-number-parse-int/main.bundle.min.js
-   9088        es6-number-parse-float/main.bundle.min.js
-   9040        es6-object-freeze/main.bundle.min.js
-   9026        es6-object-seal/main.bundle.min.js
-   9010        es6-object-get-prototype-of/main.bundle.min.js
-   8842        es6-string-raw/main.bundle.min.js
-   8792        es6-function-bind/main.bundle.min.js
-   8667        es6-reflect-get-prototype-of/main.bundle.min.js
-   8594        es6-string-trim/main.bundle.min.js
-   8444        es6-string-from-code-point/main.bundle.min.js
-   8424        es6-date-to-iso-string/main.bundle.min.js
-   8413        es6-string-code-point-at/main.bundle.min.js
-   8218        es6-math-fround/main.bundle.min.js
-   8217        es6-string-repeat/main.bundle.min.js
-   8194        es6-array-of/main.bundle.min.js
-   8192        es6-date-to-json/main.bundle.min.js
-   8003        es6-reflect-define-property/main.bundle.min.js
-   7997        es6-object-is-extensible/main.bundle.min.js
-   7983        es6-math-sinh/main.bundle.min.js
-   7969        es6-object-is-sealed/main.bundle.min.js
-   7969        es6-object-is-frozen/main.bundle.min.js
-   7941        es6-reflect-apply/main.bundle.min.js
-   7906        es6-math-tanh/main.bundle.min.js
-   7905        es6-math-acosh/main.bundle.min.js
-   7875        es6-number-is-safe-integer/main.bundle.min.js
-   7820        es6-math-expm1/main.bundle.min.js
-   7814        es6-array-is-array/main.bundle.min.js
-   7785        es6-math-hypot/main.bundle.min.js
-   7762        es6-reflect-prevent-extensions/main.bundle.min.js
-   7751        es6-math-imul/main.bundle.min.js
-   7742        es6-number-is-integer/main.bundle.min.js
-   7701        es6-math-cbrt/main.bundle.min.js
-   7692        es6-reflect-is-extensible/main.bundle.min.js
-   7653        es6-math-log1p/main.bundle.min.js
-   7630        es6-math-sign/main.bundle.min.js
-   7627        es6-math-asinh/main.bundle.min.js
-   7607        es6-object-define-property/main.bundle.min.js
-   7591        es6-math-atanh/main.bundle.min.js
-   7550        es6-math-clz32/main.bundle.min.js
-   7538        es6-reflect-has/main.bundle.min.js
-   7532        es6-math-cosh/main.bundle.min.js
-   7530        es6-math-trunc/main.bundle.min.js
-   7529        es6-number-min-safe-integer/main.bundle.min.js
-   7528        es6-number-max-safe-integer/main.bundle.min.js
-   7522        es6-math-log10/main.bundle.min.js
-   7515        es6-math-log2/main.bundle.min.js
-   7505        es6-date-now/main.bundle.min.js
-   7500        es6-number-epsilon/main.bundle.min.js
-   6917        es6-object-to-string/main.bundle.min.js
-   5993        es6-function-has-instance/main.bundle.min.js
-   5992        es6-date-to-string/main.bundle.min.js
-   5421        es6-date-to-primitive/main.bundle.min.js
-   4773        es6-array-species/main.bundle.min.js
-   3410        es6-function-name/main.bundle.min.js
+  47781        es6-typed-uint8-clamped-array/main.bundle.min.js
+  47761        es6-typed-float64-array/main.bundle.min.js
+  47761        es6-typed-float32-array/main.bundle.min.js
+  47757        es6-typed-uint32-array/main.bundle.min.js
+  47757        es6-typed-uint16-array/main.bundle.min.js
+  47753        es6-typed-uint8-array/main.bundle.min.js
+  47753        es6-typed-int32-array/main.bundle.min.js
+  47753        es6-typed-int16-array/main.bundle.min.js
+  47749        es6-typed-int8-array/main.bundle.min.js
+  29560        es6-map/main.bundle.min.js
+  29466        es6-set/main.bundle.min.js
+  27322        es6-weak-map/main.bundle.min.js
+  24689        es6-promise/main.bundle.min.js
+  23171        es6-typed-array-buffer/main.bundle.min.js
+  22924        es6-weak-set/main.bundle.min.js
+  20929        es6-typed-data-view/main.bundle.min.js
+  14926        es6-reflect-construct/main.bundle.min.js
+  12784        es7-object-get-own-property-descriptors/main.bundle.min.js
+  12373        es6-object-create/main.bundle.min.js
+  12229        es6-array-from/main.bundle.min.js
+  12006        es6-object-assign/main.bundle.min.js
+  11618        es6-object-get-own-property-names/main.bundle.min.js
+  11456        es6-array-find-index/main.bundle.min.js
+  11429        es6-array-find/main.bundle.min.js
+  11338        es7-object-entries/main.bundle.min.js
+  11333        es7-object-values/main.bundle.min.js
+  11283        es6-array-for-each/main.bundle.min.js
+  11256        es6-array-filter/main.bundle.min.js
+  11242        es6-array-some/main.bundle.min.js
+  11235        es6-array-map/main.bundle.min.js
+  11230        es6-object-keys/main.bundle.min.js
+  11202        es6-reflect-own-keys/main.bundle.min.js
+  11189        es6-object-define-properties/main.bundle.min.js
+  10883        es6-reflect-set/main.bundle.min.js
+  10405        es6-reflect-get/main.bundle.min.js
+  10368        es7-array-includes/main.bundle.min.js
+  10017        es6-string-ends-with/main.bundle.min.js
+   9971        es6-string-starts-with/main.bundle.min.js
+   9883        es6-reflect-set-prototype-of/main.bundle.min.js
+   9769        es6-array-fill/main.bundle.min.js
+   9749        es6-array-reduce-right/main.bundle.min.js
+   9725        es6-object-set-prototype-of/main.bundle.min.js
+   9723        es6-array-reduce/main.bundle.min.js
+   9605        es7-string-pad-start/main.bundle.min.js
+   9598        es7-string-pad-end/main.bundle.min.js
+   9575        es6-object-get-own-property-descriptor/main.bundle.min.js
+   9501        es6-array-last-index-of/main.bundle.min.js
+   9358        es6-string-includes/main.bundle.min.js
+   9239        es6-reflect-delete-property/main.bundle.min.js
+   9216        es6-reflect-get-own-property-descriptor/main.bundle.min.js
+   9163        es6-object-prevent-extensions/main.bundle.min.js
+   9138        es6-number-parse-int/main.bundle.min.js
+   9132        es6-number-parse-float/main.bundle.min.js
+   9084        es6-object-freeze/main.bundle.min.js
+   9070        es6-object-seal/main.bundle.min.js
+   9054        es6-object-get-prototype-of/main.bundle.min.js
+   8886        es6-string-raw/main.bundle.min.js
+   8711        es6-reflect-get-prototype-of/main.bundle.min.js
+   8638        es6-string-trim/main.bundle.min.js
+   8488        es6-string-from-code-point/main.bundle.min.js
+   8468        es6-date-to-iso-string/main.bundle.min.js
+   8457        es6-string-code-point-at/main.bundle.min.js
+   8261        es6-string-repeat/main.bundle.min.js
+   8238        es6-array-of/main.bundle.min.js
+   8236        es6-date-to-json/main.bundle.min.js
+   8047        es6-reflect-define-property/main.bundle.min.js
+   8041        es6-object-is-extensible/main.bundle.min.js
+   8013        es6-object-is-sealed/main.bundle.min.js
+   8013        es6-object-is-frozen/main.bundle.min.js
+   7985        es6-reflect-apply/main.bundle.min.js
+   7919        es6-number-is-safe-integer/main.bundle.min.js
+   7858        es6-array-is-array/main.bundle.min.js
+   7806        es6-reflect-prevent-extensions/main.bundle.min.js
+   7786        es6-number-is-integer/main.bundle.min.js
+   7736        es6-reflect-is-extensible/main.bundle.min.js
+   7651        es6-object-define-property/main.bundle.min.js
+   7582        es6-reflect-has/main.bundle.min.js
+   7549        es6-date-now/main.bundle.min.js
+   6036        es6-date-to-string/main.bundle.min.js
+   3454        es6-function-name/main.bundle.min.js
 
 core-js-3-preset-env-esmodules
-  2813         false/main.bundle.min.js
-  1308         true/main.bundle.min.js
+  2857         false/main.bundle.min.js
+  1352         true/main.bundle.min.js
 
 only-plugin
-  1706         -babel-plugin-transform-spread/main.bundle.min.js
-   827         -babel-plugin-transform-regenerator/main.bundle.min.js
-   814         -babel-plugin-transform-classes/main.bundle.min.js
+  1750         -babel-plugin-transform-spread/main.bundle.min.js
+   871         -babel-plugin-transform-regenerator/main.bundle.min.js
+   858         -babel-plugin-transform-classes/main.bundle.min.js
diff --git a/lighthouse-viewer/README.md b/lighthouse-viewer/README.md
index 7adc9ad46..01d023c53 100644
--- a/lighthouse-viewer/README.md
+++ b/lighthouse-viewer/README.md
@@ -21,20 +21,28 @@ yarn deploy-viewer
 
 For more information on deployment, see `releasing.md`.
 
-## Gist
+## Usage
 
-http://localhost:8000/?gist=bd1779783a5bbcb348564a58f80f7099
+### Load JSON from Gist
 
-## PSI
+Pass the GitHub Gist identifier as `gist` query parameter.
 
-Example:
-```
-http://localhost:8000/?psiurl=https://www.example.com&category=pwa&category=seo
-```
+e.g., `http://localhost:8000/?gist=bd1779783a5bbcb348564a58f80f7099`
+
+### Load JSON from URL
+
+Pass the absolute URL as `jsonurl` query parameter.
+
+e.g., `http://localhost:8000/?josnurl=https://gist.githubusercontent.com/Kikobeats/d570a1aa285c5d1d97bbda10b92fb97f/raw/4b0f14a5914edd25c95b4bd9d09728ab42181c3e/lighthouse.json`
+
+### Run and load from PageSpeed Insights
+
+Pass target URL `psiurl` query parameter.
+
+e.g., `http://localhost:8000/?psiurl=https://www.example.com&category=pwa&category=seo`
 
-Options:
+The following query parameters are also supported as options:
 
-`psiurl` - URL to audit
 `category` - Category to enable. One per category.
 `strategy` - mobile, desktop
 `locale` - locale to render report with
diff --git a/lighthouse-viewer/app/src/github-api.js b/lighthouse-viewer/app/src/github-api.js
index eaad39926..4d9ce6f59 100644
--- a/lighthouse-viewer/app/src/github-api.js
+++ b/lighthouse-viewer/app/src/github-api.js
@@ -22,6 +22,10 @@ class GithubApi {
     return '.lighthouse.report.json';
   }
 
+  getFirebaseAuth() {
+    return this._auth;
+  }
+
   /**
    * Creates a gist under the users account.
    * @param {LH.Result} jsonFile The gist file body.
diff --git a/lighthouse-viewer/app/src/lighthouse-report-viewer.js b/lighthouse-viewer/app/src/lighthouse-report-viewer.js
index 7f6e4f384..b054096ff 100644
--- a/lighthouse-viewer/app/src/lighthouse-report-viewer.js
+++ b/lighthouse-viewer/app/src/lighthouse-report-viewer.js
@@ -45,6 +45,7 @@ class LighthouseReportViewer {
      */
     this._reportIsFromGist = false;
     this._reportIsFromPSI = false;
+    this._reportIsFromJSON = false;
 
     this._addEventListeners();
     this._loadFromDeepLink();
@@ -100,8 +101,9 @@ class LighthouseReportViewer {
 
     const gistId = params.get('gist');
     const psiurl = params.get('psiurl');
+    const jsonurl = params.get('jsonurl');
 
-    if (!gistId && !psiurl) return Promise.resolve();
+    if (!gistId && !psiurl && !jsonurl) return Promise.resolve();
 
     this._toggleLoadingBlur(true);
     let loadPromise = Promise.resolve();
@@ -118,6 +120,21 @@ class LighthouseReportViewer {
         this._reportIsFromGist = true;
         this._replaceReportHtml(reportJson);
       }).catch(err => logger.error(err.message));
+    } else if (jsonurl) {
+      const firebaseAuth = this._github.getFirebaseAuth();
+      loadPromise = firebaseAuth.getAccessTokenIfLoggedIn()
+        .then(token => {
+          return token
+            ? Promise.reject(new Error('Can only use jsonurl when not logged in'))
+            : null;
+        })
+        .then(() => fetch(jsonurl))
+        .then(resp => resp.json())
+        .then(json => {
+          this._reportIsFromJSON = true;
+          this._replaceReportHtml(json);
+        })
+        .catch(err => logger.error(err.message));
     }
 
     return loadPromise.finally(() => this._toggleLoadingBlur(false));
@@ -184,7 +201,7 @@ class LighthouseReportViewer {
       }
 
       // Only clear query string if current report isn't from a gist or PSI.
-      if (!this._reportIsFromGist && !this._reportIsFromPSI) {
+      if (!this._reportIsFromGist && !this._reportIsFromPSI && !this._reportIsFromJSON) {
         history.pushState({}, '', LighthouseReportViewer.APP_URL);
       }
 
@@ -196,7 +213,7 @@ class LighthouseReportViewer {
       container.textContent = '';
       throw e;
     } finally {
-      this._reportIsFromGist = this._reportIsFromPSI = false;
+      this._reportIsFromGist = this._reportIsFromPSI = this._reportIsFromJSON = false;
     }
 
     // Remove the placeholder UI once the user has loaded a report.
diff --git a/package.json b/package.json
index 24d2888cd..55ddf3625 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
     "build-extension": "yarn build-extension-chrome && yarn build-extension-firefox",
     "build-extension-chrome": "node ./build/build-extension.js chrome",
     "build-extension-firefox": "node ./build/build-extension.js firefox",
-    "build-devtools": "yarn link && yarn link lighthouse && node ./build/build-bundle.js clients/devtools-entry.js dist/lighthouse-dt-bundle.js && node ./build/build-dt-report-resources.js",
+    "build-devtools": "(yarn unlink || true) && yarn link && yarn link lighthouse && node ./build/build-bundle.js clients/devtools-entry.js dist/lighthouse-dt-bundle.js && node ./build/build-dt-report-resources.js",
     "build-smokehouse-bundle": "node ./build/build-smokehouse-bundle.js",
     "build-lr": "node ./build/build-lightrider-bundles.js",
     "build-pack": "bash build/build-pack.sh",
diff --git a/readme.md b/readme.md
index b456b1a82..977d57821 100644
--- a/readme.md
+++ b/readme.md
@@ -416,6 +416,18 @@ Other awesome open source projects that use Lighthouse.
 
 See [Lighthouse Architecture](./docs/architecture.md).
 
+### Why is the performance score so low? It looks fine to me.
+
+Lighthouse reports the performance metrics as they would be experienced by a typical mobile user on a 4G connection and a mid-tier ~$200 phone. Even if it loads quickly on your device and network, users in other environments will experience the site very differently.
+
+Read more in our [guide to throttling](./docs/throttling.md).
+
+### Why does the performance score change so much?
+
+Lighthouse performance scores will change due to inherent variability in web and network technologies, even if there hasn't been a code change. Test in consistent environments, run Lighthouse multiple times, and beware of variability before drawing conclusions about a performance-impacting change.
+
+Read more in our [guide to reducing variability](./docs/variability.md).
+
 ### Can I configure the lighthouse run?
 
 Yes! Details in [Lighthouse configuration](./docs/configuration.md).


Test patch:
diff --git a/lighthouse-cli/test/smokehouse/test-definitions/legacy-javascript/legacy-javascript-config.js b/lighthouse-cli/test/smokehouse/test-definitions/legacy-javascript/legacy-javascript-config.js
index 20053469b..de04d3769 100644
--- a/lighthouse-cli/test/smokehouse/test-definitions/legacy-javascript/legacy-javascript-config.js
+++ b/lighthouse-cli/test/smokehouse/test-definitions/legacy-javascript/legacy-javascript-config.js
@@ -10,6 +10,12 @@
  */
 module.exports = {
   extends: 'lighthouse:default',
+  passes: [{
+    passName: 'defaultPass',
+    gatherers: [
+      'source-maps',
+    ],
+  }],
   settings: {
     onlyCategories: [
       'performance',
diff --git a/lighthouse-cli/test/smokehouse/test-definitions/pwa/pwa3-expectations.js b/lighthouse-cli/test/smokehouse/test-definitions/pwa/pwa3-expectations.js
index eb211c5b6..27bc60776 100644
--- a/lighthouse-cli/test/smokehouse/test-definitions/pwa/pwa3-expectations.js
+++ b/lighthouse-cli/test/smokehouse/test-definitions/pwa/pwa3-expectations.js
@@ -16,8 +16,10 @@ const pwaRocksExpectations = {...pwaDetailsExpectations, hasIconsAtLeast512px: f
 module.exports = [
   {
     lhr: {
-      requestedUrl: 'https://pwa.rocks',
-      finalUrl: 'https://pwa.rocks/',
+      // Archived version of https://github.com/pwarocks/pwa.rocks
+      // Fork is here: https://github.com/connorjclark/pwa.rocks
+      requestedUrl: 'https://connorjclark.github.io/pwa.rocks/',
+      finalUrl: 'https://connorjclark.github.io/pwa.rocks/',
       audits: {
         'is-on-https': {
           score: 1,
diff --git a/lighthouse-core/test/audits/legacy-javascript-test.js b/lighthouse-core/test/audits/legacy-javascript-test.js
index 4509e8544..4df65e4ac 100644
--- a/lighthouse-core/test/audits/legacy-javascript-test.js
+++ b/lighthouse-core/test/audits/legacy-javascript-test.js
@@ -10,7 +10,7 @@ const LegacyJavascript = require('../../audits/legacy-javascript.js');
 const networkRecordsToDevtoolsLog = require('../network-records-to-devtools-log.js');
 
 /**
- * @param {Array<{url: string, code: string}>} scripts
+ * @param {Array<{url: string, code: string, map?: LH.Artifacts.RawSourceMap}>} scripts
  * @return {LH.Artifacts}
  */
 const createArtifacts = (scripts) => {
@@ -21,13 +21,21 @@ const createArtifacts = (scripts) => {
   return {
     URL: {finalUrl: '', requestedUrl: ''},
     devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(networkRecords)},
-    ScriptElements: scripts.reduce((acc, {code}, index) => {
-      acc[String(index)] = {
+    ScriptElements: scripts.map(({url, code}, index) => {
+      return {
+        src: url,
         content: code,
         requestId: String(index),
       };
+    }),
+    SourceMaps: scripts.reduce((acc, {url, map}) => {
+      if (!map) return acc;
+      acc.push({
+        scriptUrl: url,
+        map,
+      });
       return acc;
-    }, {}),
+    }, []),
   };
 };
 
@@ -164,17 +172,53 @@ describe('LegacyJavaScript audit', () => {
     expect(result.details.items.map(item => getCodeForUrl(item.url))).toEqual([]);
     assert.equal(result.score, 1);
   });
+
+  it('uses source maps to identify polyfills', async () => {
+    const map = {
+      sources: [
+        'node_modules/blah/blah/es6.string.repeat.js',
+      ],
+      mappings: 'blah',
+    };
+    const script = {code: 'blah blah', url: 'https://www.example.com/0.js', map};
+    const artifacts = createArtifacts([script]);
+
+    const result = await LegacyJavascript.audit(artifacts, {computedCache: new Map()});
+    expect(result.details.items[0].signals).toEqual(['String.prototype.repeat']);
+    expect(result.details.items[0].locations).toMatchObject([{line: 0, column: 0}]);
+  });
+
+  it('uses location from pattern matching over source map', async () => {
+    const map = {
+      sources: [
+        'node_modules/blah/blah/es6.string.repeat.js',
+      ],
+      mappings: 'blah',
+    };
+    const script = {
+      code: 'some code;\nString.prototype.repeat = function() {}',
+      url: 'https://www.example.com/0.js',
+      map,
+    };
+    const artifacts = createArtifacts([script]);
+
+    const result = await LegacyJavascript.audit(artifacts, {computedCache: new Map()});
+    expect(result.details.items[0].signals).toEqual(['String.prototype.repeat']);
+    expect(result.details.items[0].locations).toMatchObject([{line: 1, column: 0}]);
+  });
 });
 
 describe('LegacyJavaScript signals', () => {
   it('expect babel-preset-env = true variant to not have any signals', () => {
-    const signalSummary = require('../../scripts/legacy-javascript/summary-signals.json');
-    const expectedMissingSignals = [
-      'core-js-2-preset-env-esmodules/true',
-      'core-js-3-preset-env-esmodules/true',
-    ];
-    for (const expectedVariant of expectedMissingSignals) {
-      expect(signalSummary.variantsMissingSignals).toContain(expectedVariant);
+    for (const summaryFilename of ['summary-signals.json', 'summary-signals-nomaps.json']) {
+      const signalSummary = require(`../../scripts/legacy-javascript/${summaryFilename}`);
+      const expectedMissingSignals = [
+        'core-js-2-preset-env-esmodules/true',
+        'core-js-3-preset-env-esmodules/true',
+      ];
+      for (const expectedVariant of expectedMissingSignals) {
+        expect(signalSummary.variantsMissingSignals).toContain(expectedVariant);
+      }
     }
   });
 });