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

watch() does not work after building for production using npm run build #7688

Open
olfek opened this issue Feb 10, 2023 · 12 comments · May be fixed by #7689
Open

watch() does not work after building for production using npm run build #7688

olfek opened this issue Feb 10, 2023 · 12 comments · May be fixed by #7689
Labels
🐞 bug Something isn't working scope: suspense

Comments

@olfek
Copy link

olfek commented Feb 10, 2023

Vue version

3.2.45

Link to minimal reproduction

will add zip file to this issue

Steps to reproduce

  1. Run npm run dev
  2. Observe that watch is called
  3. Run npm run build and serve using npx http-server dist
  4. 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()

@olfek
Copy link
Author

olfek commented Feb 10, 2023

Creating the minimal reproduction, I've learned that it has something to do with:

  • <Suspense> in App.vue
  • The use of await in HomeView.vue

@olfek
Copy link
Author

olfek commented Feb 10, 2023

@olfek
Copy link
Author

olfek commented Feb 10, 2023

  • Replacing await with void in HomeView.vue makes the problem go away.
  • <Suspense> was added in App.vue because without it, the use of await in HomeView.vue gives errors.

@LinusBorg
Copy link
Member

LinusBorg commented 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, as props 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 propsobject in the component itself has not been updated with that new value, and so the watch is never triggered.

Addign this to HomeView:

onBeforeUpdate(() => {
        const vnodeProps = getCurrentInstance()?.vnode.props
        console.log('updating...', { ...props }, { ...vnodeProps })
    })

results in this console entry:

Bildschirm­foto 2023-02-10 um 22 40 46

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
Copy link
Member

LinusBorg commented Feb 10, 2023

Bildschirm­foto 2023-02-10 um 23 00 11

patchFlag is 0, so it should receive a full props diff, but optimized is true, so line 3823 evaluates to true, so the code enters that branch - where it then does nothing because patchFlag is 0(see line 3825).

That only happens when HomeView is async. When that component is not async, optimized is false, and thus a full props patch is being done, so the app works as expected in that case.

@olfek
Copy link
Author

olfek commented Feb 10, 2023

Have you been able to reproduce it @LinusBorg ? Is this now a confirmed bug?

@LinusBorg
Copy link
Member

Yes

@LinusBorg LinusBorg added the 🐞 bug Something isn't working label Feb 10, 2023
Copy link
Member

posva commented 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 LinusBorg added security Pull requests that address a security vulnerability scope: suspense labels Feb 11, 2023
@LinusBorg
Copy link
Member

LinusBorg commented Feb 11, 2023

Got it. when calling suspense.registerDep, we don't pass the current value of optimize. Instead, in registerDep, we use the closure's value of optimized that was passed to createSusenseBoundary()

parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect)

I think we would need to change registerDep to accept the optimized flag as a third argument?

registerDep(instance, setupRenderEffect, optimized = false) {

Not sure how to write a proper test for this though.

@LinusBorg LinusBorg removed the security Pull requests that address a security vulnerability label Feb 11, 2023
@olfek
Copy link
Author

olfek commented Feb 11, 2023

Thank you for triaging this and finding a fix so quickly, much appreciated @LinusBorg ❤️

@olfek
Copy link
Author

olfek commented Feb 11, 2023

The difference of behavior between dev and production is caused by the optimized parameter? @LinusBorg

@LinusBorg
Copy link
Member

yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐞 bug Something isn't working scope: suspense
Projects
None yet
3 participants