Can't use async components in vue3 when using SSR

Viewed 952

I have a vue 3 app with vue-router and vuex installed which is working very well. Now I'm trying to integrate server side rendering for it. This was also working very well until I integrated defineAsyncComponent() to lazy load my routes.

As soon as I switch from this router implementation:

import {defineAsyncComponent} from "vue"
import {createRouter} from 'vue-router'
import Home from '../pages/Home.vue' //<-- no async import

export default function (history) {
    return createRouter({
        history: history,
        routes: [
            {
                path: '/',
                component: Home
            },
        ]
    });
}

to a variant with async components:

import {defineAsyncComponent} from "vue"
import {createRouter} from 'vue-router'

const Home = defineAsyncComponent(() => import('../pages/Home.vue')); //<-- changed to a async import

export default function (history) {
    return createRouter({
        history: history,
        routes: [
            {
                path: '/',
                component: Home
            },
        ]
    });
}

I get tho following error when I try to render the app on server side (client side is still working well and async components are loaded as expected):

/var/app/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:1542 return (comp.__props = shared.EMPTY_ARR); ^ TypeError: Cannot add property __props, object is not extensible at normalizePropsOptions (/var/app/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:1542:30) at createComponentInstance (/var/app/node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5934:23) at renderComponentVNode (/var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:159:22) at renderVNode (/var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:244:22) at renderComponentSubTree (/var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:213:13) at /var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:174:29 at async unrollBuffer (/var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:355:24) at async unrollBuffer (/var/app/node_modules/@vue/server-renderer/dist/server-renderer.cjs.js:361:24)

This is the vite config I use to build everything:

const {ssrBuild, build} = require('vite')

;(async () => {
    await build({
        mode: 'development',
        assetsDir: '.',
        emitAssets: false,
        rollupInputOptions: {
            input: './resources/js/entry-client.js'
        },
        rollupOutputOptions: {
            entryFileNames: '[name].js'
        },
        outDir: 'public/build/client',
    })

    await ssrBuild({
        mode: 'development',
        rollupInputOptions: {
            inlineDynamicImports: true,
            input: './resources/js/entry-server.js'
        },
        outDir: 'public/build/server',
    })

    process.exit();
})()

and this is my server-entry.js:

import renderer from '@vue/server-renderer';
import createApp from './main.js';

const {app, router, store} = createApp(context, true);

router.push(context.url);

router.isReady().then(() => {
    renderer.renderToString(app).then((html) => {

        var data = JSON.stringify({
            'resourceHints': '',
            'styles': '',
            'html': html,
            'state': store.state,
            'scripts': "",
            'preload': '',
        })

        console.log(data);
    });
});

Do you have any idea why the ssr build does not work with async components and how I can fix this?

1 Answers

When setting up async/code-splitting in VueRouter specifically, you shouldn't be using defineAsyncComponent at all.

https://next.router.vuejs.org/guide/advanced/lazy-loading.html

Simply pass a function that returns an import:

const UserDetails = () => import('./views/UserDetails')

const router = createRouter({
  // ...
  routes: [{ path: '/users/:id', component: UserDetails }],
})

Related