fix(runtime-core): fix props/emits resolving with global mixins

fix #1975
This commit is contained in:
Evan You
2020-08-31 18:32:07 -04:00
parent 2bbeea9a51
commit 8ed0b342d4
8 changed files with 162 additions and 101 deletions

View File

@@ -31,6 +31,7 @@ import {
} from './component'
import { isEmitListener } from './componentEmits'
import { InternalObjectKey } from './vnode'
import { AppContext } from './apiCreateApp'
export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
@@ -107,7 +108,8 @@ type NormalizedProp =
// normalized value is a tuple of the actual normalized options
// and an array of prop keys that need value casting (booleans and defaults)
export type NormalizedPropsOptions = [Record<string, NormalizedProp>, string[]]
export type NormalizedProps = Record<string, NormalizedProp>
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
export function initProps(
instance: ComponentInternalInstance,
@@ -121,7 +123,7 @@ export function initProps(
setFullProps(instance, rawProps, props, attrs)
// validation
if (__DEV__) {
validateProps(props, instance.type)
validateProps(props, instance)
}
if (isStateful) {
@@ -151,7 +153,7 @@ export function updateProps(
vnode: { patchFlag }
} = instance
const rawCurrentProps = toRaw(props)
const [options] = normalizePropsOptions(instance.type)
const [options] = instance.propsOptions
if (
// always force full diff if hmr is enabled
@@ -236,7 +238,7 @@ export function updateProps(
trigger(instance, TriggerOpTypes.SET, '$attrs')
if (__DEV__ && rawProps) {
validateProps(props, instance.type)
validateProps(props, instance)
}
}
@@ -246,7 +248,7 @@ function setFullProps(
props: Data,
attrs: Data
) {
const [options, needCastKeys] = normalizePropsOptions(instance.type)
const [options, needCastKeys] = instance.propsOptions
if (rawProps) {
for (const key in rawProps) {
const value = rawProps[key]
@@ -259,7 +261,7 @@ function setFullProps(
let camelKey
if (options && hasOwn(options, (camelKey = camelize(key)))) {
props[camelKey] = value
} else if (!isEmitListener(instance.type, key)) {
} else if (!isEmitListener(instance.emitsOptions, key)) {
// Any non-declared (either as a prop or an emitted event) props are put
// into a separate `attrs` object for spreading. Make sure to preserve
// original key casing
@@ -283,7 +285,7 @@ function setFullProps(
}
function resolvePropValue(
options: NormalizedPropsOptions[0],
options: NormalizedProps,
props: Data,
key: string,
value: unknown
@@ -315,10 +317,15 @@ function resolvePropValue(
}
export function normalizePropsOptions(
comp: ConcreteComponent
): NormalizedPropsOptions | [] {
if (comp.__props) {
return comp.__props
comp: ConcreteComponent,
appContext: AppContext,
asMixin = false
): NormalizedPropsOptions {
const appId = appContext.app ? appContext.app._uid : -1
const cache = comp.__props || (comp.__props = {})
const cached = cache[appId]
if (cached) {
return cached
}
const raw = comp.props
@@ -329,22 +336,24 @@ export function normalizePropsOptions(
let hasExtends = false
if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) {
const extendProps = (raw: ComponentOptions) => {
const [props, keys] = normalizePropsOptions(raw)
hasExtends = true
const [props, keys] = normalizePropsOptions(raw, appContext, true)
extend(normalized, props)
if (keys) needCastKeys.push(...keys)
}
if (!asMixin && appContext.mixins.length) {
appContext.mixins.forEach(extendProps)
}
if (comp.extends) {
hasExtends = true
extendProps(comp.extends)
}
if (comp.mixins) {
hasExtends = true
comp.mixins.forEach(extendProps)
}
}
if (!raw && !hasExtends) {
return (comp.__props = EMPTY_ARR)
return (cache[appId] = EMPTY_ARR)
}
if (isArray(raw)) {
@@ -381,9 +390,8 @@ export function normalizePropsOptions(
}
}
}
const normalizedEntry: NormalizedPropsOptions = [normalized, needCastKeys]
comp.__props = normalizedEntry
return normalizedEntry
return (cache[appId] = [normalized, needCastKeys])
}
// use function string name to check type constructors
@@ -416,9 +424,9 @@ function getTypeIndex(
/**
* dev only
*/
function validateProps(props: Data, comp: ConcreteComponent) {
function validateProps(props: Data, instance: ComponentInternalInstance) {
const rawValues = toRaw(props)
const options = normalizePropsOptions(comp)[0]
const options = instance.propsOptions[0]
for (const key in options) {
let opt = options[key]
if (opt == null) continue