Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

template refs on suspended components expose component instance early, before it has been resolved or properties been exposed. #7346

Closed
SimmeNilsson opened this issue Dec 14, 2022 · 11 comments

Comments

@SimmeNilsson
Copy link

Vue version

3.2.45

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-a4rmmb?file=src%2FApp.vue,src%2Fcomponents%2FHelloWorld.vue,package.json,package-lock.json&terminal=dev

Steps to reproduce

Run sample
It uses watch on a component ref to know when there is something to act on.
When the component ref is set we try to call a method on that child component.
However, in 3.2.45 something changed and if the child component is async we can't see the method.

3.2.44 version (working as intended)

3.2.45 version (example breaks because method isn't exposed)

What is expected?

Receiving the child component back in the component ref and being able to see and call exposed methods on it.

What is actually happening?

The object returned doesn't have the exposed method available.

System Info

No response

Any additional comments?

We have a microfrontend that in some cases need to be able to call methods on "top-level" components from outside Vue.

Might be a better way to do it than this example (would be happy to be pointed in a good direction), however it did work prior to 3.2.45.

@edison1105
Copy link
Member

as workaround

// Move this to the front of top level await
defineExpose({
  callMe,
});
  
// Make async
await new Promise((resolve) => setTimeout(resolve, 1));

@edison1105 edison1105 added 🐞 bug Something isn't working and removed 🐞 bug Something isn't working labels Dec 15, 2022
@edison1105
Copy link
Member

edison1105 commented Dec 15, 2022

duplicate of #4930
In fact, version 3.2.45 will also have problems with production.

@SimmeNilsson
Copy link
Author

as workaround

// Move this to the front of top level await
defineExpose({
  callMe,
});
  
// Make async
await new Promise((resolve) => setTimeout(resolve, 1));

That works, but would require all teams to make changes and remember the order.
Is there no way to work around it from outside the component?
Or will there be a fix and we just have to postpone upgrading?

@edison1105
Copy link
Member

@SimmeNilsson this PR #4951 will fix it.

@LinusBorg
Copy link
Member

@edison1105 #4951 was too outdated, author just closed it. I'll reopen this issue here until we have a fresh fix. Also, since it works in 3.2.44, it must be something that changed in the meantime, right?

@LinusBorg LinusBorg reopened this Dec 15, 2022
@edison1105
Copy link
Member

it must be something that changed in the meantime, right?

@LinusBorg
Yes, and is not working all the time in reproduction mode.

@LinusBorg
Copy link
Member

Ah, got it. in 3.2.45, we closed a few loopholes in the difference between development and production behaviour of compiled script-setup components.

One of these "loopholes" made the code in this example work in development with 3.2.44. And as you said, it never worked in production in either version.

That's because the ref is being set before instance.exposed is being set. The ref is set when the async component is being mounted by Suspense into an inactive side branch, where it stays until it has resolved. at that point, exposed() hasn't been called yet.

Now I see two possible ways around that:

  1. The ref should be set later: We set the ref only after the async component has resolved.
  2. The ref should still be set as early as it is now, but the expose proxy should be properly provided, independent of when exposed()is being called.

But 2. isn't really a proper solution: We would expose the correct proxy now, but the callMe method still would not be exposed on that proxy until right before the component resolved, because only then does the example call expose().

@LinusBorg LinusBorg changed the title After upgrading to 3.2.45, component ref to async component doesn't reveal exposed functions. template refs on suspended components expose component instance early, before it has been resolved or properties been exposed. Dec 20, 2022
@SimmeNilsson
Copy link
Author

Any idea if/when a fix will be made? :)

@awacode21
Copy link

i am dealing with the same issue. Last comments were late 2022. Is there something new?

@b10-as
Copy link

b10-as commented Aug 22, 2024

I'm dealing with this issue as well and would love to know if there's an update

@edison1105
Copy link
Member

Closing as duplicate of #4930

@edison1105 edison1105 closed this as not planned Won't fix, can't repro, duplicate, stale Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants