From 3f37cf79616208cf03cff69c1fd898f1e53a5034 Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Sat, 20 Jul 2024 01:48:41 +0100 Subject: [PATCH 1/2] perf(runtime-core): improve efficiency of normalizePropsOptions --- packages/runtime-core/src/componentProps.ts | 61 ++++++++++----------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 9d7b7f0e4a5..216dc6e2da8 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -174,12 +174,10 @@ export type ExtractDefaultPropTypes = O extends object { [K in keyof Pick>]: InferPropType } : {} -type NormalizedProp = - | null - | (PropOptions & { - [BooleanFlags.shouldCast]?: boolean - [BooleanFlags.shouldCastTrue]?: boolean - }) +type NormalizedProp = PropOptions & { + [BooleanFlags.shouldCast]?: boolean + [BooleanFlags.shouldCastTrue]?: boolean +} // normalized value is a tuple of the actual normalized options // and an array of prop keys that need value casting (booleans and defaults) @@ -564,16 +562,32 @@ export function normalizePropsOptions( const opt = raw[key] const prop: NormalizedProp = (normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt)) - if (prop) { - const booleanIndex = getTypeIndex(Boolean, prop.type) - const stringIndex = getTypeIndex(String, prop.type) - prop[BooleanFlags.shouldCast] = booleanIndex > -1 - prop[BooleanFlags.shouldCastTrue] = - stringIndex < 0 || booleanIndex < stringIndex - // if the prop needs boolean casting or default value - if (booleanIndex > -1 || hasOwn(prop, 'default')) { - needCastKeys.push(normalizedKey) + const propType = prop.type + let shouldCastTrue = true + + const checkForBoolean = ( + type: PropConstructor | true | null | undefined, + ) => { + const typeName = isFunction(type) && type.name + + // If we find `String` before `Boolean`, e.g. `[String, Boolean]`, we need to handle the casting slightly + // differently. Props passed as `` or `` will either be treated as + // strings or converted to a boolean `true`, depending on the order of the types. + if (typeName === 'String') { + shouldCastTrue = false } + + return typeName === 'Boolean' + } + + const shouldCast = isArray(propType) + ? propType.some(checkForBoolean) + : checkForBoolean(propType) + prop[BooleanFlags.shouldCast] = shouldCast + prop[BooleanFlags.shouldCastTrue] = shouldCastTrue + // if the prop needs boolean casting or default value + if (shouldCast || hasOwn(prop, 'default')) { + needCastKeys.push(normalizedKey) } } } @@ -595,6 +609,7 @@ function validatePropName(key: string) { return false } +// dev only // use function string name to check type constructors // so that it works across vms / iframes. function getType(ctor: Prop): string { @@ -617,22 +632,6 @@ function getType(ctor: Prop): string { return '' } -function isSameType(a: Prop, b: Prop): boolean { - return getType(a) === getType(b) -} - -function getTypeIndex( - type: Prop, - expectedTypes: PropType | void | null | true, -): number { - if (isArray(expectedTypes)) { - return expectedTypes.findIndex(t => isSameType(t, type)) - } else if (isFunction(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1 - } - return -1 -} - /** * dev only */ From e0be33da06127b2e01abfae46728633b74bffddf Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Sat, 20 Jul 2024 05:18:22 +0100 Subject: [PATCH 2/2] Further performance improvements --- packages/runtime-core/src/componentProps.ts | 34 ++++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 216dc6e2da8..ce39f150ef5 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -563,26 +563,30 @@ export function normalizePropsOptions( const prop: NormalizedProp = (normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt)) const propType = prop.type + let shouldCast = false let shouldCastTrue = true - const checkForBoolean = ( - type: PropConstructor | true | null | undefined, - ) => { - const typeName = isFunction(type) && type.name - - // If we find `String` before `Boolean`, e.g. `[String, Boolean]`, we need to handle the casting slightly - // differently. Props passed as `` or `` will either be treated as - // strings or converted to a boolean `true`, depending on the order of the types. - if (typeName === 'String') { - shouldCastTrue = false + if (isArray(propType)) { + for (let index = 0; index < propType.length; ++index) { + const type = propType[index] + const typeName = isFunction(type) && type.name + + if (typeName === 'Boolean') { + shouldCast = true + break + } else if (typeName === 'String') { + // If we find `String` before `Boolean`, e.g. `[String, Boolean]`, + // we need to handle the casting slightly differently. Props + // passed as `` or `` + // will either be treated as strings or converted to a boolean + // `true`, depending on the order of the types. + shouldCastTrue = false + } } - - return typeName === 'Boolean' + } else { + shouldCast = isFunction(propType) && propType.name === 'Boolean' } - const shouldCast = isArray(propType) - ? propType.some(checkForBoolean) - : checkForBoolean(propType) prop[BooleanFlags.shouldCast] = shouldCast prop[BooleanFlags.shouldCastTrue] = shouldCastTrue // if the prop needs boolean casting or default value