]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler): v-for fragments should be blocks
authorEvan You <yyx990803@gmail.com>
Wed, 2 Oct 2019 14:47:01 +0000 (10:47 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 2 Oct 2019 14:47:01 +0000 (10:47 -0400)
packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-core/__tests__/transforms/vFor.spec.ts
packages/compiler-core/src/ast.ts
packages/compiler-core/src/transforms/vFor.ts
packages/compiler-core/src/transforms/vIf.ts

index 9bf7229e51fd7f4ddc007e10e3e233acf95d5d0c..8d7ae5dd4c98f39bf555a111c0984e0e2187ce79 100644 (file)
@@ -17,11 +17,11 @@ return function render() {
         : _createBlock(_Fragment, { key: 1 }, [
             \\"no\\"
           ])),
-      _createVNode(_Fragment, null, _renderList(list, (value, index) => {
+      (_openBlock(), _createBlock(_Fragment, null, _renderList(list, (value, index) => {
         return (_openBlock(), _createBlock(\\"div\\", null, [
           _createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
         ]))
-      }), 128 /* UNKEYED_FRAGMENT */)
+      }), 128 /* UNKEYED_FRAGMENT */))
     ], 2 /* CLASS */)
   }
 }"
@@ -42,11 +42,11 @@ return function render() {
       : createBlock(Fragment, { key: 1 }, [
           \\"no\\"
         ])),
-    createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
+    (openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
       return (openBlock(), createBlock(\\"div\\", null, [
         createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */)
       ]))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   ], 2 /* CLASS */)
 }"
 `;
@@ -66,11 +66,11 @@ export default function render() {
       : createBlock(Fragment, { key: 1 }, [
           \\"no\\"
         ])),
-    createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
+    (openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
       return (openBlock(), createBlock(\\"div\\", null, [
         createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
       ]))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   ], 2 /* CLASS */)
 }"
 `;
index 29a751517b450d4087c8117fecbd260ce5183df9..c2df6a1206a1b809289fca31533a6091f7ee9006 100644 (file)
@@ -5,11 +5,11 @@ exports[`compiler: v-for codegen basic v-for 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
       return (_openBlock(), _createBlock(\\"span\\"))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -19,14 +19,14 @@ exports[`compiler: v-for codegen keyed template v-for 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
       return (_openBlock(), _createBlock(_Fragment, { key: item }, [
         \\"hello\\",
         _createVNode(\\"span\\")
       ]))
-    }), 64 /* KEYED_FRAGMENT */)
+    }), 64 /* KEYED_FRAGMENT */))
   }
 }"
 `;
@@ -36,11 +36,11 @@ exports[`compiler: v-for codegen keyed v-for 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
       return (_openBlock(), _createBlock(\\"span\\", { key: item }))
-    }), 64 /* KEYED_FRAGMENT */)
+    }), 64 /* KEYED_FRAGMENT */))
   }
 }"
 `;
@@ -50,11 +50,11 @@ exports[`compiler: v-for codegen skipped key 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item, __, index) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item, __, index) => {
       return (_openBlock(), _createBlock(\\"span\\"))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -64,11 +64,11 @@ exports[`compiler: v-for codegen skipped value & key 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (_, __, index) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, __, index) => {
       return (_openBlock(), _createBlock(\\"span\\"))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -78,11 +78,11 @@ exports[`compiler: v-for codegen skipped value 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (_, key, index) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, key, index) => {
       return (_openBlock(), _createBlock(\\"span\\"))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -92,14 +92,14 @@ exports[`compiler: v-for codegen template v-for 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
       return (_openBlock(), _createBlock(_Fragment, null, [
         \\"hello\\",
         _createVNode(\\"span\\")
       ]))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -109,11 +109,11 @@ exports[`compiler: v-for codegen template v-for w/ <slot/> 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, renderSlot: _renderSlot, openBlock: _openBlock, createBlock: _createBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, renderSlot: _renderSlot } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
       return (_openBlock(), _createBlock(_Fragment, null, _renderSlot($slots.default)))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
@@ -123,7 +123,7 @@ exports[`compiler: v-for codegen v-if + v-for 1`] = `
 
 return function render() {
   with (this) {
-    const { openBlock: _openBlock, renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, Empty: _Empty } = _Vue
+    const { openBlock: _openBlock, renderList: _renderList, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, Empty: _Empty } = _Vue
     
     return (_openBlock(), ok
       ? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
@@ -139,11 +139,11 @@ exports[`compiler: v-for codegen value + key + index 1`] = `
 
 return function render() {
   with (this) {
-    const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
+    const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode } = _Vue
     
-    return _createVNode(_Fragment, null, _renderList(items, (item, key, index) => {
+    return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item, key, index) => {
       return (_openBlock(), _createBlock(\\"span\\"))
-    }), 128 /* UNKEYED_FRAGMENT */)
+    }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
 `;
index 161a5e0b51505fbda25bf0a19bf2827d2d342d1e..0357443c2df3f67d5d1276d42de3f1867fd65d1a 100644 (file)
@@ -12,7 +12,8 @@ import {
   SimpleExpressionNode,
   ElementNode,
   InterpolationNode,
-  CallExpression
+  CallExpression,
+  SequenceExpression
 } from '../../src/ast'
 import { ErrorCodes } from '../../src/errors'
 import { CompilerOptions, generate } from '../../src'
@@ -21,7 +22,6 @@ import {
   CREATE_BLOCK,
   FRAGMENT,
   RENDER_LIST,
-  CREATE_VNODE,
   RENDER_SLOT
 } from '../../src/runtimeConstants'
 import { PatchFlags } from '@vue/runtime-dom'
@@ -565,46 +565,59 @@ describe('compiler: v-for', () => {
   })
 
   describe('codegen', () => {
-    function assertSharedCodegen(node: CallExpression, keyed: boolean = false) {
+    function assertSharedCodegen(
+      node: SequenceExpression,
+      keyed: boolean = false
+    ) {
       expect(node).toMatchObject({
-        type: NodeTypes.JS_CALL_EXPRESSION,
-        callee: `_${CREATE_VNODE}`,
-        arguments: [
-          `_${FRAGMENT}`,
-          `null`,
+        type: NodeTypes.JS_SEQUENCE_EXPRESSION,
+        expressions: [
+          {
+            type: NodeTypes.JS_CALL_EXPRESSION,
+            callee: `_${OPEN_BLOCK}`
+          },
           {
             type: NodeTypes.JS_CALL_EXPRESSION,
-            callee: `_${RENDER_LIST}`,
+            callee: `_${CREATE_BLOCK}`,
             arguments: [
-              {}, // to be asserted by each test
+              `_${FRAGMENT}`,
+              `null`,
               {
-                type: NodeTypes.JS_FUNCTION_EXPRESSION,
-                returns: {
-                  type: NodeTypes.JS_SEQUENCE_EXPRESSION,
-                  expressions: [
-                    {
-                      type: NodeTypes.JS_CALL_EXPRESSION,
-                      callee: `_${OPEN_BLOCK}`
-                    },
-                    {
-                      type: NodeTypes.JS_CALL_EXPRESSION,
-                      callee: `_${CREATE_BLOCK}`
+                type: NodeTypes.JS_CALL_EXPRESSION,
+                callee: `_${RENDER_LIST}`,
+                arguments: [
+                  {}, // to be asserted by each test
+                  {
+                    type: NodeTypes.JS_FUNCTION_EXPRESSION,
+                    returns: {
+                      type: NodeTypes.JS_SEQUENCE_EXPRESSION,
+                      expressions: [
+                        {
+                          type: NodeTypes.JS_CALL_EXPRESSION,
+                          callee: `_${OPEN_BLOCK}`
+                        },
+                        {
+                          type: NodeTypes.JS_CALL_EXPRESSION,
+                          callee: `_${CREATE_BLOCK}`
+                        }
+                      ]
                     }
-                  ]
-                }
-              }
+                  }
+                ]
+              },
+              keyed
+                ? `${PatchFlags.KEYED_FRAGMENT} /* ${
+                    PatchFlagNames[PatchFlags.KEYED_FRAGMENT]
+                  } */`
+                : `${PatchFlags.UNKEYED_FRAGMENT} /* ${
+                    PatchFlagNames[PatchFlags.UNKEYED_FRAGMENT]
+                  } */`
             ]
-          },
-          keyed
-            ? `${PatchFlags.KEYED_FRAGMENT} /* ${
-                PatchFlagNames[PatchFlags.KEYED_FRAGMENT]
-              } */`
-            : `${PatchFlags.UNKEYED_FRAGMENT} /* ${
-                PatchFlagNames[PatchFlags.UNKEYED_FRAGMENT]
-              } */`
+          }
         ]
       })
-      const renderListArgs = (node.arguments[2] as CallExpression).arguments
+      const renderListArgs = ((node.expressions[1] as CallExpression)
+        .arguments[2] as CallExpression).arguments
       return {
         source: renderListArgs[0] as SimpleExpressionNode,
         params: (renderListArgs[1] as any).params,
index c0941afc375eaa8126f7dab2fa1deb880f5ba6c0..52cda7aeacd89d4da16a2f26a5f29e4663f2561b 100644 (file)
@@ -158,7 +158,7 @@ export interface ForNode extends Node {
   keyAlias: ExpressionNode | undefined
   objectIndexAlias: ExpressionNode | undefined
   children: TemplateChildNode[]
-  codegenNode: CallExpression
+  codegenNode: SequenceExpression
 }
 
 // We also include a number of JavaScript AST nodes for code generation.
index e73e280ee7e43f3c21f738ee95e7cbd30543aa5b..1abc4994eb17631a89fbf4e8ee146413b1b63b77 100644 (file)
@@ -24,8 +24,7 @@ import {
   RENDER_LIST,
   OPEN_BLOCK,
   CREATE_BLOCK,
-  FRAGMENT,
-  CREATE_VNODE
+  FRAGMENT
 } from '../runtimeConstants'
 import { processExpression } from './transformExpression'
 import { PatchFlags, PatchFlagNames } from '@vue/shared'
@@ -52,12 +51,15 @@ export const transformFor = createStructuralDirectiveTransform(
         const fragmentFlag = keyProp
           ? PatchFlags.KEYED_FRAGMENT
           : PatchFlags.UNKEYED_FRAGMENT
-        const codegenNode = createCallExpression(helper(CREATE_VNODE), [
-          helper(FRAGMENT),
-          `null`,
-          renderExp,
-          fragmentFlag +
-            (__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``)
+        const codegenNode = createSequenceExpression([
+          createCallExpression(helper(OPEN_BLOCK)),
+          createCallExpression(helper(CREATE_BLOCK), [
+            helper(FRAGMENT),
+            `null`,
+            renderExp,
+            fragmentFlag +
+              (__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``)
+          ])
         ])
 
         context.replaceNode({
index 404662702f0143c852f595fe26a4a7a6a1236a13..24760e472bcfcd48d22bd672f425239e7c8377d0 100644 (file)
@@ -176,7 +176,8 @@ function createChildrenCodegenNode(
     if (children.length === 1) {
       // optimize away nested fragments when child is a ForNode
       if (child.type === NodeTypes.FOR) {
-        const forBlockArgs = child.codegenNode.arguments
+        const forBlockArgs = (child.codegenNode
+          .expressions[1] as CallExpression).arguments
         // directly use the for block's children and patchFlag
         blockArgs[2] = forBlockArgs[2]
         blockArgs[3] = forBlockArgs[3]