Closed
Description
Vue version
3.2.45
Link to minimal reproduction
will add zip file to this issue
Steps to reproduce
- Run
npm run dev
- Observe that watch is called
- Run
npm run build
and serve usingnpx http-server dist
- Observe that watch is not called
What is expected?
watch callback gets called
What is actually happening?
watch callback does not get called
System Info
No response
Any additional comments?
creating this issue to bring attention back to (#5707)
looks like the bug affects both watch()
and watchEffect()
Activity
olfek commentedon Feb 10, 2023
Creating the minimal reproduction, I've learned that it has something to do with:
<Suspense>
inApp.vue
await
inHomeView.vue
olfek commentedon Feb 10, 2023
watch-watchEffect-bug.zip
olfek commentedon Feb 10, 2023
await
withvoid
inHomeView.vue
makes the problem go away.<Suspense>
was added inApp.vue
because without it, the use ofawait
inHomeView.vue
gives errors.LinusBorg commentedon Feb 10, 2023
This seems to be unrelated to #5707.
The problem here is that the component's
props
object is not being properly updated when the route changes - so the watch of course can't run, asprops
didn't change.Here's what I could find out quickly:
The renderer triggers a re-render of the HomeView component, because in the component's vnode, the prop has been updated. However the
props
object in the component itself has not been updated with that new value, and so the watch is never triggered.Addign this to
HomeView
:results in this console entry:
So, seems to be a problem with Suspense, maybe in combination with
<RouterView>
./cc @posva does this look familiar to some problem you have seen before?
LinusBorg commentedon Feb 10, 2023
patchFlag
is0
, so it should receive a full props diff, butoptimized
istrue
, so line 3823 evaluates to true, so the code enters that branch - where it then does nothing because patchFlag is0
(see line 3825).That only happens when
HomeView
is async. When that component is not async,optimized
isfalse
, and thus a full props patch is being done, so the app works as expected in that case.olfek commentedon Feb 10, 2023
Have you been able to reproduce it @LinusBorg ? Is this now a confirmed bug?
LinusBorg commentedon Feb 10, 2023
Yes
posva commentedon Feb 11, 2023
There are other bugs with Suspense and keep alive that appear because the entering component renders before the leaving component. There are some open issues in vue router about this. But I don't recall any problem with a different behavior between dev and prod
LinusBorg commentedon Feb 11, 2023
Got it. when calling
suspense.registerDep
, we don't pass the current value ofoptimize
. Instead, inregisterDep
, we use the closure's value ofoptimized
that was passed tocreateSusenseBoundary()
core/packages/runtime-core/src/renderer.ts
Line 1231 in 1d09540
I think we would need to change
registerDep
to accept theoptimized
flag as a third argument?Not sure how to write a proper test for this though.
olfek commentedon Feb 11, 2023
Thank you for triaging this and finding a fix so quickly, much appreciated @LinusBorg ❤️
olfek commentedon Feb 11, 2023
The difference of behavior between dev and production is caused by the
optimized
parameter? @LinusBorgLinusBorg commentedon Feb 11, 2023
yes
fix(runtime-core): ensure suspense creates dep component's render eff…