]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: bail stringification for slots
authorEvan You <yyx990803@gmail.com>
Wed, 10 Jun 2020 18:31:51 +0000 (14:31 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 10 Jun 2020 18:31:59 +0000 (14:31 -0400)
fix #1281, close #1286

packages/compiler-core/src/options.ts
packages/compiler-core/src/transforms/hoistStatic.ts
packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts
packages/compiler-dom/src/transforms/stringifyStatic.ts

index 7b2c888674a9757d5a37fe68cb6d87be66905a03..621fe93b2258ddfb99a4866ef86f9c815a4d1942 100644 (file)
@@ -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 {
index b3ac3aa7cce253de00908ec1fce064febeda9a3e..d584ca74094aca136ab2c4753a5a3c4f203571cb 100644 (file)
@@ -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<TemplateChildNode, StaticType>,
   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)
   }
 }
 
index 62d12af7456c3749992e1319965192d943f6ac5d..5dc5621725b4802746c2193ba97d9590a1d961e9 100644 (file)
@@ -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>`,
@@ -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
+      })
+    })
+  })
 })
index b34377e25c32ae02e48ad507a7246638b50026f4..94a4e05396cca7d0cc1e2d5f3539462d56261c8c 100644 (file)
@@ -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[] = []