[Vite + Renderer] Component proxy is undefined (hydration error with Async components)
When hydrating an SSR application that makes use of async components, an error is thrown:
The line throwing the error is here: https://github.com/vuejs/vue-next/blob/3a6b1207fa39cb35eed5bae0b5fdcdb465926bca/packages/runtime-core/src/renderer.ts#L314
Version
3.0.2
Reproduction link
https://github.com/fiction-com/vite-vue-poc
Steps to reproduce
Create SSR application and attempt hydration with an app that uses Async components.
What is expected?
Hydration occurs smoothy.
What is actually happening?
Error is thrown "Uncaught (in promise) TypeError: Cannot read property 'proxy' of null"
Note in the example that router.ready()
is awaited at which point all async components should be resolved.
Note you shouldn't use defineAsyncComponent
with lazy routes: https://next.router.vuejs.org/guide/advanced/lazy-loading.html
Note - Do not use Async components for routes. Async components can still be used inside route components but route component themselves are just dynamic imports.
Ah! Didn't see this. Thanks you @posva . I'd suggest a warning log or similar for this edge case.
In any case, there is a typing bug in Vue Core as the !
non-null assertion suggests that component
can never be undefined.. clearly not the case ;)
Closing as using the proper import solves the issue. A PR for the warning with a test would be appreciated! 🙂
@posva
I'm still having this problem. I'm not using Vite (yet), this is pure Vue v3.0.7.
Before I was passing a Vue.defineAsyncComponent()
to the VueRouter configuration, but I already replaced that with a function that return a promise that returns the component definition.
I also am enhancing the Vue.resolveComponent = function myOwnFunction() {...}
that loads the components based on the name and this is returning a Vue.defineAsyncComponent()
value.
Here is a reproduction link: http://vue-next-example.arijs.org/
The error is here:
function createAppAPI(render, hydrate) {
return function createApp(rootComponent, rootProps = null) {
// ... snip ...
const app = (context.app = {
// ... snip ...
mount(rootContainer, isHydrate) {
if (!isMounted) {
// ... snip ...
return vnode.component.proxy; // <== vnode.component is null
Below is the value of vnode
:
({
"__v_isVNode": true,
"__v_skip": true,
"type": {
"name": "AsyncComponentWrapper",
"setup": setup() {
const instance = currentInstance; // already resolved if (resolvedComp) { return () => {…
},
"__asyncLoader": () => {…}
"__proto__": Object
},
"props": null,
"key": null,
"ref": null,
"scopeId": null,
"children": null,
"component": null,
"suspense": null,
"ssContent": null,
"ssFallback": null,
"dirs": null,
"transition": null,
"el": null,
"anchor": null,
"target": null,
"targetAnchor": null,
"staticCount": 0,
"shapeFlag": 4,
"patchFlag": 0,
"dynamicProps": null,
"dynamicChildren": null,
"appContext": null
})
Before I was getting a warning from VueRouter saying that I couldn't use Vue.defineAsyncComponent()
on the routes definition. After I changed it, I'm no longer getting that warning, but somehow I still have the vnode.component is null
error.