From 354d79c42bf152643b77d83520757818d913de4f Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 27 Jul 2020 17:44:17 -0400 Subject: [PATCH] fix(runtime-core): respect render function from mixins fix #1630 --- .../runtime-core/__tests__/apiOptions.spec.ts | 11 +++++ packages/runtime-core/src/component.ts | 40 ++++++++++--------- packages/runtime-core/src/componentOptions.ts | 10 ++++- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/packages/runtime-core/__tests__/apiOptions.spec.ts b/packages/runtime-core/__tests__/apiOptions.spec.ts index 0107848ec68..074596bb30f 100644 --- a/packages/runtime-core/__tests__/apiOptions.spec.ts +++ b/packages/runtime-core/__tests__/apiOptions.spec.ts @@ -520,6 +520,17 @@ describe('api: options', () => { ]) }) + test('render from mixin', () => { + const Comp = { + mixins: [ + { + render: () => 'from mixin' + } + ] + } + expect(renderToString(h(Comp))).toBe('from mixin') + }) + test('extends', () => { const calls: string[] = [] const Base = { diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 2a8e1efbe63..58e1725e8e9 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -589,6 +589,7 @@ function finishComponentSetup( instance.render = Component.render as InternalRenderFunction } } else if (!instance.render) { + // could be set from setup() if (compile && Component.template && !Component.render) { if (__DEV__) { startMeasure(instance, `compile`) @@ -604,25 +605,6 @@ function finishComponentSetup( ;(Component.render as InternalRenderFunction)._rc = true } - if (__DEV__ && !Component.render) { - /* istanbul ignore if */ - if (!compile && Component.template) { - warn( - `Component provided template option but ` + - `runtime compilation is not supported in this build of Vue.` + - (__ESM_BUNDLER__ - ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` - : __ESM_BROWSER__ - ? ` Use "vue.esm-browser.js" instead.` - : __GLOBAL__ - ? ` Use "vue.global.js" instead.` - : ``) /* should not happen */ - ) - } else { - warn(`Component is missing template or render function.`) - } - } - instance.render = (Component.render || NOOP) as InternalRenderFunction // for runtime-compiled render functions using `with` blocks, the render @@ -642,6 +624,26 @@ function finishComponentSetup( applyOptions(instance, Component) currentInstance = null } + + // warn missing template/render + if (__DEV__ && !Component.render && instance.render === NOOP) { + /* istanbul ignore if */ + if (!compile && Component.template) { + warn( + `Component provided template option but ` + + `runtime compilation is not supported in this build of Vue.` + + (__ESM_BUNDLER__ + ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` + : __ESM_BROWSER__ + ? ` Use "vue.esm-browser.js" instead.` + : __GLOBAL__ + ? ` Use "vue.global.js" instead.` + : ``) /* should not happen */ + ) + } else { + warn(`Component is missing template or render function.`) + } + } } const attrHandlers: ProxyHandler = { diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 247ea946d47..19e8f4bbba0 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -4,7 +4,8 @@ import { SetupContext, ComponentInternalOptions, PublicAPIComponent, - Component + Component, + InternalRenderFunction } from './component' import { isFunction, @@ -390,6 +391,7 @@ export function applyOptions( deactivated, beforeUnmount, unmounted, + render, renderTracked, renderTriggered, errorCaptured @@ -398,7 +400,10 @@ export function applyOptions( const publicThis = instance.proxy! const ctx = instance.ctx const globalMixins = instance.appContext.mixins - // call it only during dev + + if (asMixin && render && instance.render === NOOP) { + instance.render = render as InternalRenderFunction + } // applyOptions is called non-as-mixin once per instance if (!asMixin) { @@ -406,6 +411,7 @@ export function applyOptions( // global mixins are applied first applyMixins(instance, globalMixins, deferredData, deferredWatch) } + // extending a base component... if (extendsOptions) { applyOptions(instance, extendsOptions, deferredData, deferredWatch, true)