Skip to content

Commit

Permalink
fix: bail stringification for slots
Browse files Browse the repository at this point in the history
fix #1281, close #1286
  • Loading branch information
yyx990803 committed Jun 10, 2020
1 parent fbaf52a commit 9b5d13e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 12 deletions.
5 changes: 3 additions & 2 deletions packages/compiler-core/src/options.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -53,7 +53,8 @@ export interface ParserOptions {

export type HoistTransform = (
children: TemplateChildNode[],
context: TransformContext
context: TransformContext,
parent: ParentNode
) => void

export interface TransformOptions {
Expand Down
22 changes: 14 additions & 8 deletions packages/compiler-core/src/transforms/hoistStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import {
ComponentNode,
TemplateNode,
ElementNode,
VNodeCall
VNodeCall,
ParentNode
} from '../ast'
import { TransformContext } from '../transform'
import { PatchFlags, isString, isSymbol } from '@vue/shared'
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
Expand Down Expand Up @@ -44,7 +45,7 @@ const enum StaticType {
}

function walk(
children: TemplateChildNode[],
node: ParentNode,
context: TransformContext,
resultCache: Map<TemplateChildNode, StaticType>,
doNotHoistNode: boolean = false
Expand All @@ -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.
Expand Down Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
`<table><tbody>${repeat(
`<tr class="foo"><td>foo</td></tr>`,
Expand All @@ -262,4 +262,36 @@ describe('stringify static html', () => {
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
})
})

test('should bail inside slots', () => {
const { ast } = compileWithStringify(
`<foo>${repeat(
`<div class="foo"></div>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</foo>`
)
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(
`<foo><template #foo>${repeat(
`<div class="foo"></div>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)}</template></foo>`
)
expect(ast2.hoists.length).toBe(
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
)
ast2.hoists.forEach(node => {
expect(node).toMatchObject({
type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION
})
})
})
})
10 changes: 9 additions & 1 deletion packages/compiler-dom/src/transforms/stringifyStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = []
Expand Down

0 comments on commit 9b5d13e

Please sign in to comment.