vue-email-editor icon indicating copy to clipboard operation
vue-email-editor copied to clipboard

Latest update 2.1.2 brakes the editor

Open therealcljohn opened this issue 1 year ago • 5 comments

The latest update to version 2.1.2 brakes the editor (2.1.1 still works). The following error occurs:

runtime-core.esm-bundler.js:408 Uncaught DOMException: Failed to execute 'postMessage' on 'Window': #<Object> could not be cloned.
    at https://editor.unlayer.com/embed.js?2:1:15159
    at Proxy.forEach (<anonymous>)
    at Proxy.value (https://editor.unlayer.com/embed.js?2:1:15081)
    at Proxy.value (https://editor.unlayer.com/embed.js?2:1:13882)
    at Proxy.value (https://editor.unlayer.com/embed.js?2:1:13990)
    at Proxy.value (https://editor.unlayer.com/embed.js?2:1:29029)
    at Proxy.saveDesign (webpack-internal:///./node_modules/ts-loader/index.js??clonedRuleSet-40.use…s??ruleSet[0].use[0]!./src/views/Example.vue?vue&type=script&lang=ts:41:39)
    at onClick._cache.<computed>._cache.<computed> (webpack-internal:///./node_modules/ts-loader/index.js??clonedRuleSet-40.use…use[0]!./src/views/Example.vue?vue&type=template&id=1a31a320&ts=true:20:63)
    at callWithErrorHandling (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:338:19)
    at callWithAsyncErrorHandling (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:345:17)

This can be reproduced using the example editor from this repository and doing the following steps:

npm ci
npm run serve

Then open the application in the browser and hit the Save Design button. Then you will see this:

Bildschirmfoto_20241024_171238

The error occurs when using the exportHtml function of the editor.

therealcljohn avatar Oct 24 '24 15:10 therealcljohn

Thank you for bringing this up, can you please confirm if 2.1.3 fixes this issue

omerzahidbajwa avatar Oct 24 '24 17:10 omerzahidbajwa

Thank you for bringing this up, can you please confirm if 2.1.3 fixes this issue

2.1.3 it's not working for me, seems like it's missing something:

[vite] Internal server error: Failed to resolve entry for package "vue-email-editor". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "vue-email-editor". The package may have incorrect main/module/exports specified in its package.json.

2.1.1 works but this feature stopped working:

const editorReady = async () => {
  emailEditor.value.editor.registerCallback(
    'selectImage',
    async function (data: any, done: any) {
      console.log('SelectImage triggered ', data)
      await uploadImage().then((img) => {
        done({ url: img });
      });
    }
  );
};

Even though the documentation still seems to be the same.

NaturalDevCR avatar Oct 26 '24 02:10 NaturalDevCR

This should be fixed now (2.1.4), there was indeed an issue with the release of 2.1.3

omerzahidbajwa avatar Oct 26 '24 05:10 omerzahidbajwa

Still getting errors in 2.1.4. Here is my take, albeit perhaps far fetched

image

It appears this has not been fixed in 2.1.4 @omerzahidbajwa . I have a hunch that perhaps the problem isn't originating directly from vue-email-editor, but that doesn't mean that perhaps a solution couldn't be discovered for it via the vue-email-editor.

I think instead it is originating from the embed.js which has multiple uses of postMessage within it. This script is imported within the loadScript.ts (https://github.com/unlayer/vue-email-editor/blob/master/src/components/loadScript.ts#L1).

I can see why shallowRef might be a solution for some but I think it depends on the level of integration added within individual's components.

I had a read through BroadcastChannel's documentation (https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#message) particularly around message and how it works. For those not wishing to click the link and read this themselves, it states:

Data to be dispatched to the other window. The data is serialized using the structured clone algorithm. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.

Upon reading the Structured Clone Algorithm link, there is a big section about what doesn't work with this (https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#things_that_dont_work_with_structured_clone)

  • Function objects cannot be duplicated by the structured clone algorithm; attempting to throws a DataCloneError exception.
  • Cloning DOM nodes likewise throws a DataCloneError exception.
  • Certain object properties are not preserved:
  • The lastIndex property of RegExp objects is not preserved.
  • Property descriptors, setters, getters, and similar metadata-like features are not duplicated. For example, if an object is marked readonly with a property descriptor, it will be read/write in the duplicate, since that's the default.
  • The prototype chain is not walked or duplicated.
  • Class private properties are not duplicated. (Although private properties of built-in types may.)

When I look at where these postMessage errors are originating from within our own code, they all stem from us calling functions from the editor instance, for example this.editor?.setMergeTags() immediately throws this postMessage error. I'm curious if this problem is something in relation to Function objects not being duplicated by the structured clone algorithm and thus throwing these errors.

Ideally a solution could be found via the component and I'm not entirely sure this is where the problem is, as, from what I can see on that document, this function cloning issue isn't new so I'd of thought this might have raised it's head prior to Vue 3 upgrades..

Our application uses Broadcast Channel's too and we also faced this issue when upgrading to Vue 3, it seemed to no longer like passing key values that were associated with a data variable, for example:

Options API Component

import { defaultVariableData } from '@location/location2/location3'

// ...

data() {
   myVar: defaultVariableData,
   broadcastChannel: new BroadcastChannel('my-channel-name')
},
methods: {
  myMethod () {
     // This will trigger the same postMessage warning, presuming it is due to how Vue fetches this data.
     this.broadcastChannel.postMessage({
       myKey: this.myVar
     })
  }
}

As opposed to shallowRef on the myVar - importing toRaw from vue and wrapping it like so fixes the error:

import { toRaw } from 'vue'

// ....

myMethod () {
     // This fixes the issue.
     this.broadcastChannel.postMessage({
       myKey: toRaw(this.myVar)
     })
  }

Our problem here is, we don't have access other than a minified file to where the postMessage is called from.

PF-Liam avatar Dec 18 '24 09:12 PF-Liam

Update on @PF-Liam 's issues: we manage to solve our issues with DataCloneErrors by doing two things:

  • We were keeping a reference to the Editor in data (in Options API). This needed to be in a shallowRef, which we created via setup.
  • One remaining error was from calling loadDesign with a design object which was evidently a reactive Proxy itself. We needed to call toRaw on this before passing it to the editor.

Ideally I would say the Vue library should provide some kind of wrapper for the Editor class which calls toRaw on any data being passed to Unlayer via BroadcastChannels. As a user, trying to keep track of which pieces of data might be proxied and where this might cause an error can be quite a challenge.

Failing this, some guidance in the documentation about this error could really help.

baffalop avatar Dec 19 '24 10:12 baffalop