feat(compiler-core): do not generate TEXT flag if child is constant
This commit is contained in:
		
							parent
							
								
									6607edab2d
								
							
						
					
					
						commit
						6a75c3463b
					
				| @ -190,7 +190,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t | ||||
| "const _Vue = Vue | ||||
| const _createVNode = Vue.createVNode | ||||
| 
 | ||||
| const _hoisted_1 = _createVNode(\\"span\\", { foo: 0 }, _toString(1), 1 /* TEXT */) | ||||
| const _hoisted_1 = _createVNode(\\"span\\", { foo: 0 }, _toString(1)) | ||||
| 
 | ||||
| return function render() { | ||||
|   with (this) { | ||||
| @ -300,6 +300,20 @@ return function render() { | ||||
| }" | ||||
| `; | ||||
| 
 | ||||
| exports[`compiler: hoistStatic transform should NOT hoist element with dynamic ref 1`] = ` | ||||
| "const _Vue = Vue | ||||
| 
 | ||||
| return function render() { | ||||
|   with (this) { | ||||
|     const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue | ||||
|      | ||||
|     return (_openBlock(), _createBlock(\\"div\\", null, [ | ||||
|       _createVNode(\\"div\\", { ref: foo }, null, 32 /* NEED_PATCH */) | ||||
|     ])) | ||||
|   } | ||||
| }" | ||||
| `; | ||||
| 
 | ||||
| exports[`compiler: hoistStatic transform should NOT hoist root node 1`] = ` | ||||
| "const _Vue = Vue | ||||
| 
 | ||||
|  | ||||
| @ -273,6 +273,28 @@ describe('compiler: hoistStatic transform', () => { | ||||
|     expect(generate(root).code).toMatchSnapshot() | ||||
|   }) | ||||
| 
 | ||||
|   test('should NOT hoist element with dynamic ref', () => { | ||||
|     const { root, args } = transformWithHoist(`<div><div :ref="foo"/></div>`) | ||||
|     expect(root.hoists.length).toBe(0) | ||||
|     expect(args[2]).toMatchObject([ | ||||
|       { | ||||
|         type: NodeTypes.ELEMENT, | ||||
|         codegenNode: { | ||||
|           callee: CREATE_VNODE, | ||||
|           arguments: [ | ||||
|             `"div"`, | ||||
|             createObjectMatcher({ | ||||
|               ref: `[foo]` | ||||
|             }), | ||||
|             `null`, | ||||
|             genFlagText(PatchFlags.NEED_PATCH) | ||||
|           ] | ||||
|         } | ||||
|       } | ||||
|     ]) | ||||
|     expect(generate(root).code).toMatchSnapshot() | ||||
|   }) | ||||
| 
 | ||||
|   test('hoist static props for elements with directives', () => { | ||||
|     const { root, args } = transformWithHoist( | ||||
|       `<div><div id="foo" v-foo/></div>` | ||||
| @ -521,8 +543,7 @@ describe('compiler: hoistStatic transform', () => { | ||||
|                 isStatic: false, | ||||
|                 isConstant: true | ||||
|               } | ||||
|             }, | ||||
|             '1 /* TEXT */' | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|       ]) | ||||
|  | ||||
| @ -15,9 +15,8 @@ import { APPLY_DIRECTIVES } from '../runtimeHelpers' | ||||
| import { PatchFlags, isString, isSymbol } from '@vue/shared' | ||||
| import { isSlotOutlet, findProp } from '../utils' | ||||
| 
 | ||||
| function hasDynamicKey(node: ElementNode) { | ||||
|   const keyProp = findProp(node, 'key') | ||||
|   return keyProp && keyProp.type === NodeTypes.DIRECTIVE | ||||
| function hasDynamicKeyOrRef(node: ElementNode) { | ||||
|   return findProp(node, 'key', true) || findProp(node, 'ref', true) | ||||
| } | ||||
| 
 | ||||
| export function hoistStatic(root: RootNode, context: TransformContext) { | ||||
| @ -57,7 +56,7 @@ function walk( | ||||
|       if ( | ||||
|         !doNotHoistNode && | ||||
|         isStaticNode(child, resultCache) && | ||||
|         !hasDynamicKey(child) | ||||
|         !hasDynamicKeyOrRef(child) | ||||
|       ) { | ||||
|         // whole tree is static
 | ||||
|         child.codegenNode = context.hoist(child.codegenNode!) | ||||
| @ -70,7 +69,7 @@ function walk( | ||||
|           (!flag || | ||||
|             flag === PatchFlags.NEED_PATCH || | ||||
|             flag === PatchFlags.TEXT) && | ||||
|           !hasDynamicKey(child) | ||||
|           !hasDynamicKeyOrRef(child) | ||||
|         ) { | ||||
|           let codegenNode = child.codegenNode as ElementCodegenNode | ||||
|           if (codegenNode.callee === APPLY_DIRECTIVES) { | ||||
| @ -107,9 +106,9 @@ function getPatchFlag(node: PlainElementNode): number | undefined { | ||||
|   return flag ? parseInt(flag, 10) : undefined | ||||
| } | ||||
| 
 | ||||
| function isStaticNode( | ||||
| export function isStaticNode( | ||||
|   node: TemplateChildNode | SimpleExpressionNode, | ||||
|   resultCache: Map<TemplateChildNode, boolean> | ||||
|   resultCache: Map<TemplateChildNode, boolean> = new Map() | ||||
| ): boolean { | ||||
|   switch (node.type) { | ||||
|     case NodeTypes.ELEMENT: | ||||
| @ -121,7 +120,7 @@ function isStaticNode( | ||||
|         return cached | ||||
|       } | ||||
|       const flag = getPatchFlag(node) | ||||
|       if (!flag || flag === PatchFlags.TEXT) { | ||||
|       if (!flag) { | ||||
|         // element self is static. check its children.
 | ||||
|         for (let i = 0; i < node.children.length; i++) { | ||||
|           if (!isStaticNode(node.children[i], resultCache)) { | ||||
|  | ||||
| @ -28,6 +28,7 @@ import { | ||||
| } from '../runtimeHelpers' | ||||
| import { getInnerRange, isVSlot, toValidAssetId } from '../utils' | ||||
| import { buildSlots } from './vSlot' | ||||
| import { isStaticNode } from './hoistStatic' | ||||
| 
 | ||||
| // some directive transforms (e.g. v-model) may return a symbol for runtime
 | ||||
| // import, which should be used instead of a resolveDirective call.
 | ||||
| @ -93,10 +94,11 @@ export const transformElement: NodeTransform = (node, context) => { | ||||
|           } else if (node.children.length === 1) { | ||||
|             const child = node.children[0] | ||||
|             const type = child.type | ||||
|             // check for dynamic text children
 | ||||
|             const hasDynamicTextChild = | ||||
|               type === NodeTypes.INTERPOLATION || | ||||
|               type === NodeTypes.COMPOUND_EXPRESSION | ||||
|             if (hasDynamicTextChild) { | ||||
|             if (hasDynamicTextChild && !isStaticNode(child)) { | ||||
|               patchFlag |= PatchFlags.TEXT | ||||
|             } | ||||
|             // pass directly if the only child is a text node
 | ||||
|  | ||||
| @ -156,15 +156,18 @@ export function findDir( | ||||
| 
 | ||||
| export function findProp( | ||||
|   node: ElementNode, | ||||
|   name: string | ||||
|   name: string, | ||||
|   dynamicOnly: boolean = false | ||||
| ): ElementNode['props'][0] | undefined { | ||||
|   for (let i = 0; i < node.props.length; i++) { | ||||
|     const p = node.props[i] | ||||
|     if (p.type === NodeTypes.ATTRIBUTE) { | ||||
|       if (dynamicOnly) continue | ||||
|       if (p.name === name && p.value && !p.value.isEmpty) { | ||||
|         return p | ||||
|       } | ||||
|     } else if ( | ||||
|       p.name === 'bind' && | ||||
|       p.arg && | ||||
|       p.arg.type === NodeTypes.SIMPLE_EXPRESSION && | ||||
|       p.arg.isStatic && | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user