diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index bfb7736b..48f6f6e5 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -670,9 +670,13 @@ function finishComponentSetup( // template / render function normalization if (__NODE_JS__ && isSSR) { - if (Component.render) { - instance.render = Component.render as InternalRenderFunction - } + // 1. the render function may already exist, returned by `setup` + // 2. otherwise try to use the `Component.render` + // 3. if the component doesn't have a render function, + // set `instance.render` to NOOP so that it can inherit the render function from mixins/extend + instance.render = (instance.render || + Component.render || + NOOP) as InternalRenderFunction } else if (!instance.render) { // could be set from setup() if (compile && Component.template && !Component.render) { @@ -711,7 +715,8 @@ function finishComponentSetup( } // warn missing template/render - if (__DEV__ && !Component.render && instance.render === NOOP) { + // the runtime compilation of template in SSR is done by server-render + if (__DEV__ && !Component.render && instance.render === NOOP && !isSSR) { /* istanbul ignore if */ if (!compile && Component.template) { warn( diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts index 29bccba8..e27fdf4b 100644 --- a/packages/server-renderer/__tests__/render.spec.ts +++ b/packages/server-renderer/__tests__/render.spec.ts @@ -99,6 +99,46 @@ function testRender(type: string, render: typeof renderToString) { ).toBe(`
hello
`) }) + test('components using defineComponent with extends option', async () => { + expect( + await render( + createApp( + defineComponent({ + extends: { + data() { + return { msg: 'hello' } + }, + render(this: any) { + return h('div', this.msg) + } + } + }) + ) + ) + ).toBe(`
hello
`) + }) + + test('components using defineComponent with mixins option', async () => { + expect( + await render( + createApp( + defineComponent({ + mixins: [ + { + data() { + return { msg: 'hello' } + }, + render(this: any) { + return h('div', this.msg) + } + } + ] + }) + ) + ) + ).toBe(`
hello
`) + }) + test('optimized components', async () => { expect( await render( diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index fd40f3be..c0ba83be 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -22,7 +22,8 @@ import { isString, isVoidTag, ShapeFlags, - isArray + isArray, + NOOP } from '@vue/shared' import { ssrRenderAttrs } from './helpers/ssrRenderAttrs' import { ssrCompile } from './helpers/ssrCompile' @@ -118,7 +119,7 @@ function renderComponentSubTree( ) } else { if ( - !instance.render && + (!instance.render || instance.render === NOOP) && !instance.ssrRender && !comp.ssrRender && isString(comp.template) @@ -155,7 +156,7 @@ function renderComponentSubTree( instance.ctx ) setCurrentRenderingInstance(null) - } else if (instance.render) { + } else if (instance.render && instance.render !== NOOP) { renderVNode( push, (instance.subTree = renderComponentRoot(instance)),