perf: avoid deopt for props/emits normalization when global mixins are used

This commit is contained in:
Evan You 2021-06-02 15:22:52 -04:00
parent e2ca67b59a
commit 51d2be2038
5 changed files with 35 additions and 28 deletions

View File

@ -20,6 +20,8 @@ import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
import { isFunction, NO, isObject } from '@vue/shared' import { isFunction, NO, isObject } from '@vue/shared'
import { version } from '.' import { version } from '.'
import { installAppCompatProperties } from './compat/global' import { installAppCompatProperties } from './compat/global'
import { NormalizedPropsOptions } from './componentProps'
import { ObjectEmitsOptions } from './componentEmits'
export interface App<HostElement = any> { export interface App<HostElement = any> {
version: string version: string
@ -101,13 +103,19 @@ export interface AppContext {
* Cache for merged/normalized component options * Cache for merged/normalized component options
* Each app instance has its own cache because app-level global mixins and * Each app instance has its own cache because app-level global mixins and
* optionMergeStrategies can affect merge behavior. * optionMergeStrategies can affect merge behavior.
*/
cache: WeakMap<ComponentOptions, MergedComponentOptions>
/**
* Flag for de-optimizing props normalization
* @internal * @internal
*/ */
deopt?: boolean optionsCache: WeakMap<ComponentOptions, MergedComponentOptions>
/**
* Cache for normalized props options
* @internal
*/
propsCache: WeakMap<ConcreteComponent, NormalizedPropsOptions>
/**
* Cache for normalized emits options
* @internal
*/
emitsCache: WeakMap<ConcreteComponent, ObjectEmitsOptions | null>
/** /**
* HMR only * HMR only
* @internal * @internal
@ -144,7 +152,9 @@ export function createAppContext(): AppContext {
components: {}, components: {},
directives: {}, directives: {},
provides: Object.create(null), provides: Object.create(null),
cache: new WeakMap() optionsCache: new WeakMap(),
propsCache: new WeakMap(),
emitsCache: new WeakMap()
} }
} }
@ -213,11 +223,6 @@ export function createAppAPI<HostElement>(
if (__FEATURE_OPTIONS_API__) { if (__FEATURE_OPTIONS_API__) {
if (!context.mixins.includes(mixin)) { if (!context.mixins.includes(mixin)) {
context.mixins.push(mixin) context.mixins.push(mixin)
// global mixin with props/emits de-optimizes props/emits
// normalization caching.
if (mixin.props || mixin.emits) {
context.deopt = true
}
} else if (__DEV__) { } else if (__DEV__) {
warn( warn(
'Mixin has already been applied to target app' + 'Mixin has already been applied to target app' +

View File

@ -76,14 +76,6 @@ export interface AllowedComponentProps {
// Note: can't mark this whole interface internal because some public interfaces // Note: can't mark this whole interface internal because some public interfaces
// extend it. // extend it.
export interface ComponentInternalOptions { export interface ComponentInternalOptions {
/**
* @internal
*/
__props?: NormalizedPropsOptions
/**
* @internal
*/
__emits?: ObjectEmitsOptions | null
/** /**
* @internal * @internal
*/ */

View File

@ -172,8 +172,10 @@ export function normalizeEmitsOptions(
appContext: AppContext, appContext: AppContext,
asMixin = false asMixin = false
): ObjectEmitsOptions | null { ): ObjectEmitsOptions | null {
if (!appContext.deopt && comp.__emits !== undefined) { const cache = appContext.emitsCache
return comp.__emits const cached = cache.get(comp)
if (cached !== undefined) {
return cached
} }
const raw = comp.emits const raw = comp.emits
@ -201,7 +203,8 @@ export function normalizeEmitsOptions(
} }
if (!raw && !hasExtends) { if (!raw && !hasExtends) {
return (comp.__emits = null) cache.set(comp, null)
return null
} }
if (isArray(raw)) { if (isArray(raw)) {
@ -209,7 +212,9 @@ export function normalizeEmitsOptions(
} else { } else {
extend(normalized, raw) extend(normalized, raw)
} }
return (comp.__emits = normalized)
cache.set(comp, normalized)
return normalized
} }
// Check if an incoming prop key is a declared emit event listener. // Check if an incoming prop key is a declared emit event listener.

View File

@ -894,7 +894,7 @@ export function resolveMergedOptions(
const { mixins, extends: extendsOptions } = base const { mixins, extends: extendsOptions } = base
const { const {
mixins: globalMixins, mixins: globalMixins,
cache, optionsCache: cache,
config: { optionMergeStrategies } config: { optionMergeStrategies }
} = instance.appContext } = instance.appContext
const cached = cache.get(base) const cached = cache.get(base)

View File

@ -436,8 +436,10 @@ export function normalizePropsOptions(
appContext: AppContext, appContext: AppContext,
asMixin = false asMixin = false
): NormalizedPropsOptions { ): NormalizedPropsOptions {
if (!appContext.deopt && comp.__props) { const cache = appContext.propsCache
return comp.__props const cached = cache.get(comp)
if (cached) {
return cached
} }
const raw = comp.props const raw = comp.props
@ -468,7 +470,8 @@ export function normalizePropsOptions(
} }
if (!raw && !hasExtends) { if (!raw && !hasExtends) {
return (comp.__props = EMPTY_ARR as any) cache.set(comp, EMPTY_ARR as any)
return EMPTY_ARR as any
} }
if (isArray(raw)) { if (isArray(raw)) {
@ -506,7 +509,9 @@ export function normalizePropsOptions(
} }
} }
return (comp.__props = [normalized, needCastKeys]) const res: NormalizedPropsOptions = [normalized, needCastKeys]
cache.set(comp, res)
return res
} }
function validatePropName(key: string) { function validatePropName(key: string) {