diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index be8d87da..6d219bb5 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -130,29 +130,37 @@ export function parse ( processAttrs(element) } - // tree management - if (!root) { - root = element - // check root element constraints + function checkRootConstraints (el) { if (process.env.NODE_ENV !== 'production') { - if (tag === 'slot' || tag === 'template') { + if (el.tag === 'slot' || el.tag === 'template') { warn( - `Cannot use <${tag}> as component root element because it may ` + + `Cannot use <${el.tag}> as component root element because it may ` + 'contain multiple nodes:\n' + template ) } - if (element.attrsMap.hasOwnProperty('v-for')) { + if (el.attrsMap.hasOwnProperty('v-for')) { warn( 'Cannot use v-for on stateful component root element because ' + 'it renders multiple elements:\n' + template ) } } + } + + // tree management + if (!root) { + root = element + checkRootConstraints(root) } else if (process.env.NODE_ENV !== 'production' && !stack.length && !warned) { - warned = true - warn( - `Component template should contain exactly one root element:\n\n${template}` - ) + // allow 2 root elements with v-if and v-else + if ((root.attrsMap.hasOwnProperty('v-if') && element.attrsMap.hasOwnProperty('v-else'))) { + checkRootConstraints(element) + } else { + warned = true + warn( + `Component template should contain exactly one root element:\n\n${template}` + ) + } } if (currentParent && !element.forbidden) { if (element.else) { diff --git a/test/unit/modules/compiler/parser.spec.js b/test/unit/modules/compiler/parser.spec.js index 0574053e..56bfdbb2 100644 --- a/test/unit/modules/compiler/parser.spec.js +++ b/test/unit/modules/compiler/parser.spec.js @@ -76,6 +76,35 @@ describe('parser', () => { expect('Component template should contain exactly one root element').toHaveBeenWarned() }) + it('warn multiple root elements', () => { + parse('
', baseOptions) + expect('Component template should contain exactly one root element:\n\n
').toHaveBeenWarned() + }) + + it('not warn 2 root elements with v-if and v-else', () => { + parse('
', baseOptions) + expect('Component template should contain exactly one root element:\n\n
') + .not.toHaveBeenWarned() + }) + + it('warn 2 root elements with v-if', () => { + parse('
', baseOptions) + expect('Component template should contain exactly one root element:\n\n
') + .toHaveBeenWarned() + }) + + it('warn 3 root elements with v-if and v-else on first 2', () => { + parse('
', baseOptions) + expect('Component template should contain exactly one root element:\n\n
') + .toHaveBeenWarned() + }) + + it('warn 2 root elements with v-if and v-else with v-for on 2nd', () => { + parse('
', baseOptions) + expect('Cannot use v-for on stateful component root element because it renders multiple elements:\n
') + .toHaveBeenWarned() + }) + it('warn