zloirock / core-js

Standard Library
MIT License
24.42k stars 1.65k forks source link

[IE11][Since 3.6.2] "SCRIPT5078: Cannot redefine non-configurable property 'find'" #790

Closed erhanalankus closed 3 years ago

erhanalankus commented 4 years ago

Hello,

We updated our packages and noticed that the scripts were not working on IE11.

The error message was "SCRIPT5078: Cannot redefine non-configurable property 'find'".

I tried each version of core-js, the issue appeared when we updated from 3.6.1 to 3.6.2.

This is the list of our dependencies, from package.json:

"dependencies": { "@aspnet/signalr": "^1.1.4", "@babel/runtime": "^7.8.7", "@babel/runtime-corejs3": "^7.8.7", "@glidejs/glide": "^3.4.1", "axios": "^0.18.1", "core-js": "3.6.1", "haptics": "^1.0.0", "iban": "0.0.12", "intersection-observer": "^0.7.0", "jarallax": "^1.12.0", "lodash": "^4.17.15", "mobx": "^5.15.4", "nouislider": "^14.1.1", "nprogress": "^0.2.0", "numeral": "^2.0.6", "perspective.js": "^1.0.0", "qs": "^6.9.1", "quill": "^1.3.7", "redux": "^4.0.5", "redux-thunk": "^2.3.0", "redux-watch": "^1.1.1", "regenerator-runtime": "^0.13.5", "rellax": "^1.12.1", "simple-parallax-js": "^5.3.0", "sweetalert2": "^8.19.0", "tooltip.js": "^1.3.3", "validate.js": "^0.13.1", "vanilla-lazyload": "^12.5.1" }

Thank you for all your work.

slowcheetah commented 4 years ago

Try to update to last version

suspiciousfellow commented 4 years ago

Getting same issue with latest version (albeit includes rather than find)

This appears to be related to two instances of corejs in the page.

aardvarkk commented 4 years ago

I'm also having this problem. No idea how to get around it at this point.

slowcheetah commented 4 years ago

Can you give reproducible example?

gempeler commented 4 years ago

I have the same issue. I switched to version 3.4.0 - this works fine.

Rohit-L commented 4 years ago

Also seeing this on >= 3.6.2 for the "includes" method on IE11, switched to 3.6.1 for now.

aardvarkk commented 4 years ago

@slowcheetah I think I have more insight into this now.

In my case, I'm running a Ruby on Rails app. JavaScript processing is split into two: the asset pipeline and webpack. Our webpack JS relies on our asset pipeline JS executing first. Inside our asset pipeline JS we have an existing polyfill for Array.prototype.find in IE11. I'm not entirely sure on the history of it, but we must have added it to get some of the JS from the asset pipeline working properly. This is the exact code we have:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

If I have a webpack side that runs import 'core-js/stable' and an asset pipeline side that runs that polyfill, we see that error on IE11.

aardvarkk commented 4 years ago

I can also confirm that reverting to 3.6.1 fixes the error.

DanishDeveloper360 commented 4 years ago

I am experiencing Cannot redefine non-configurable property 'includes'.

I have a webpack side that runs import 'core-js/stable', we see that error on IE11.

Reproducible even in core-js version 3.6.1

amok commented 4 years ago

Experiencing the same for a widget. Appears if core-js is included twice. I believe the issue can be considered as an important one. Any news on it?

amok commented 4 years ago

UPD I did not manage to reproduce the bug including core-js twice (even with different or older versions)

Had to apply the following hotfix:

function isBrowserIEVersionBelowEdge() {
  return navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > -1;
}

function overrideObjectDefineProperty() {
  const defineProperty = Object.defineProperty;

  if (!defineProperty) {
    return;
  }

  Object.defineProperty = function (object, propertyName) {
    if (propertyName === 'includes' && Object.getOwnPropertyDescriptor) {
      const propertyDescriptor = Object.getOwnPropertyDescriptor(object, propertyName);

      if (propertyDescriptor && !propertyDescriptor.configurable) {
        // Do not redefine since it's gonna throw;
        return object;
      }
    }

    return defineProperty.apply(this, arguments);
  };
}

function applyWorkaround() {
  if (!isBrowserIEVersionBelowEdge()) {
    return;
  }

  try {
    overrideObjectDefineProperty();
  } catch (error) {
    console.error(error);
  }
}

applyWorkaround();
VsevolodGolovanov commented 4 years ago

Getting this error, because sometimes a polyfill (Array.includes) is already present from another place. Thing is, both core-js polyfills and those other polyfills are defined very globally in two different places, and intersect only in certain conditions. It's very hard for me to get rid of one - both are necessary at different times. I wish core-js wouldn't fail, if another polyfill is already present - in the end it doesn't matter to me, which one is actually active, because both of them implement things to the same spec.

JakeChampion commented 4 years ago

Whichever polyfill is setting Array.prototype.find's descriptor to be non-configurable is incorrect and needs to either be corrected or removed.

Array.prototype.find is created using the abstract spec operation CreateMethodProperty which makes the property configurable.

