Просмотр исходного кода

fix(ssr): handle inline template compilation error

fix #6766
Evan You 8 лет назад
Родитель
Сommit
dff85b230a
4 измененных файлов с 33 добавлено и 16 удалено
  1. 5 3
      src/compiler/to-function.js
  2. 3 2
      src/core/util/debug.js
  3. 15 10
      src/server/render.js
  4. 10 1
      test/ssr/ssr-string.spec.js

+ 5 - 3
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') {

+ 3 - 2
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

+ 15 - 10
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: ${

+ 10 - 1
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: `<div></div><div></div>`
+    }), (err, res) => {
+      expect(err.toString()).toContain('Component template should contain exactly one root element')
+      done()
+    })
+  })
 })
 
 function renderVmWithOptions (options, cb) {