Subscribe on changes!

Vue 3 does not work well with iframes

avatar
Oct 28th 2020

Version

3.0.2

Reproduction link

https://codesandbox.io/s/unruffled-northcutt-cmndl?file=/public/iframe.html

Steps to reproduce

  1. Have an app that shows an iframe
  2. Create a teleport that will place it's content inside the iframe
  3. Add an event like click to the teleport content
  4. Immediately after the irame loads, try to click on the teleported element

What is expected?

The click event should fire immediatelly

What is actually happening?

The click is not working until the event.timestamp ( that is generated by the iframe dom ) gets higher than the attached timestamp from the parent window.


More info can be found here ( https://github.com/vuejs/vue-next/blob/ea5f92ae051be511558569eaf4c2afa2839c3e4d/packages/runtime-dom/src/modules/events.ts#L114 here, inside the iframe the event.timeStamp which is calculated based on the iframe timestamp is lower than the initial invoker.attached = getNow() that is calculated based on the parent frame ). Due to this, events are not firing for the time difference it takes the iframe to load

avatar
Nov 21st 2020

I'm in a similar boat, not sure how much it's related to OP but it sounds very similar. I've a Vue.js app with an iframe, which loads a different Vue.js app. Sometimes, click events weren't registering in the nested app, commenting out the line highlighted in OP helped. It's weird because it didn't happen every time and both machines are running the same version of browser.

avatar
Dec 2nd 2020

From what you experience, this is the same issue

avatar
Dec 2nd 2020

@yyx990803 Looking at the source code, I noticed this comment accompanied the "fix" that introduced the problem above:

        // async edge case #6566: inner click event triggers patch, event handler
        // attached to outer element during patch, and triggered again. This
        // happens because browsers fire microtask ticks between event propagation.
        // the solution is simple: we save the timestamp when a handler is attached,
        // and the handler would only fire if the event passed to it was fired
        // AFTER it was attached.

I have made some tests using the reproduction template provided in the initial ticket ( https://github.com/vuejs/vue/issues/6566 ) with Vue 3 and it seems that the problem mentioned there is not reproducing anymore if I comment out the timestamp check.

Are there other issues that involved that fix? If there aren't, I would like to make a pull request removing the timestamp check.

avatar
Mar 23rd 2021

I have the same problem in 3.0.7. Is there a solution now?the reproduce

avatar
Mar 25th 2021

I have the same problem in 3.0.7. Is there a solution now?the reproduce

raise by the iframe's event.timeStamp. need to wait until the iframe's creation time longer than clickEvent's creation time.

avatar
Mar 29th 2021

I have the same problem in 3.0.7. Is there a solution now?the reproduce

raise by the iframe's event.timeStamp. need to wait until the iframe's creation time longer than clickEvent's creation time.

It's not a solution.🙁

avatar
Apr 30th 2021

Is there any solution to fix this problem yet? Every time, I mounted an iframe without reloading the page, @click handler of element inside iframe won't work anymore

avatar
Apr 30th 2021

As indicated by the open issue, there's no solution yet.

avatar
Apr 30th 2021

The "solution" we are using in production is to manually modify a vue file and disable this ( runtime-dom.esm-bundler.js in our case ), however, I do not recommend doing so as other problems may appear.

The changes we've made: https://gist.github.com/zauan/a3488a9feb799242df607c983de9c5b7

We have this modification in a live product ( zionbuilder.io ) and didn't encounter any side effects so far. I also tested the initial bug that introduced this modification and I cannot reproduce it in Vue 3 ( with the timestamp check disabled ), so, I am not sure if the initial problem is still valid in Vue 3.

avatar
Apr 30th 2021

The "solution" we are using in production is to manually modify a vue file and disable this ( runtime-dom.esm-bundler.js in our case ), however, I do not recommend doing so as other problems may appear.

The changes we've made: https://gist.github.com/zauan/a3488a9feb799242df607c983de9c5b7

We have this modification in a live product ( zionbuilder.io ) and didn't encounter any side effects so far. I also tested the initial bug that introduced this modification and I cannot reproduce it in Vue 3 ( with the timestamp check disabled ), so, I am not sure if the initial problem is still valid in Vue 3.

Thank you so much, it was working great, I will try with a new fork 👍

avatar
May 1st 2021

I also tested the initial bug that introduced this modification and I cannot reproduce it in Vue 3 ( with the timestamp check disabled ), so, I am not sure if the initial problem is still valid in Vue 3.

@zauan Here's a demo of the behaviour this check is meant to protect against, simulated with a custom directive (which leaves event handling to your vanilla JS adn thus doesn't contain this check unless added manually:

https://jsfiddle.net/Linusborg/tc1aksvx/

It really is an edge case so things could seem to be working fine for 99.9% of the time with your change in place.

But you could still be right theoretically that the problem doesn't persist with actual v-on events with your modification, haven't had the time to properly test this (optimally across all supported browsers).

avatar
Jun 17th 2021

The workaround to this problem is to register all events in onMounted() using vanilla events. This will bypass the timestamp restriction.

<template>
    <div ref="mydiv"></div>
</template>
<script>
export default {
    setup() {
        const mydiv = ref(null);
        
        onMounted(() => {
            mydiv.value.addEventListener('click', handler);
        });

        onBeforeUnmount(() => {
            mydiv.value.removeEventListener('click', handler);
        });
        
        function handler(event) {
            // ...
        }
        
        return {
            mydiv,
        };
    }
};
</script>
avatar
Jun 17th 2021

Yes, this works on smaller projects, however, this cannot be implemented in larger projects like Zion Builder as it increase the code base and there are many places were events are used. Also, can you please also add the removeEventListener on the 'beforeUnmount' hook to your code so that the event gets removed when the component gets unmounted ( in case someone wants to use you workaround and just copies and pastes the code )

avatar
Jun 18th 2021

Sure, I edited the code.

avatar
Jun 25th 2021

This issue is a nightmare for big projects. Adding events manually doesn't work for elements with v-if conditions. I hope this bug will be fixed soon.

avatar
Oct 7th 2021

I confirm that the problem is still here, is there any update on that?

avatar
Oct 8th 2021

For information, this is how we temporaly fix it for our usecase (App which load components inside iframe)

iframe.onload = () => { performance.now = iframe.contentWindow.performance.now }

Tested only on Chrome, this is a way to resynchronise the timestamps used by Vue

avatar
Nov 30th 2021

For anyone else attempting @zauan's fix in Vite, here's what I needed to do-

  1. Update /node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js as per his gist file
  2. Clear out all files from /node_modules/.vite
  3. npm run dev
avatar
Jan 6th 2022

I am also encountering this issue when mounting a component into an empty iframe. The first click events are ignored. It can last a few seconds before click events are finally emitted.

Since the time check fix concerns only rare edge cases and introduces bugs in other cases, it might be interesting to allow disabling this check, either via a global application config, or locally per component (and its children).

avatar
Feb 23rd 2022

FYI, I am working on a solution to allow opting out of the timestamp check. I hope to be able to submit a pull request very soon.

avatar
Jun 16th 2022
avatar
Aug 19th 2022

Really struggling with this one. None of the workarounds above seem to work reliably and @semiaddict 's pull request has been sitting there unmerged for over 6 months.

Is there any updates?

avatar
Aug 20th 2022

@Hyperblaster this was the only thing that worked for me.

    /*
    * This fixes the current issue with event timestamps when running vue in a window or iframe.
    * */
    let ua = window.navigator.userAgent;
    Object.defineProperty(window.navigator, 'userAgent', {
        get: () => {
            let s = new String(ua);
            s.match = function (re) {
                // only care about this particualr match call.
                if (re.toString() === '/firefox\\/(\\d+)/i') {
                    return [, 53];
                }
                return ua.match(re);
            };
            return s;
        },
    });

I can't remember who posted it originally, but it was on another ticket on this repo.

Edit: Credit to @lidlanca for this solution from https://github.com/vuejs/core/issues/3933#issuecomment-1157259673

avatar
Aug 20th 2022

I wouldn't recommend overriding the userAgent as this can have side effects within and outside of Vue.

I've personally been patching Vue 3 with the changes in my pull request using patch-package without issues.

I just hope someone in the Vue team will get the time to look into the pull request soon.

avatar
Aug 20th 2022

@LinusBorg, @yyx990803,

Any chance of getting the pull request reviewed? I'm totally open on working on a different solution if for any reason the one proposed in the pull request doesn't quite fit the Vue coding practices. Thanks in advance.

avatar
Aug 21st 2022

@semiaddict @Kyon147 the source of this snippet is from here https://github.com/vuejs/core/issues/3933#issuecomment-1157259673

and it doesn't override the user-agent, it actually overrides the match() call of the userAgent to minimize impact, and target the check vue does.

avatar
Aug 21st 2022

@lidlanca thanks so much! This helped me solve my issue. Adding the script into the head (before vue is initialised) seemed to do the trick. I tried all kinds of things in onMounted hooks and nothing seemed to work.

Hopefully this can be merged and fixed in core soon

avatar
Feb 20th 2023

Has anybody come across this issue with Vue 3 using the Options API? Any idea if it's been resolved yet at all?

avatar
Mar 17th 2023

+1 @miainchambers

We're about to starting building a Vue application for a client but have been informed that it may need to be placed inside an iframe for 3rd party sites using the app; what problems do we need to be aware of with this in 2023?

avatar
Mar 17th 2023

@nicholasfishjgm I haven't yet deployed my Vue3 Options API application yet, it's going to sit in an iframe on a client's Wordpress site, so I'll let you know any issues/solutions I have.