perf: improve VNode creation performance with compiler hints (#3334)

This commit is contained in:
HcySunYang
2021-06-23 07:15:20 +08:00
committed by Evan You
parent 31abdc8ada
commit ceff89905b
42 changed files with 1130 additions and 685 deletions

View File

@@ -30,9 +30,16 @@ import {
SUSPENSE,
KEEP_ALIVE,
BASE_TRANSITION,
TO_HANDLERS
TO_HANDLERS,
NORMALIZE_PROPS,
GUARD_REACTIVE_PROPS,
CREATE_BLOCK,
CREATE_ELEMENT_BLOCK,
CREATE_VNODE,
CREATE_ELEMENT_VNODE
} from './runtimeHelpers'
import { isString, isObject, hyphenate, extend } from '@vue/shared'
import { PropsExpression } from './transforms/transformElement'
export const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
p.type === NodeTypes.SIMPLE_EXPRESSION && p.isStatic
@@ -291,14 +298,66 @@ export function isSlotOutlet(
return node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.SLOT
}
export function getVNodeHelper(ssr: boolean, isComponent: boolean) {
return ssr || isComponent ? CREATE_VNODE : CREATE_ELEMENT_VNODE
}
export function getVNodeBlockHelper(ssr: boolean, isComponent: boolean) {
return ssr || isComponent ? CREATE_BLOCK : CREATE_ELEMENT_BLOCK
}
const propsHelperSet = new Set([NORMALIZE_PROPS, GUARD_REACTIVE_PROPS])
function getUnnormalizedProps(
props: PropsExpression | '{}',
callPath: CallExpression[] = []
): [PropsExpression | '{}', CallExpression[]] {
if (
props &&
!isString(props) &&
props.type === NodeTypes.JS_CALL_EXPRESSION
) {
const callee = props.callee
if (!isString(callee) && propsHelperSet.has(callee)) {
return getUnnormalizedProps(
props.arguments[0] as PropsExpression,
callPath.concat(props)
)
}
}
return [props, callPath]
}
export function injectProp(
node: VNodeCall | RenderSlotCall,
prop: Property,
context: TransformContext
) {
let propsWithInjection: ObjectExpression | CallExpression | undefined
const props =
const originalProps =
node.type === NodeTypes.VNODE_CALL ? node.props : node.arguments[2]
/**
* 1. mergeProps(...)
* 2. toHandlers(...)
* 3. normalizeProps(...)
* 4. normalizeProps(guardReactiveProps(...))
*
* we need to get the real props before normalization
*/
let props = originalProps
let callPath: CallExpression[] = []
let parentCall: CallExpression | undefined
if (
props &&
!isString(props) &&
props.type === NodeTypes.JS_CALL_EXPRESSION
) {
const ret = getUnnormalizedProps(props)
props = ret[0]
callPath = ret[1]
parentCall = callPath[callPath.length - 1]
}
if (props == null || isString(props)) {
propsWithInjection = createObjectExpression([prop])
} else if (props.type === NodeTypes.JS_CALL_EXPRESSION) {
@@ -341,11 +400,25 @@ export function injectProp(
createObjectExpression([prop]),
props
])
// in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(props))`,
// it will be rewritten as `normalizeProps(mergeProps({ key: 0 }, props))`,
// the `guardReactiveProps` will no longer be needed
if (parentCall && parentCall.callee === GUARD_REACTIVE_PROPS) {
parentCall = callPath[callPath.length - 2]
}
}
if (node.type === NodeTypes.VNODE_CALL) {
node.props = propsWithInjection
if (parentCall) {
parentCall.arguments[0] = propsWithInjection
} else {
node.props = propsWithInjection
}
} else {
node.arguments[2] = propsWithInjection
if (parentCall) {
parentCall.arguments[0] = propsWithInjection
} else {
node.arguments[2] = propsWithInjection
}
}
}