vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.6k stars 8.32k forks source link

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

Closed SimmeNilsson closed 1 month ago

SimmeNilsson commented 1 year ago

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 commented 1 year ago

as workaround

// Move this to the front of top level await
defineExpose({
  callMe,
});

// Make async
await new Promise((resolve) => setTimeout(resolve, 1));
edison1105 commented 1 year ago

duplicate of https://github.com/vuejs/core/issues/4930 In fact, version 3.2.45 will also have problems with production.

SimmeNilsson commented 1 year ago

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 commented 1 year ago

@SimmeNilsson this PR https://github.com/vuejs/core/pull/4951 will fix it.

LinusBorg commented 1 year ago

@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?

edison1105 commented 1 year ago

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

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

LinusBorg commented 1 year ago

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().

SimmeNilsson commented 1 year ago

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

awacode21 commented 10 months ago

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

b10-as commented 2 months ago

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

edison1105 commented 1 month ago

Closing as duplicate of https://github.com/vuejs/core/issues/4930