diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts index 7b2c8886..621fe93b 100644 --- a/packages/compiler-core/src/options.ts +++ b/packages/compiler-core/src/options.ts @@ -1,4 +1,4 @@ -import { ElementNode, Namespace, TemplateChildNode } from './ast' +import { ElementNode, Namespace, TemplateChildNode, ParentNode } from './ast' import { TextModes } from './parse' import { CompilerError } from './errors' import { @@ -53,7 +53,8 @@ export interface ParserOptions { export type HoistTransform = ( children: TemplateChildNode[], - context: TransformContext + context: TransformContext, + parent: ParentNode ) => void export interface TransformOptions { diff --git a/packages/compiler-core/src/transforms/hoistStatic.ts b/packages/compiler-core/src/transforms/hoistStatic.ts index b3ac3aa7..d584ca74 100644 --- a/packages/compiler-core/src/transforms/hoistStatic.ts +++ b/packages/compiler-core/src/transforms/hoistStatic.ts @@ -8,7 +8,8 @@ import { ComponentNode, TemplateNode, ElementNode, - VNodeCall + VNodeCall, + ParentNode } from '../ast' import { TransformContext } from '../transform' import { PatchFlags, isString, isSymbol } from '@vue/shared' @@ -16,7 +17,7 @@ import { isSlotOutlet, findProp } from '../utils' export function hoistStatic(root: RootNode, context: TransformContext) { walk( - root.children, + root, context, new Map(), // Root node is unfortunately non-hoistable due to potential parent @@ -44,7 +45,7 @@ const enum StaticType { } function walk( - children: TemplateChildNode[], + node: ParentNode, context: TransformContext, resultCache: Map, doNotHoistNode: boolean = false @@ -60,6 +61,7 @@ function walk( // stringficiation threshold is met. let hasRuntimeConstant = false + const { children } = node for (let i = 0; i < children.length; i++) { const child = children[i] // only plain elements & text calls are eligible for hoisting. @@ -114,21 +116,25 @@ function walk( // walk further if (child.type === NodeTypes.ELEMENT) { - walk(child.children, context, resultCache) + walk(child, context, resultCache) } else if (child.type === NodeTypes.FOR) { // Do not hoist v-for single child because it has to be a block - walk(child.children, context, resultCache, child.children.length === 1) + walk(child, context, resultCache, child.children.length === 1) } else if (child.type === NodeTypes.IF) { for (let i = 0; i < child.branches.length; i++) { - const branchChildren = child.branches[i].children // Do not hoist v-if single child because it has to be a block - walk(branchChildren, context, resultCache, branchChildren.length === 1) + walk( + child.branches[i], + context, + resultCache, + child.branches[i].children.length === 1 + ) } } } if (!hasRuntimeConstant && hasHoistedNode && context.transformHoist) { - context.transformHoist(children, context) + context.transformHoist(children, context, node) } } diff --git a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts index 62d12af7..5dc56217 100644 --- a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts @@ -250,7 +250,7 @@ describe('stringify static html', () => { }) }) - test('should bail on break content with innerHTML (eg.tables related tags)', () => { + test('should bail on tags that has placement constraints (eg.tables related tags)', () => { const { ast } = compileWithStringify( `${repeat( ``, @@ -262,4 +262,36 @@ describe('stringify static html', () => { type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION }) }) + + test('should bail inside slots', () => { + const { ast } = compileWithStringify( + `${repeat( + `
`, + StringifyThresholds.ELEMENT_WITH_BINDING_COUNT + )}
` + ) + expect(ast.hoists.length).toBe( + StringifyThresholds.ELEMENT_WITH_BINDING_COUNT + ) + ast.hoists.forEach(node => { + expect(node).toMatchObject({ + type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION + }) + }) + + const { ast: ast2 } = compileWithStringify( + `` + ) + expect(ast2.hoists.length).toBe( + StringifyThresholds.ELEMENT_WITH_BINDING_COUNT + ) + ast2.hoists.forEach(node => { + expect(node).toMatchObject({ + type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION + }) + }) + }) }) diff --git a/packages/compiler-dom/src/transforms/stringifyStatic.ts b/packages/compiler-dom/src/transforms/stringifyStatic.ts index b34377e2..94a4e053 100644 --- a/packages/compiler-dom/src/transforms/stringifyStatic.ts +++ b/packages/compiler-dom/src/transforms/stringifyStatic.ts @@ -59,7 +59,15 @@ type StringifiableNode = PlainElementNode | TextCallNode * * This optimization is only performed in Node.js. */ -export const stringifyStatic: HoistTransform = (children, context) => { +export const stringifyStatic: HoistTransform = (children, context, parent) => { + if ( + parent.type === NodeTypes.ELEMENT && + (parent.tagType === ElementTypes.COMPONENT || + parent.tagType === ElementTypes.TEMPLATE) + ) { + return + } + let nc = 0 // current node count let ec = 0 // current element with binding count const currentChunk: StringifiableNode[] = []
foo