GoogleChrome/lighthouse

Some JS polyfills should be added to the list of legacy JS

zloirock opened this issue · 7 comments

Continuation of #13439.

Let's check what core-js modules are not required in engines with ES modules support:

const compat = require('core-js-compat');
compat({ targets: { esmodules: true }, inverse: true }).list;

=>

[
  "es.symbol",
  "es.symbol.has-instance",
  "es.symbol.is-concat-spreadable",
  "es.symbol.iterator",
  "es.symbol.species",
  "es.symbol.to-primitive",
  "es.symbol.to-string-tag",
  "es.symbol.unscopables",
  "es.error.to-string",
  "es.array.concat",
  "es.array.copy-within",
  "es.array.every",
  "es.array.fill",
  "es.array.filter",
  "es.array.find",
  "es.array.find-index",
  "es.array.for-each",
  "es.array.from",
  "es.array.index-of",
  "es.array.is-array",
  "es.array.join",
  "es.array.last-index-of",
  "es.array.map",
  "es.array.of",
  "es.array.slice",
  "es.array.some",
  "es.array.species",
  "es.array.splice",
  "es.array-buffer.is-view",
  "es.data-view",
  "es.date.get-year",
  "es.date.now",
  "es.date.set-year",
  "es.date.to-gmt-string",
  "es.date.to-iso-string",
  "es.date.to-json",
  "es.date.to-primitive",
  "es.date.to-string",
  "es.escape",
  "es.function.bind",
  "es.function.has-instance",
  "es.function.name",
  "es.json.to-string-tag",
  "es.map",
  "es.math.acosh",
  "es.math.asinh",
  "es.math.atanh",
  "es.math.cbrt",
  "es.math.clz32",
  "es.math.cosh",
  "es.math.expm1",
  "es.math.fround",
  "es.math.imul",
  "es.math.log10",
  "es.math.log1p",
  "es.math.log2",
  "es.math.sign",
  "es.math.sinh",
  "es.math.tanh",
  "es.math.to-string-tag",
  "es.math.trunc",
  "es.number.constructor",
  "es.number.epsilon",
  "es.number.is-finite",
  "es.number.is-integer",
  "es.number.is-nan",
  "es.number.is-safe-integer",
  "es.number.max-safe-integer",
  "es.number.min-safe-integer",
  "es.number.to-precision",
  "es.object.create",
  "es.object.define-properties",
  "es.object.define-property",
  "es.object.entries",
  "es.object.freeze",
  "es.object.get-own-property-descriptor",
  "es.object.get-own-property-descriptors",
  "es.object.get-own-property-names",
  "es.object.get-prototype-of",
  "es.object.is",
  "es.object.is-extensible",
  "es.object.is-frozen",
  "es.object.is-sealed",
  "es.object.keys",
  "es.object.prevent-extensions",
  "es.object.seal",
  "es.object.set-prototype-of",
  "es.object.to-string",
  "es.object.values",
  "es.reflect.apply",
  "es.reflect.construct",
  "es.reflect.define-property",
  "es.reflect.delete-property",
  "es.reflect.get",
  "es.reflect.get-own-property-descriptor",
  "es.reflect.get-prototype-of",
  "es.reflect.has",
  "es.reflect.is-extensible",
  "es.reflect.own-keys",
  "es.reflect.prevent-extensions",
  "es.reflect.set-prototype-of",
  "es.regexp.sticky",
  "es.set",
  "es.string.code-point-at",
  "es.string.from-code-point",
  "es.string.iterator",
  "es.string.raw",
  "es.string.repeat",
  "es.string.substr",
  "es.string.anchor",
  "es.string.big",
  "es.string.blink",
  "es.string.bold",
  "es.string.fixed",
  "es.string.fontcolor",
  "es.string.fontsize",
  "es.string.italics",
  "es.string.link",
  "es.string.small",
  "es.string.strike",
  "es.string.sub",
  "es.string.sup",
  "es.typed-array.copy-within",
  "es.typed-array.every",
  "es.typed-array.filter",
  "es.typed-array.find",
  "es.typed-array.find-index",
  "es.typed-array.for-each",
  "es.typed-array.includes",
  "es.typed-array.index-of",
  "es.typed-array.iterator",
  "es.typed-array.join",
  "es.typed-array.last-index-of",
  "es.typed-array.map",
  "es.typed-array.reduce",
  "es.typed-array.reduce-right",
  "es.typed-array.reverse",
  "es.typed-array.slice",
  "es.typed-array.some",
  "es.typed-array.subarray",
  "es.typed-array.to-string",
  "es.unescape",
  "es.weak-map",
  "es.weak-set",
  "web.dom-collections.for-each",
  "web.timers"
]

In addition to currently detected features, it's:

Array.prototype.concat
Array.prototype.copyWithin
Array.prototype.every
Array.prototype.indexOf
Array.prototype.join
Array.prototype.lastIndexOf
Array.prototype.slice
Array.prototype.splice
ArrayBuffer.isView
Date.prototype.getYear
Date.prototype.setYear
Date.prototype.toGMTString
Date.prototype.toPrimitive
Date.prototype.toString
Function.prototype.bind
Math.acosh
Math.asinh
Math.atanh
Math.cbrt
Math.clz32
Math.cosh
Math.expm1
Math.fround
Math.imul
Math.log10
Math.log1p
Math.log2
Math.sign
Math.sinh
Math.tanh
Math.trunc
Number.EPSILON
Number.isFinite
Number.isNaN
Number.MAX_SAFE_INTEGER
Number.MIN_SAFE_INTEGER
Number.prototype.toPrecision
Object.create
Object.getOwnPropertyDescriptor
Object.is
Object.prototype.toString
String.prototype.substr
String.prototype.anchor
String.prototype.big
String.prototype.blink
String.prototype.bold
String.prototype.fixed
String.prototype.fontcolor
String.prototype.fontsize
String.prototype.italics
String.prototype.link
String.prototype.small
String.prototype.strike
String.prototype.sub
String.prototype.sup

