defineAsyncComponent render error in ssr
Vue version
latest
Link to minimal reproduction
Steps to reproduce
open the playground
What is expected?
render the component
What is actually happening?
get error
System Info
No response
Any additional comments?
No response
This could be a bug on the playground, currentInstance = null
that's not possible, did you test it in the test case?
This could be a bug on the playground,
currentInstance = null
that's not possible, did you test it in the test case?
https://github.com/vuejs/core/blob/78b86150b801e7eb4ebf1cdff977e791dc0438f0/packages/runtime-core/__tests__/hydration.spec.ts#L716 This test is passed, maybe it is a playground bug
Hey, it is definitely not a playground bug, I have run into the exact same issue with our production application.
Here is some more context:
- It is an SSR app built on https://vite-plugin-ssr.com/ with Vue 3.3.4
- We have noticed that sometimes if the Async component chunks were loading slower on flaky networks (and always in Safari for some reason), the hydration of components was failing, but was succeeding after the chunks had been cached on subsequent page visits.
I would say as the issue naturally occurs in Safari, even on stable networks, it is quite severe.
After looking into the implementation for defineAsyncComponent
I have noticed that the case of hydration is never handled when the component is not managed by a Suspense. https://github.com/vuejs/core/blob/623ba514ec0f5adc897db90c0f986b1b6905e014/packages/runtime-core/src/apiAsyncComponent.ts#L198
if (loaded.value && resolvedComp) {
return createInnerComp(resolvedComp, instance)
} else if (error.value && errorComponent) {
return createVNode(errorComponent, {
error: error.value
})
} else if (loadingComponent && !delayed.value) {
return createVNode(loadingComponent)
}
// If none of the above conditions are met, meaning that the component is still loading
// and the component was rendered on the server, then no vnode is returned resulting
// in a `<!--[-->`(Fragment) being rendered and hydration mismatch in return
Workaround: Wrap each AsyncComponent
in the template with Suspense
<template>
<Suspense>
<AsnycComp />
</Suspense>
</template>
<script setup>
const AsyncComp = defineAsyncComponent(() => import('./Comp.vue'));
</script>