Object.getOwnPropertyDescriptor(Array.prototype, 'find')
// returns: Object { value: find(), writable: true, enumerable: false, configurable: true }
Miladiir commented 4 years ago

You have to realize that sometimes code runs in an environment that you have absolutely no influence on.

For example, at Inform, we develop extensions for Qlik Sense. Depending on the Qlik Sense Server version, different polyfills are already present. Since we (want to, have to) support a wide range of versions of QS we have to rely on our own polyfills.

The problem presented in this issue is the exact same one we are experiencing right now. Is there some way to catch the polyfill initialization errors?

Is there a reason why one might care about whether or not Array.prototype.find is polyfilled by our core-js version vs. whatever Qlik Sense or -vendor name here- polyfilled with?

JakeChampion commented 4 years ago

You have to realize that sometimes code runs in an environment that you have absolutely no influence on.

I realise this as this project core-js runs in only environments we have no influence on and I also work on https://polyfill.io which runs only in environments I have no influence on.

Is there a reason why one might care about whether or not Array.prototype.find is polyfilled by our core-js version vs. whatever Qlik Sense or -vendor name here- polyfilled with?

There is no reason to care which polyfill is being used if they are all completely compliant with the specification. However this issue is showing that a polyfill being used is not specification compliant because it is marking the method as non-configurable when it is meant to be configurable.

Miladiir commented 4 years ago

Thank you for your swift response. Also my comment sounded pretty harsh, for which I apologize. I am not a native speaker.

There is no reason to care which polyfill is being used if they are all completely compliant with the specification. However this issue is showing that a polyfill being used is not specification compliant because it is marking the method as non-configurable when it is meant to be configurable. Okay, I get that. However, I am still lost as to what we should do in our code and/or our babel + core-js + webpack setup to remedy the issue.

The problematic polyfill is already present in servers, that will probably not get an update to fix that issue within the next year or so. Nothing I can do about it and completely in the hands of the customers. Our code, that injects core-js, must now run on these machines as well as machines that are more up-to-date.

We currently use babel with the following (pretty standard) configuration:

{
  presets: [
      ["@babel/env", {
        useBuiltIns: "usage",
        modules: "commonjs",
        corejs: 3,
      }]
  ]
}

We support old browsers including IE11 and use webpack to bundle. From my understanding our code could not control which polyfills would be imported during runtime, because at the point at which our code execution starts, polyfills would have been already initialized. In our case this means on problematic QS Versions, the error in this issue would be thrown and our code will never run.

So do you, or anyone else know how to fix this? Maybe with core-js-pure?

JakeChampion commented 4 years ago

The problematic polyfill is already present in servers, that will probably not get an update to fix that issue within the next year or so. Nothing I can do about it and completely in the hands of the customers.

I understand that, I would still love to know which package is providing the polyfill so that I can fix the source of the problem whilst also working around the problem from within core-js.

So do you, or anyone else know how to fix this? Maybe with core-js-pure?

I reckon adding a workaround in core-js is okay to do

JakeChampion commented 4 years ago

In the past we can see issues like this one have been closed without any changes being made to core-js. https://github.com/zloirock/core-js/issues/746

Miladiir commented 4 years ago

I understand that, I would still love to know which package is providing the polyfill so that I can fix the source of the problem whilst also working around the problem from within core-js.

I will look into it. I unfortunately do not have access to source code, so I will do what I can.

I reckon adding a workaround in core-js is okay to do

That would be seriously awesome.

In the past we can see issues like this one have been closed without any changes being made to core-js. #746

I saw that aswell. Seems like zloirock changed his mind a couple of times for some reason.

Miladiir commented 4 years ago

I found this:

DXp7: function (e, t) {
    Array.prototype.includes || Object.defineProperty(Array.prototype, 'includes', {
        value: function e(t, n) {
            if (null == this) throw new TypeError('"this" is null or not defined');
            if ('undefined' === typeof n) return -1 !== this.indexOf(t);
            var r = this.slice(n);
            return -1 !== r.indexOf(t)
        }
    })
},

Notice the missing options object. I can unfortunately not identify, where this part of the code comes from. All I can tell is, that the lines above are already executed on the page before my code is run.

Miladiir commented 4 years ago

I just noticed, my colleague is also messaging you on #845. The two issues are the same.

jorgutdev commented 3 years ago

I had the same issue on IE11. Nothing worked until I changed to core-js v2

npm install --save core-js@2

babel.config.js

module.exports = function (api) {
  api.cache(true);

  return {
    presets: [
      ['@babel/preset-env', {
        debug: false,
        corejs: 2,
        targets: {
          browsers: ['ie 11, not dead']
        }
      }]
    ],
    plugins: [
      '@babel/transform-runtime',
      '@babel/plugin-proposal-class-properties'
    ]
  };
};
zloirock commented 3 years ago

It's an issue with an alternative incorrect 3rd party Array#find polyfill which defined as non-configurable and which does not pass core-js feature detection. core-js tries to fix it, but can't delete the previous implementation. It's a bug in this 3rd party polyfill, it's not a core-js issue.