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

cross-request state pollution when useAsyncData is used in a plugin #19623

Closed
huang-julien opened this issue Mar 12, 2023 · 6 comments · Fixed by #19753
Closed

cross-request state pollution when useAsyncData is used in a plugin #19623

huang-julien opened this issue Mar 12, 2023 · 6 comments · Fixed by #19753

Comments

@huang-julien
Copy link
Member

huang-julien commented Mar 12, 2023

Environment


  • Operating System: Windows_NT
  • Node Version: v18.15.0
  • Nuxt Version: 3.2.3
  • Nitro Version: 2.2.3
  • Package Manager: pnpm@7.29.1
  • Builder: vite
  • User Config: -
  • Runtime Modules: -
  • Build Modules: -

Reproduction

https://github.com/huang-julien/nuxt/tree/test/xrps-server-component
This repo contains the content of #19605
Run the fixtures in dev and go to /islands
Refresh 5-6 time, you should see that PureComponent get replaced by the result of AsyncServerComponent

You can also do it at / but you'd need to leave your finger on F5 for 2-3sec.

Check the console. There's 2 value, they should always be the same. The first one is an array length, the second one a Set size.

Describe the bug

When there's a very high rate of request with sync component server side (just leave you're finger on F5), sometimes the app instance retrieved from unctx with useNuxtApp does not belong to the current instance of vue App.

It seems that this does not apply to pages rendering but only when requesting for server components.

Additional context

Found when working on #19605. It is way easier to reproduce it with async components

discussed with @danielroe

Logs

No response

@huang-julien huang-julien changed the title cross-request state pollution with server components low risk of cross-request state pollution with server only components Mar 12, 2023
@huang-julien huang-julien changed the title low risk of cross-request state pollution with server only components cross-request state pollution with server only components Mar 14, 2023
@huang-julien
Copy link
Member Author

huang-julien commented Mar 14, 2023

confirming this also happens with NuxtIsland, not only .server components

@huang-julien
Copy link
Member Author

huang-julien commented Mar 15, 2023

@danielroe @pi0 found the culprit within the fixtures... Looks like plugins/async-plugins.ts is causing the XRSP.

useFetch is being call after a Promise so we should normally loose the context of nuxt app. But since we can have multiple server components, I guess it is easily possible to have a nuxt app used by multiple requests.

@danielroe
Copy link
Member

danielroe commented Mar 15, 2023

We perform an unctx transform of defineNuxtPlugin (in https://github.com/nuxt/nuxt/blob/6016aef859efe485871fe007d9b572304916ebba/packages/nuxt/src/core/plugins/unctx.ts) so the context should be restored. (If it weren't, then the test would throw an error - and in fact that plugin exists in the fixture in order to ensure that the transform works.) I don't think the issue is with that file in the fixtures.

@huang-julien
Copy link
Member Author

huang-julien commented Mar 15, 2023

adding await to useFetch stops the pollution 🤔 (if this can help)

@danielroe
Copy link
Member

Aha. That's very helpful. It may be a bug in useFetch.

@danielroe danielroe changed the title cross-request state pollution with server only components cross-request state pollution when useFetch is used in a plugin Mar 16, 2023
@huang-julien
Copy link
Member Author

also with useAsyncData (probably the cause), i can reproduce it with
test/fixtures/basic/plugins/async-plugin.ts

export default defineNuxtPlugin(async ( nuxtApp ) => {
  const config1 = useRuntimeConfig()
  await new Promise(resolve => setTimeout(resolve, 100))
  const { data } = useAsyncData('hey', () => {
    return $fetch('/api/hey')
  })
  const config2 = useRuntimeConfig() 
  return {
    provide: {
      asyncPlugin: () => config1 && config1 === config2
        ? 'Async plugin works! ' + config1.testConfig + (data.value?.baz ? 'useFetch works!' : 'useFetch does not work')
        : 'Async plugin failed!'
    }
  }
})

@danielroe danielroe changed the title cross-request state pollution when useFetch is used in a plugin cross-request state pollution when useAsyncData is used in a plugin Mar 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment