]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(compiler): generate TEXT patchFlag
authorEvan You <yyx990803@gmail.com>
Wed, 2 Oct 2019 04:19:23 +0000 (00:19 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 2 Oct 2019 04:19:23 +0000 (00:19 -0400)
packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/__tests__/transforms/vSlot.spec.ts
packages/compiler-core/src/transforms/transformElement.ts

index 99b7dd6c0648a07e5a091d70afd4b3668a65ac86..9bf7229e51fd7f4ddc007e10e3e233acf95d5d0c 100644 (file)
@@ -5,7 +5,7 @@ exports[`compiler: integration tests function mode 1`] = `
 
 return function render() {
   with (this) {
-    const { createVNode: _createVNode, toString: _toString, openBlock: _openBlock, createBlock: _createBlock, Empty: _Empty, Fragment: _Fragment, renderList: _renderList } = _Vue
+    const { toString: _toString, openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Empty: _Empty, Fragment: _Fragment, renderList: _renderList } = _Vue
     
     return _createVNode(\\"div\\", {
       id: \\"foo\\",
@@ -19,7 +19,7 @@ return function render() {
           ])),
       _createVNode(_Fragment, null, _renderList(list, (value, index) => {
         return (_openBlock(), _createBlock(\\"div\\", null, [
-          _createVNode(\\"span\\", null, _toString(value + index))
+          _createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
         ]))
       }), 128 /* UNKEYED_FRAGMENT */)
     ], 2 /* CLASS */)
@@ -28,7 +28,7 @@ return function render() {
 `;
 
 exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
-"const { createVNode, toString, openBlock, createBlock, Empty, Fragment, renderList } = Vue
+"const { toString, openBlock, createVNode, createBlock, Empty, Fragment, renderList } = Vue
 
 return function render() {
   const _ctx = this
@@ -44,7 +44,7 @@ return function render() {
         ])),
     createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
       return (openBlock(), createBlock(\\"div\\", null, [
-        createVNode(\\"span\\", null, toString(value + index))
+        createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */)
       ]))
     }), 128 /* UNKEYED_FRAGMENT */)
   ], 2 /* CLASS */)
@@ -52,7 +52,7 @@ return function render() {
 `;
 
 exports[`compiler: integration tests module mode 1`] = `
-"import { createVNode, toString, openBlock, createBlock, Empty, Fragment, renderList } from \\"vue\\"
+"import { toString, openBlock, createVNode, createBlock, Empty, Fragment, renderList } from \\"vue\\"
 
 export default function render() {
   const _ctx = this
@@ -68,7 +68,7 @@ export default function render() {
         ])),
     createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
       return (openBlock(), createBlock(\\"div\\", null, [
-        createVNode(\\"span\\", null, _toString(value + index))
+        createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
       ]))
     }), 128 /* UNKEYED_FRAGMENT */)
   ], 2 /* CLASS */)
index 03ab9da4b637ee89c2d23e036c7639d54d3b9e80..d1810ae7ab08161f7f0fdd3d81fa98cef99efecc 100644 (file)
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`compiler: transform component slots dynamically named slots 1`] = `
-"const { resolveComponent, createVNode, toString } = Vue
+"const { toString, resolveComponent, createVNode } = Vue
 
 return function render() {
   const _ctx = this
@@ -21,7 +21,7 @@ return function render() {
 `;
 
 exports[`compiler: transform component slots explicit default slot 1`] = `
-"const { resolveComponent, createVNode, toString } = Vue
+"const { toString, resolveComponent, createVNode } = Vue
 
 return function render() {
   const _ctx = this
@@ -37,7 +37,7 @@ return function render() {
 `;
 
 exports[`compiler: transform component slots implicit default slot 1`] = `
-"const { resolveComponent, createVNode } = Vue
+"const { createVNode, resolveComponent } = Vue
 
 return function render() {
   const _ctx = this
@@ -52,7 +52,7 @@ return function render() {
 `;
 
 exports[`compiler: transform component slots named slots 1`] = `
-"const { resolveComponent, createVNode, toString } = Vue
+"const { toString, resolveComponent, createVNode } = Vue
 
 return function render() {
   const _ctx = this
@@ -72,12 +72,12 @@ return function render() {
 `;
 
 exports[`compiler: transform component slots nested slots scoping 1`] = `
-"const { resolveComponent, createVNode, toString } = Vue
+"const { toString, resolveComponent, createVNode } = Vue
 
 return function render() {
   const _ctx = this
-  const _component_Comp = resolveComponent(\\"Comp\\")
   const _component_Inner = resolveComponent(\\"Inner\\")
+  const _component_Comp = resolveComponent(\\"Comp\\")
   
   return createVNode(_component_Comp, null, {
     default: ({ foo }) => [
index 7d2793c9b1a1141bd0f725e194308ab1cbc77176..f2aed954ee919f7b15b188aeacd826a701d1320c 100644 (file)
@@ -26,6 +26,7 @@ import { transformStyle } from '../../src/transforms/transformStyle'
 import { transformBind } from '../../src/transforms/vBind'
 import { PatchFlags } from '@vue/shared'
 import { createObjectMatcher } from '../testUtils'
+import { optimizeText } from '../../src/transforms/optimizeText'
 
 function parseWithElementTransform(
   template: string,
@@ -36,7 +37,7 @@ function parseWithElementTransform(
 } {
   const ast = parse(template, options)
   transform(ast, {
-    nodeTransforms: [transformElement],
+    nodeTransforms: [optimizeText, transformElement],
     ...options
   })
   const codegenNode = (ast.children[0] as ElementNode)
@@ -562,6 +563,20 @@ describe('compiler: element transform', () => {
       })
     }
 
+    test('TEXT', () => {
+      const { node } = parseWithBind(`<div>foo</div>`)
+      expect(node.arguments.length).toBe(3)
+
+      const { node: node2 } = parseWithBind(`<div>{{ foo }}</div>`)
+      expect(node2.arguments.length).toBe(4)
+      expect(node2.arguments[3]).toBe(`${PatchFlags.TEXT} /* TEXT */`)
+
+      // multiple nodes, merged with optimze text
+      const { node: node3 } = parseWithBind(`<div>foo {{ bar }} baz</div>`)
+      expect(node3.arguments.length).toBe(4)
+      expect(node3.arguments[3]).toBe(`${PatchFlags.TEXT} /* TEXT */`)
+    })
+
     test('CLASS', () => {
       const { node } = parseWithBind(`<div :class="foo" />`)
       expect(node.arguments.length).toBe(4)
index 93fc5329c5b211a6af69dc0a776a8255d57bd5d0..f2f2ad817d8c2417d647b30e3e7c00aecde5f6ec 100644 (file)
@@ -123,9 +123,8 @@ describe('compiler: transform component slots', () => {
         one: {
           type: NodeTypes.JS_FUNCTION_EXPRESSION,
           params: {
-            type: NodeTypes.SIMPLE_EXPRESSION,
-            content: `{ foo }`,
-            isStatic: false
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [`{ `, { content: `foo` }, ` }`]
           },
           returns: [
             {
@@ -145,9 +144,8 @@ describe('compiler: transform component slots', () => {
         two: {
           type: NodeTypes.JS_FUNCTION_EXPRESSION,
           params: {
-            type: NodeTypes.SIMPLE_EXPRESSION,
-            content: `{ bar }`,
-            isStatic: false
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [`{ `, { content: `bar` }, ` }`]
           },
           returns: [
             {
@@ -186,9 +184,8 @@ describe('compiler: transform component slots', () => {
         '[_ctx.one]': {
           type: NodeTypes.JS_FUNCTION_EXPRESSION,
           params: {
-            type: NodeTypes.SIMPLE_EXPRESSION,
-            content: `{ foo }`,
-            isStatic: false
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [`{ `, { content: `foo` }, ` }`]
           },
           returns: [
             {
@@ -208,9 +205,8 @@ describe('compiler: transform component slots', () => {
         '[_ctx.two]': {
           type: NodeTypes.JS_FUNCTION_EXPRESSION,
           params: {
-            type: NodeTypes.SIMPLE_EXPRESSION,
-            content: `{ bar }`,
-            isStatic: false
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [`{ `, { content: `bar` }, ` }`]
           },
           returns: [
             {
@@ -249,9 +245,8 @@ describe('compiler: transform component slots', () => {
         default: {
           type: NodeTypes.JS_FUNCTION_EXPRESSION,
           params: {
-            type: NodeTypes.SIMPLE_EXPRESSION,
-            content: `{ foo }`,
-            isStatic: false
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [`{ `, { content: `foo` }, ` }`]
           },
           returns: [
             {
index 26d10f77efa4ef44b5e29e439f219f8677f93373..70733b3f88719ee349a6508f757b0dc6c0dc9aa0 100644 (file)
@@ -38,65 +38,72 @@ export const transformElement: NodeTransform = (node, context) => {
       node.tagType === ElementTypes.ELEMENT ||
       node.tagType === ElementTypes.COMPONENT
     ) {
-      const isComponent = node.tagType === ElementTypes.COMPONENT
-      let hasProps = node.props.length > 0
-      const hasChildren = node.children.length > 0
-      let patchFlag: number = 0
-      let runtimeDirectives: DirectiveNode[] | undefined
-      let dynamicPropNames: string[] | undefined
-      let componentIdentifier: string | undefined
+      // perform the work on exit, after all child expressions have been
+      // processed and merged.
+      return () => {
+        const isComponent = node.tagType === ElementTypes.COMPONENT
+        let hasProps = node.props.length > 0
+        const hasChildren = node.children.length > 0
+        let patchFlag: number = 0
+        let runtimeDirectives: DirectiveNode[] | undefined
+        let dynamicPropNames: string[] | undefined
+        let componentIdentifier: string | undefined
 
-      if (isComponent) {
-        componentIdentifier = `_component_${toValidId(node.tag)}`
-        context.statements.add(
-          `const ${componentIdentifier} = ${context.helper(
-            RESOLVE_COMPONENT
-          )}(${JSON.stringify(node.tag)})`
-        )
-      }
-
-      const args: CallExpression['arguments'] = [
-        isComponent ? componentIdentifier! : `"${node.tag}"`
-      ]
-      // props
-      if (hasProps) {
-        const propsBuildResult = buildProps(
-          node.props,
-          node.loc,
-          context,
-          isComponent
-        )
-        patchFlag = propsBuildResult.patchFlag
-        dynamicPropNames = propsBuildResult.dynamicPropNames
-        runtimeDirectives = propsBuildResult.directives
-        if (!propsBuildResult.props) {
-          hasProps = false
-        } else {
-          args.push(propsBuildResult.props)
+        if (isComponent) {
+          componentIdentifier = `_component_${toValidId(node.tag)}`
+          context.statements.add(
+            `const ${componentIdentifier} = ${context.helper(
+              RESOLVE_COMPONENT
+            )}(${JSON.stringify(node.tag)})`
+          )
         }
-      }
-      // children
-      if (hasChildren) {
-        if (!hasProps) {
-          args.push(`null`)
+
+        const args: CallExpression['arguments'] = [
+          isComponent ? componentIdentifier! : `"${node.tag}"`
+        ]
+        // props
+        if (hasProps) {
+          const propsBuildResult = buildProps(
+            node.props,
+            node.loc,
+            context,
+            isComponent
+          )
+          patchFlag = propsBuildResult.patchFlag
+          dynamicPropNames = propsBuildResult.dynamicPropNames
+          runtimeDirectives = propsBuildResult.directives
+          if (!propsBuildResult.props) {
+            hasProps = false
+          } else {
+            args.push(propsBuildResult.props)
+          }
         }
-        if (isComponent) {
-          const { slots, hasDynamicSlotName } = buildSlots(node, context)
-          args.push(slots)
-          if (hasDynamicSlotName) {
-            patchFlag |= PatchFlags.DYNAMIC_SLOTS
+        // children
+        if (hasChildren) {
+          if (!hasProps) {
+            args.push(`null`)
           }
-        } else {
-          if (node.children.length === 1) {
+          if (isComponent) {
+            const { slots, hasDynamicSlotName } = buildSlots(node, context)
+            args.push(slots)
+            if (hasDynamicSlotName) {
+              patchFlag |= PatchFlags.DYNAMIC_SLOTS
+            }
+          } else if (node.children.length === 1) {
             const child = node.children[0]
             const type = child.type
+            const hasDynamicTextChild =
+              type === NodeTypes.INTERPOLATION ||
+              type === NodeTypes.COMPOUND_EXPRESSION
+            if (hasDynamicTextChild) {
+              patchFlag |= PatchFlags.TEXT
+            }
             // pass directly if the only child is one of:
             // - text (plain / interpolation / expression)
             // - <slot> outlet (already an array)
             if (
               type === NodeTypes.TEXT ||
-              type === NodeTypes.INTERPOLATION ||
-              type === NodeTypes.COMPOUND_EXPRESSION ||
+              hasDynamicTextChild ||
               (type === NodeTypes.ELEMENT &&
                 (child as ElementNode).tagType === ElementTypes.SLOT)
             ) {
@@ -108,54 +115,54 @@ export const transformElement: NodeTransform = (node, context) => {
             args.push(node.children)
           }
         }
-      }
-      // patchFlag & dynamicPropNames
-      if (patchFlag !== 0) {
-        if (!hasChildren) {
-          if (!hasProps) {
+        // patchFlag & dynamicPropNames
+        if (patchFlag !== 0) {
+          if (!hasChildren) {
+            if (!hasProps) {
+              args.push(`null`)
+            }
             args.push(`null`)
           }
-          args.push(`null`)
-        }
-        if (__DEV__) {
-          const flagNames = Object.keys(PatchFlagNames)
-            .filter(n => patchFlag & Number(n))
-            .map(n => PatchFlagNames[n as any])
-            .join(`, `)
-          args.push(patchFlag + ` /* ${flagNames} */`)
-        } else {
-          args.push(patchFlag + '')
-        }
-        if (dynamicPropNames && dynamicPropNames.length) {
-          args.push(
-            `[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`
-          )
+          if (__DEV__) {
+            const flagNames = Object.keys(PatchFlagNames)
+              .filter(n => patchFlag & Number(n))
+              .map(n => PatchFlagNames[n as any])
+              .join(`, `)
+            args.push(patchFlag + ` /* ${flagNames} */`)
+          } else {
+            args.push(patchFlag + '')
+          }
+          if (dynamicPropNames && dynamicPropNames.length) {
+            args.push(
+              `[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`
+            )
+          }
         }
-      }
 
-      const { loc } = node
-      const vnode = createCallExpression(
-        context.helper(CREATE_VNODE),
-        args,
-        loc
-      )
-
-      if (runtimeDirectives && runtimeDirectives.length) {
-        node.codegenNode = createCallExpression(
-          context.helper(APPLY_DIRECTIVES),
-          [
-            vnode,
-            createArrayExpression(
-              runtimeDirectives.map(dir => {
-                return createDirectiveArgs(dir, context)
-              }),
-              loc
-            )
-          ],
+        const { loc } = node
+        const vnode = createCallExpression(
+          context.helper(CREATE_VNODE),
+          args,
           loc
         )
-      } else {
-        node.codegenNode = vnode
+
+        if (runtimeDirectives && runtimeDirectives.length) {
+          node.codegenNode = createCallExpression(
+            context.helper(APPLY_DIRECTIVES),
+            [
+              vnode,
+              createArrayExpression(
+                runtimeDirectives.map(dir => {
+                  return createDirectiveArgs(dir, context)
+                }),
+                loc
+              )
+            ],
+            loc
+          )
+        } else {
+          node.codegenNode = vnode
+        }
       }
     }
   }