Web Component breaks on Vue when Object.defineProperties (Cannot redefine property: __vnode)

Hi there. I’ve got a web component (custom element) that works fine in HTML but breaks when used in Vue (Cannot redefine property: __vnode).

This is a native web component that should seamlessly work on Vue

The web component uses Object.defineProperties to change the setter of every property, basically adding a listener to changes and reacting to them.
A simplified version:

propertyObserver() {
    const properties = Object.getOwnPropertyDescriptors(this);
    // defines the new object properties, including the getters and setters
    for (let key in properties) {
      const descriptor = properties[key];
      this.#propertyData[key] = descriptor.value;
      descriptor.get = () => this.#propertyData[key];
      descriptor.set = (newValue) => {
        if (newValue !== this.#propertyData[key]) {
          console.log('property changed', key);
          // do something
      delete descriptor.value;
      delete descriptor.writable;
    Object.defineProperties(this, properties);

When used in a Vue component, such as

<script setup>
import "./itm-button.js"
 <h2>See browser's console</h2>

It get

Uncaught TypeError: Cannot redefine property: __vnode
    at Function.defineProperties (<anonymous>)
    at ITMButton.propertyObserver (itm-button.js?t=1669010473886:37:12)
    at ITMButton.connectedCallback (itm-button.js?t=1669010473886:65:10)

Without the propertyObserver() function, the component loads, but of course, it doesn’t behave as expected.

Here’s a Stackblitz implementation that reproduces the error.

As a side note, I want to keep using native components, I know Vue can build custom elements, but this is not the case.

As the error says, you’re redefining a critical property within Vue. Vue relies on some internal properties for its reactivity - these are intended to be private (as in not documented in the API) as denoted by the __. So, basically, don’t do that. Do you really need to observe every property? I’d be more selective about this to avoid collisions such as this and with any other framework/plugin/lib.

Thanks, James.
The idea was to get less declarative, but I didn’t think Vue would complain. I have tried with Lit instead of me doing the reactiveness I needed, and it worked. Somehow Google programmers seem better than me :wink: