diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index dd2e62b85fb..4afc4711c2f 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -18,6 +18,7 @@ export class CodegenState { maybeComponent: (el: ASTElement) => boolean; onceId: number; staticRenderFns: Array; + pre: boolean; constructor (options: CompilerOptions) { this.options = options @@ -29,6 +30,7 @@ export class CodegenState { this.maybeComponent = (el: ASTElement) => !(isReservedTag(el.tag) && !el.component) this.onceId = 0 this.staticRenderFns = [] + this.pre = false } } @@ -58,7 +60,7 @@ export function genElement (el: ASTElement, state: CodegenState): string { return genFor(el, state) } else if (el.if && !el.ifProcessed) { return genIf(el, state) - } else if (el.tag === 'template' && !el.slotTarget) { + } else if (el.tag === 'template' && !el.slotTarget && !state.pre) { return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { return genSlot(el, state) @@ -88,7 +90,15 @@ export function genElement (el: ASTElement, state: CodegenState): string { // hoist static sub-trees out function genStatic (el: ASTElement, state: CodegenState): string { el.staticProcessed = true + // Some elements (templates) need to behave differently inside of a v-pre + // node. All pre nodes are static roots, so we can use this as a location to + // wrap a state change and reset it upon exiting the pre node. + const originalPreState = state.pre + if (el.pre) { + state.pre = el.pre + } state.staticRenderFns.push(`with(this){return ${genElement(el, state)}}`) + state.pre = originalPreState return `_m(${ state.staticRenderFns.length - 1 }${ diff --git a/test/unit/modules/compiler/codegen.spec.js b/test/unit/modules/compiler/codegen.spec.js index 126453555f1..0758142ed27 100644 --- a/test/unit/modules/compiler/codegen.spec.js +++ b/test/unit/modules/compiler/codegen.spec.js @@ -595,6 +595,18 @@ describe('codegen', () => { expect(res.render).toBe(generatedCode) }) + // #8041 + it('does not squash templates inside v-pre', () => { + const template = '
' + const generatedCode = `with(this){return _m(0)}` + const renderFn = `with(this){return _c('div',{pre:true},[_c('template',[_c('p',[_v("{{msg}}")])])],2)}` + const ast = parse(template, baseOptions) + optimize(ast, baseOptions) + const res = generate(ast, baseOptions) + expect(res.render).toBe(generatedCode) + expect(res.staticRenderFns).toEqual([renderFn]) + }) + it('not specified ast type', () => { const res = generate(null, baseOptions) expect(res.render).toBe(`with(this){return _c("div")}`) diff --git a/test/unit/modules/compiler/parser.spec.js b/test/unit/modules/compiler/parser.spec.js index 5ab0398990a..1cdaa3b7171 100644 --- a/test/unit/modules/compiler/parser.spec.js +++ b/test/unit/modules/compiler/parser.spec.js @@ -250,6 +250,15 @@ describe('parser', () => { expect(ast.children[0].children[0].text).toBe('{{msg}}') }) + it('v-pre directive should leave template in DOM', () => { + const ast = parse('
', baseOptions) + expect(ast.pre).toBe(true) + expect(ast.attrs[0].name).toBe('id') + expect(ast.attrs[0].value).toBe('"message1"') + expect(ast.children[0].attrs[0].name).toBe('id') + expect(ast.children[0].attrs[0].value).toBe('"template1"') + }) + it('v-for directive basic syntax', () => { const ast = parse('', baseOptions) const liAst = ast.children[0]