diff --git a/src/compiler/to-function.js b/src/compiler/to-function.js index 6137422cf51..d9f20056093 100644 --- a/src/compiler/to-function.js +++ b/src/compiler/to-function.js @@ -1,7 +1,7 @@ /* @flow */ -import { noop } from 'shared/util' -import { warn, tip } from 'core/util/debug' +import { noop, extend } from 'shared/util' +import { warn as baseWarn, tip } from 'core/util/debug' type CompiledFunctionResult = { render: Function; @@ -27,7 +27,9 @@ export function createCompileToFunctionFn (compile: Function): Function { options?: CompilerOptions, vm?: Component ): CompiledFunctionResult { - options = options || {} + options = extend({}, options) + const warn = options.warn || baseWarn + delete options.warn /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production') { diff --git a/src/core/util/debug.js b/src/core/util/debug.js index 7799024240d..4508ac2d36a 100644 --- a/src/core/util/debug.js +++ b/src/core/util/debug.js @@ -5,7 +5,8 @@ import { noop } from 'shared/util' export let warn = noop export let tip = noop -export let formatComponentName: Function = (null: any) // work around flow check +export let generateComponentTrace = (noop: any) // work around flow check +export let formatComponentName = (noop: any) if (process.env.NODE_ENV !== 'production') { const hasConsole = typeof console !== 'undefined' @@ -66,7 +67,7 @@ if (process.env.NODE_ENV !== 'production') { return res } - const generateComponentTrace = vm => { + generateComponentTrace = vm => { if (vm._isVue && vm.$parent) { const tree = [] let currentRecursiveSequence = 0 diff --git a/src/server/render.js b/src/server/render.js index 52d0191c9d1..8be73cf3f6d 100644 --- a/src/server/render.js +++ b/src/server/render.js @@ -1,18 +1,14 @@ /* @flow */ -import { - isDef, - isUndef, - isTrue, - extend -} from 'shared/util' - import { escape } from 'web/server/util' import { SSR_ATTR } from 'shared/constants' import { RenderContext } from './render-context' +import { generateComponentTrace } from 'core/util/debug' import { ssrCompileToFunctions } from 'web/server/compiler' import { installSSRHelpers } from './optimizing-compiler/runtime-helpers' +import { isDef, isUndef, isTrue } from 'shared/util' + import { createComponent, createComponentInstanceForVnode @@ -26,13 +22,22 @@ const warnOnce = msg => { } } +const onCompilationError = (err, vm) => { + const trace = vm ? generateComponentTrace(vm) : '' + throw new Error(`\n\u001b[31m${err}${trace}\u001b[39m\n`) +} + const normalizeRender = vm => { const { render, template, _scopeId } = vm.$options if (isUndef(render)) { if (template) { - extend(vm.$options, ssrCompileToFunctions(template, { - scopeId: _scopeId - })) + const compiled = ssrCompileToFunctions(template, { + scopeId: _scopeId, + warn: onCompilationError + }, vm) + + vm.$options.render = compiled.render + vm.$options.staticRenderFns = compiled.staticRenderFns } else { throw new Error( `render function or template not defined in component: ${ diff --git a/test/ssr/ssr-string.spec.js b/test/ssr/ssr-string.spec.js index 547ba19e39c..7e07ad112fe 100644 --- a/test/ssr/ssr-string.spec.js +++ b/test/ssr/ssr-string.spec.js @@ -968,7 +968,7 @@ describe('SSR: renderToString', () => { }) }) - it('should Promise (error)', done => { + it('return Promise (error)', done => { Vue.config.silent = true renderToString(new Vue({ render () { @@ -980,6 +980,15 @@ describe('SSR: renderToString', () => { done() }) }) + + it('should catch template compilation error', done => { + renderToString(new Vue({ + template: `
` + }), (err, res) => { + expect(err.toString()).toContain('Component template should contain exactly one root element') + done() + }) + }) }) function renderVmWithOptions (options, cb) {