@vue/server-renderer's renderToString doesn't resolve async components
Version
3.0.7
Reproduction link
https://github.com/BeauAgst/async-resolve-vue
Steps to reproduce
Notice that in App.vue
, we have used defineAsyncComponent
. npm run compile
is a small repro script to demonstrate that renderToString
is failing.
- Run
npm run build
- Run
npm run compile
What is expected?
Asynchronous components should be resolved so that the component can render
What is actually happening?
[Vue warn]: Unhandled error during execution of setup function
at <AsyncComponentWrapper msg="Welcome to Your Vue.js App" >
(node:43827) UnhandledPromiseRejectionWarning: ReferenceError: document is not defined
Currently I'm trying to build out an app that will have a dynamic root component. I am running vue-cli-service build
with 2 different contexts - one for server, and another for the client for hydration.
When I build for the server, it fails because of the async component. It works perfectly for the client however. If I use regular import, my client bundle becomes a lot larger, but the server bundle works and I can use renderToString
.
I have also deleted the splitChunks
optimisation via webpack.config.js
, but that doesn't seem to resolve the issue.
I am able to get around this for my specific scenario by creating two versions of App.vue
, which has async components for client, and regular imports for the server. However, this isn't ideal if I were to attempt to asynchronously load a component nested further into the project for the client.
Try this in your vue.config.js
const { WebpackManifestPlugin } = require('webpack-manifest-plugin')
const nodeExternals = require('webpack-node-externals')
module.exports = {
chainWebpack: config => {
config.plugin('manifest').use(new WebpackManifestPlugin({ fileName: 'manifest.json' }))
if (process.env.BUILD_MODE !== 'SSR') return
config.target('node')
config.output.libraryTarget('commonjs2')
config.externals(nodeExternals({ allowlist: /\.(css)$/ }))
config.module.rule('vue').uses.delete('cache-loader')
config.module.rule('js').uses.delete('cache-loader')
config.module.rule('ts').uses.delete('cache-loader')
config.module.rule('tsx').uses.delete('cache-loader')
config.optimization.delete('splitChunks')
config.plugins.delete('hmr').delete('html').delete('inline-runtime-chunk')
config.plugins.delete('preload')
config.plugins.delete('prefetch').delete('named-chunks')
const isExtracting = config.plugins.has('extract-css')
if (isExtracting) {
const langs = ['css', 'postcss', 'scss', 'sass', 'less', 'stylus']
const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
for (const lang of langs) {
for (const type of types) {
const rule = config.module.rule(lang).oneOf(type)
rule.uses.delete('extract-css-loader')
}
}
config.plugins.delete('extract-css')
}
},
}