diff --git a/flow/options.js b/flow/options.js index ea7736836d..c7045f359d 100644 --- a/flow/options.js +++ b/flow/options.js @@ -33,7 +33,8 @@ declare type ComponentOptions = { // DOM el?: string | Element; template?: string; - render: () => VNode; + render: (h: () => VNode) => VNode; + renderError?: (h: () => VNode, err: Error) => VNode; staticRenderFns?: Array<() => VNode>; // lifecycle beforeCreate?: Function; diff --git a/src/core/instance/render.js b/src/core/instance/render.js index 237b356369..c4d26c849a 100644 --- a/src/core/instance/render.js +++ b/src/core/instance/render.js @@ -78,8 +78,15 @@ export function renderMixin (Vue: Class) { vnode = render.call(vm._renderProxy, vm.$createElement) } catch (e) { handleError(e, vm, `render function`) - // return previous vnode to prevent render error causing blank component - vnode = vm._vnode + // return error render result, + // or previous vnode to prevent render error causing blank component + if (process.env.NODE_ENV !== 'production') { + vnode = vm.$options.renderError + ? vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) + : vm._vnode + } else { + vnode = vm._vnode + } } // return empty vnode in case the render function errored out if (!(vnode instanceof VNode)) { diff --git a/test/unit/features/error-handling.spec.js b/test/unit/features/error-handling.spec.js index 61b4661ba6..f5162ebe78 100644 --- a/test/unit/features/error-handling.spec.js +++ b/test/unit/features/error-handling.spec.js @@ -96,7 +96,9 @@ describe('Error handling', () => { expect(args[1]).toBe(vm.$refs.child) // vm expect(args[2]).toContain('render function') // description - assertRootInstanceActive(vm).then(done) + assertRootInstanceActive(vm).then(() => { + Vue.config.errorHandler = null + }).then(done) }) }) diff --git a/test/unit/features/options/renderError.spec.js b/test/unit/features/options/renderError.spec.js new file mode 100644 index 0000000000..36b263b856 --- /dev/null +++ b/test/unit/features/options/renderError.spec.js @@ -0,0 +1,28 @@ +import Vue from 'vue' + +describe('Options renderError', () => { + it('should be used on render errors', done => { + Vue.config.errorHandler = () => {} + const vm = new Vue({ + data: { + ok: true + }, + render (h) { + if (this.ok) { + return h('div', 'ok') + } else { + throw new Error('no') + } + }, + renderError (h, err) { + return h('div', err.toString()) + } + }).$mount() + expect(vm.$el.textContent).toBe('ok') + vm.ok = false + waitForUpdate(() => { + expect(vm.$el.textContent).toBe('Error: no') + Vue.config.errorHandler = null + }).then(done) + }) +})