DataView
Map
Number
Set
Symbol
WeakMap
WeakSet
escape
unescape
setTimeout
setInterval

It should be added to this list.

Thanks for the close attention in this audit. It took me awhile to recall, but we excluded many of these for a reason: #10937 . I hadn't heard of core-js-compat until now, I'll have to go through the reasoning for excluding some of these and see if it still holds.

BTW, we have a test harness for verifying this stuff: yarn test-legacy-javascript

It creates various bundles using core-js@2 and 3 with different options, and snapshots the signals found. The expectation is that we find no signals when bundling withh latest core-js version + esmodules: true. I see we are a few big updates behind (

for (const coreJsVersion of ['2.6.12', '3.9.1']) {
) so I'm updating that now.

Seems the only signal we giving a false-positive for at the moment is es6.object.get-own-property-names so I am removing that. It makes me wonder why the Array prototype methods you pointed out in #13439 are not being found in the esmodules: true variant. I'd like to understand that first before removing those signals too.

Ah, I updated babel too and I see Array.prototype.reduceRight, Array.prototype.reduce, Number.parseInt in the false positives. OK.

Seems the only signal we giving a false-positive for at the moment is es6.object.get-own-property-names so I am removing that.

That's strange since in the test from the head of this thread you can find es6.object.get-own-property-names in the output, so it should not be polyfilled with esmodules: true.

I'll take a look at test-legacy-javascript tomorrow.

I hadn't heard of core-js-compat until now, I'll have to go through the reasoning for excluding some of these and see if it still holds.

core-js-compat is the data source that's used for automatic polyfilling in babel and other tools, other data sets are not oriented to polyfilling ES and miss too many cases, so it's strange to orient to something else.

es6.object.get-own-property-names

Obsolete preset-env core-js: 2 mode uses compat-table as a data source, however even here Object.getOwnPropertyNames should not be polyfilled with esmodules: true target.

It does not look fixed,

return [
['Array.prototype.fill', 'es6.array.fill'],
['Array.prototype.filter', 'es6.array.filter'],
['Array.prototype.find', 'es6.array.find'],
['Array.prototype.findIndex', 'es6.array.find-index'],
['Array.prototype.forEach', 'es6.array.for-each'],
['Array.from', 'es6.array.from'],
['Array.isArray', 'es6.array.is-array'],
['Array.prototype.map', 'es6.array.map'],
['Array.of', 'es6.array.of'],
['Array.prototype.some', 'es6.array.some'],
['Date.now', 'es6.date.now'],
['Date.prototype.toISOString', 'es6.date.to-iso-string'],
['Date.prototype.toJSON', 'es6.date.to-json'],
['Date.prototype.toString', 'es6.date.to-string'],
['Function.prototype.name', 'es6.function.name'],
['Number.isInteger', 'es6.number.is-integer'],
['Number.isSafeInteger', 'es6.number.is-safe-integer'],
['Object.defineProperties', 'es6.object.define-properties'],
['Object.defineProperty', 'es6.object.define-property'],
['Object.freeze', 'es6.object.freeze'],
['Object.getPrototypeOf', 'es6.object.get-prototype-of'],
['Object.isExtensible', 'es6.object.is-extensible'],
['Object.isFrozen', 'es6.object.is-frozen'],
['Object.isSealed', 'es6.object.is-sealed'],
['Object.keys', 'es6.object.keys'],
['Object.preventExtensions', 'es6.object.prevent-extensions'],
['Object.seal', 'es6.object.seal'],
['Object.setPrototypeOf', 'es6.object.set-prototype-of'],
['Reflect.apply', 'es6.reflect.apply'],
['Reflect.construct', 'es6.reflect.construct'],
['Reflect.defineProperty', 'es6.reflect.define-property'],
['Reflect.deleteProperty', 'es6.reflect.delete-property'],
['Reflect.get', 'es6.reflect.get'],
['Reflect.getOwnPropertyDescriptor', 'es6.reflect.get-own-property-descriptor'],
['Reflect.getPrototypeOf', 'es6.reflect.get-prototype-of'],
['Reflect.has', 'es6.reflect.has'],
['Reflect.isExtensible', 'es6.reflect.is-extensible'],
['Reflect.ownKeys', 'es6.reflect.own-keys'],
['Reflect.preventExtensions', 'es6.reflect.prevent-extensions'],
['Reflect.setPrototypeOf', 'es6.reflect.set-prototype-of'],
['String.prototype.codePointAt', 'es6.string.code-point-at'],
['String.fromCodePoint', 'es6.string.from-code-point'],
['String.raw', 'es6.string.raw'],
['String.prototype.repeat', 'es6.string.repeat'],
['Array.prototype.includes', 'es7.array.includes'],
['Object.entries', 'es7.object.entries'],
['Object.getOwnPropertyDescriptors', 'es7.object.get-own-property-descriptors'],
['Object.values', 'es7.object.values'],
].map(data => {