From feb74ebe666cca4f0e7a1eb122f8a94c3282d984 Mon Sep 17 00:00:00 2001 From: ULIVZ <472590061@qq.com> Date: Mon, 10 Sep 2018 00:25:50 +0800 Subject: [PATCH] fix($core): SSR error when async components were registered in runtime. --- .../core/lib/app/components/Content.js | 8 +++++- .../@vuepress/core/lib/app/serverEntry.js | 26 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/@vuepress/core/lib/app/components/Content.js b/packages/@vuepress/core/lib/app/components/Content.js index cfc4ba4cbd..c034a47178 100644 --- a/packages/@vuepress/core/lib/app/components/Content.js +++ b/packages/@vuepress/core/lib/app/components/Content.js @@ -15,8 +15,14 @@ export default { render (h, { parent, props, data }) { const pageKey = props.pageKey || parent.$page.key + if (components[pageKey]) { - Vue.component(pageKey, components[pageKey]) + // In SSR, if a component is not registered with the component option + // vue-server-renderer will not be able to resovle it. + if (!parent.$ssrContext) { + Vue.component(pageKey, components[pageKey]) + } + return h(pageKey, { class: [props.custom ? 'custom' : '', data.class, data.staticClass], style: data.style, diff --git a/packages/@vuepress/core/lib/app/serverEntry.js b/packages/@vuepress/core/lib/app/serverEntry.js index defcb9e66e..f046404666 100644 --- a/packages/@vuepress/core/lib/app/serverEntry.js +++ b/packages/@vuepress/core/lib/app/serverEntry.js @@ -1,4 +1,7 @@ +import Vue from 'vue' import { createApp } from './app' +import pageComponents from '@internal/page-components' +import layoutComponents from '@internal/layout-components' export default context => new Promise((resolve, reject) => { const { app, router } = createApp(true /* isServer */) @@ -10,5 +13,26 @@ export default context => new Promise((resolve, reject) => { } router.push(url) - router.onReady(() => resolve(app)) + + // In SSR, if a component is not registered with the component option, + // vue-server-renderer will not able to resolve it. + // + // Build also works after deleting this, but the content of all pages + // will not appear to the output html, which is not conducive to SEO. + const asyncComponentLoadingPromises = [ + ...getComponentArr(pageComponents), + ...getComponentArr(layoutComponents) + ].map(({ name, loadFn }) => { + return loadFn.then(comp => { + Vue.component(name, comp.default) + }) + }) + + router.onReady(() => { + Promise.all(asyncComponentLoadingPromises).then(() => resolve(app)) + }) }) + +function getComponentArr (components) { + return Object.keys(components).map(name => ({ name, loadFn: components[name] })) +}