Mobx: SCRIPT5045 error in IE11 in version ^3.1.10

Created on 31 May 2017  Â·  15Comments  Â·  Source: mobxjs/mobx

"SCRIPT5045: Assignment to read-only properties is not allowed in strict mode" is being thrown by Internet Explorer when executing ObservableArray.prototype.findIndex function assignment. Issue occured after updaing to 3.1.10 version of mobx.

Most helpful comment

Submitted an update to MDN to improve the polyfill

All 15 comments

Can you set up a fiddle which reproduces this? Or does https://jsfiddle.net/mweststrate/wv3yopo0/ already reproduce this during load?

I can confirm this issue, will try to supply reproducing example in eight hours or so. Sadly, your fiddle has another error in IE — , so it's hard to say whether it reproduces or not.

Well, this situation just became kinda awkward. As it turns out, I've polyfilled Array.prototype.find (it's still missing in IE). And, obviously, ObservableArray is derived from Array, so IE in strict mode cannot redefine polyfilled prototype function. For me the problem was solved in a hacky way by polyfilling find after mobx loading, but dealing with IE always ends up in some nasty hacks. @domos4 It seems like https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex is not supported in IE either, can you check your production bundle, do you have any polyfills? Can you resort to my solution?

@domos4 I failed to reproduce the issue. Probably your problem is the same as @radiosterne. If that does not solve the issue, please re-open the issue, _including_ a reproduction.

I am facing the same problem now and I use the polyfill findIndex for IE 11.
@radiosterne from what you explain if I load this polyfill after mobx has finished loading, I should be able to fix the issue. Please confirm if my understanding is correct

Additional workaround is to change polyfill to define property as writable: true.

I have an example from the wild! It is strange because we have been using mobx on many pages of our product and it is only a certain path that is triggering the error. On other routes that are also using mobx we have had no problems.

An example: https://mycujoo.tv/mongolia-football-federation?id=13049

SCRIPT5045: Assignment to read-only properties is not allowed in strict mode

And we are using

"mobx": "3.1.3",
"mobx-react": "^4.2.1",

We are also using the polyfill.io service (https://cdn.polyfill.io/v2/polyfill.min.js?features=Array.prototype.includes,Set,Object.assign,Intl.~locale.en&excludes=Object.defineProperty&unknown=polyfill&flags=gated) and also we are including the babel-polyfill ^6.16.0.

FWIW I have a reproduction here: http://viridian-tulip.glitch.me/

All it takes is the MDN Array.prototype.find polyfill copied right off their webpage to cause the error.

I have to work around this in the web build of one my libraries which depends on mobx. I haven't updated in a while (since I think 3.1) but came back to this issue after updating to 3.6. It used to be the case that changing the order of mobx and babel-polyfill in my build fixed the problem, but that stopped working.

I work around it for now by including the mobx umd build unminified, and wrapping the problematic calls in a try / catch; this doesn't feel like the true solution though - i've got to be doing something wrong.

@finneganh the problem is that the polyfill is not correct. The find method it introduces is non-configurable, will it should be. Somehow only IE seems to blow up on that (probably because it only gets polyfilled there :-P).

> Object.getOwnPropertyDescriptor(Array.prototype, "find")
{value: <function>, writable: true, enumerable: false, configurable: true}

So you should als set configurable and writeable in the Object.defineProperty, as the default for all of these 3 is false, which is not correct compared to environments that provide find natively.

In other words, change the polyfill to: Object.defineProperty(Array.prototype, 'find', { configurable:true, writable:true, value: ...} should fix it.

I am not sure what core-js does. But you can simply check that by inspecting Object.getOwnPropertyDescriptor(Array.prototype, "find") after core-js has been loaded. It should yield the same result as above

@soederpop what are you using to polyfill Array.prototype.find? It is probably the same issue.

Submitted an update to MDN to improve the polyfill

Checked some packages. core-js has a correct polyfill, however, the firebase polyfill is broken: https://github.com/firebase/firebase-js-sdk/blob/master/packages/polyfill/src/shims/Array.ts

I see the same issue in Chrome 41 (which used by Google for crawling/indexing atm):

Uncaught TypeError: Cannot assign to read only property 'find' of [object Object]

Did some investigation with @mweststrate and figured out that issue appeared because of broken polyfill was used by firebase-js-sdk. So if you use Firebase, that's definitely could be because of that.

Current workaround I came with is to add correct .find and .findIndex polyfills before you include Firebase. Code is below:

'use strict';
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    value: function(predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      let o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      let len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      let thisArg = arguments[1];

      // 5. Let k be 0.
      let k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        let kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return undefined.
      return undefined;
    },
    configurable: true,
    writable: true
  });
}

if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, 'findIndex', {
    value: function(predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      let o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      let len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      let thisArg = arguments[1];

      // 5. Let k be 0.
      let k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return k.
        let kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return k;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return -1.
      return -1;
    },
    configurable: true,
    writable: true
  });
}

NOTE: code above is from MDN, BUT MDN's code has missing configurable: true, writable: true for .findIndex polyfill.

UPD: corrected polyfill in MDN findIndex page.

Closing as issue has been resolved; and is not caused by MobX but by third party polyfills

Was this page helpful?
0 / 5 - 0 ratings