Subscribe on changes!

I cannot use Libraries using read-only variables in the core without `markRaw`

avatar
Jan 27th 2022

Version

3.2.29

Reproduction link

sfc.vuejs.org/

Steps to reproduce

  • Import a library that uses read-only variable in the core
  • An error occurs during startup

The minimal reproduction mocks a library that is using read-only variables.

Note that in a real-world use case, reactive is not explicitly called. For example, in this codesandbox showcasing the issue with the bpmn-js library: https://codesandbox.io/s/epic-swartz-zttbr?file=/src/App.vue:1854-1895

What is expected?

  • I can use JS libraries out of the box

What is actually happening?

  • an Error is thrown
  • I have to use markRaw

Maybe it is possible to check if an Object is writable before proxying it. I sketched a solution below:

var obj = {};
Object.defineProperty(obj, 'foobar', {
  value: {}
});

// Proxy Config /////////
var proxy = new Proxy(obj, {
  get(target, property) {
    var writable = (Object.getOwnPropertyDescriptor(obj, property) || {}).writable;
    if (writable) {
      return new Proxy(target[property], {});
    }
    else {
      // would throw if we proxy read-only values
      return target[property];
    }
  }
});

console.log(proxy.foobar);
avatar
Jan 28th 2022

I would say using markRaw() is expected: https://v3.vuejs.org/api/basic-reactivity.html#markraw

avatar
Jan 31st 2022

If it is expected, would it be possible to throw a more expressive error message? Currently, users just get a rather cryptic property 'foo' is a read-only and non-configurable. They then assume it is a problem with the library, as the Error is thrown from there. Example.

I would expect a descriptive error message that makes possible fixes more clearer. This would improve the experience for both the library users and devs.

avatar
Feb 3rd 2022

Checking for potential readonly properties requires calling Object.getOwnPropertyDescriptor on every Proxy trap call, which I suspect is going to be too expensive even in dev mode.

In general, you should avoid making complex 3rd party objects reactive - i.e. don't return it from data() - there's no point in doing so. Just set it on this in created().