import { EMPTY_OBJ, isArray, isIntegerKey, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, isFunction, NOOP, isString, isPromise, hyphenate, isOn, isReservedProp, camelize, EMPTY_ARR, makeMap, remove, NO, isGloballyWhitelisted, toTypeString, invokeArrayFns } from '@vue/shared' export { camelize } from '@vue/shared' const targetMap = new WeakMap() const effectStack = [] let activeEffect const ITERATE_KEY = Symbol( process.env.NODE_ENV !== 'production' ? 'iterate' : '' ) const MAP_KEY_ITERATE_KEY = Symbol( process.env.NODE_ENV !== 'production' ? 'Map key iterate' : '' ) function isEffect(fn) { return fn && fn._isEffect === true } function effect(fn, options = EMPTY_OBJ) { if (isEffect(fn)) { fn = fn.raw } const effect = createReactiveEffect(fn, options) if (!options.lazy) { effect() } return effect } function stop(effect) { if (effect.active) { cleanup(effect) if (effect.options.onStop) { effect.options.onStop() } effect.active = false } } let uid = 0 function createReactiveEffect(fn, options) { const effect = function reactiveEffect() { if (!effect.active) { return options.scheduler ? undefined : fn() } if (!effectStack.includes(effect)) { cleanup(effect) try { enableTracking() effectStack.push(effect) activeEffect = effect return fn() } finally { effectStack.pop() resetTracking() activeEffect = effectStack[effectStack.length - 1] } } } effect.id = uid++ effect._isEffect = true effect.active = true effect.raw = fn effect.deps = [] effect.options = options return effect } function cleanup(effect) { const { deps } = effect if (deps.length) { for (let i = 0; i < deps.length; i++) { deps[i].delete(effect) } deps.length = 0 } } let shouldTrack = true const trackStack = [] function pauseTracking() { trackStack.push(shouldTrack) shouldTrack = false } function enableTracking() { trackStack.push(shouldTrack) shouldTrack = true } function resetTracking() { const last = trackStack.pop() shouldTrack = last === undefined ? true : last } function track(target, type, key) { if (!shouldTrack || activeEffect === undefined) { return } let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = new Set())) } if (!dep.has(activeEffect)) { dep.add(activeEffect) activeEffect.deps.push(dep) if (process.env.NODE_ENV !== 'production' && activeEffect.options.onTrack) { activeEffect.options.onTrack({ effect: activeEffect, target, type, key }) } } } function trigger(target, type, key, newValue, oldValue, oldTarget) { const depsMap = targetMap.get(target) if (!depsMap) { // never been tracked return } const effects = new Set() const add = effectsToAdd => { if (effectsToAdd) { effectsToAdd.forEach(effect => { if (effect !== activeEffect) { effects.add(effect) } }) } } if (type === 'clear' /* CLEAR */) { // collection being cleared // trigger all effects for target depsMap.forEach(add) } else if (key === 'length' && isArray(target)) { depsMap.forEach((dep, key) => { if (key === 'length' || key >= newValue) { add(dep) } }) } else { // schedule runs for SET | ADD | DELETE if (key !== void 0) { add(depsMap.get(key)) } // also run for iteration key on ADD | DELETE | Map.SET const shouldTriggerIteration = (type === 'add' /* ADD */ && (!isArray(target) || isIntegerKey(key))) || (type === 'delete' /* DELETE */ && !isArray(target)) if ( shouldTriggerIteration || (type === 'set' /* SET */ && target instanceof Map) ) { add(depsMap.get(isArray(target) ? 'length' : ITERATE_KEY)) } if (shouldTriggerIteration && target instanceof Map) { add(depsMap.get(MAP_KEY_ITERATE_KEY)) } } const run = effect => { if (process.env.NODE_ENV !== 'production' && effect.options.onTrigger) { effect.options.onTrigger({ effect, target, key, type, newValue, oldValue, oldTarget }) } if (effect.options.scheduler) { effect.options.scheduler(effect) } else { effect() } } effects.forEach(run) } const builtInSymbols = new Set( Object.getOwnPropertyNames(Symbol) .map(key => Symbol[key]) .filter(isSymbol) ) const get = /*#__PURE__*/ createGetter() const shallowGet = /*#__PURE__*/ createGetter(false, true) const readonlyGet = /*#__PURE__*/ createGetter(true) const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true) const arrayInstrumentations = {} ;['includes', 'indexOf', 'lastIndexOf'].forEach(key => { arrayInstrumentations[key] = function(...args) { const arr = toRaw(this) for (let i = 0, l = this.length; i < l; i++) { track(arr, 'get' /* GET */, i + '') } // we run the method using the original args first (which may be reactive) const res = arr[key](...args) if (res === -1 || res === false) { // if that didn't work, run it again using raw values. return arr[key](...args.map(toRaw)) } else { return res } } }) function createGetter(isReadonly = false, shallow = false) { return function get(target, key, receiver) { if (key === '__v_isReactive' /* IS_REACTIVE */) { return !isReadonly } else if (key === '__v_isReadonly' /* IS_READONLY */) { return isReadonly } else if ( key === '__v_raw' /* RAW */ && receiver === (isReadonly ? readonlyMap : reactiveMap).get(target) ) { return target } const targetIsArray = isArray(target) if (targetIsArray && hasOwn(arrayInstrumentations, key)) { return Reflect.get(arrayInstrumentations, key, receiver) } const res = Reflect.get(target, key, receiver) const keyIsSymbol = isSymbol(key) if ( keyIsSymbol ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef` ) { return res } if (!isReadonly) { track(target, 'get' /* GET */, key) } if (shallow) { return res } if (isRef(res)) { // ref unwrapping - does not apply for Array + integer key. const shouldUnwrap = !targetIsArray || !isIntegerKey(key) return shouldUnwrap ? res.value : res } if (isObject(res)) { // Convert returned value into a proxy as well. we do the isObject check // here to avoid invalid value warning. Also need to lazy access readonly // and reactive here to avoid circular dependency. return isReadonly ? readonly(res) : reactive(res) } return res } } const set = /*#__PURE__*/ createSetter() const shallowSet = /*#__PURE__*/ createSetter(true) function createSetter(shallow = false) { return function set(target, key, value, receiver) { const oldValue = target[key] if (!shallow) { value = toRaw(value) if (!isArray(target) && isRef(oldValue) && !isRef(value)) { oldValue.value = value return true } } const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key) const result = Reflect.set(target, key, value, receiver) // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { if (!hadKey) { trigger(target, 'add' /* ADD */, key, value) } else if (hasChanged(value, oldValue)) { trigger(target, 'set' /* SET */, key, value, oldValue) } } return result } } function deleteProperty(target, key) { const hadKey = hasOwn(target, key) const oldValue = target[key] const result = Reflect.deleteProperty(target, key) if (result && hadKey) { trigger(target, 'delete' /* DELETE */, key, undefined, oldValue) } return result } function has(target, key) { const result = Reflect.has(target, key) if (!isSymbol(key) || !builtInSymbols.has(key)) { track(target, 'has' /* HAS */, key) } return result } function ownKeys(target) { track(target, 'iterate' /* ITERATE */, ITERATE_KEY) return Reflect.ownKeys(target) } const mutableHandlers = { get, set, deleteProperty, has, ownKeys } const readonlyHandlers = { get: readonlyGet, set(target, key) { if (process.env.NODE_ENV !== 'production') { console.warn( `Set operation on key "${String(key)}" failed: target is readonly.`, target ) } return true }, deleteProperty(target, key) { if (process.env.NODE_ENV !== 'production') { console.warn( `Delete operation on key "${String(key)}" failed: target is readonly.`, target ) } return true } } const shallowReactiveHandlers = extend({}, mutableHandlers, { get: shallowGet, set: shallowSet }) // Props handlers are special in the sense that it should not unwrap top-level // refs (in order to allow refs to be explicitly passed down), but should // retain the reactivity of the normal readonly object. const shallowReadonlyHandlers = extend({}, readonlyHandlers, { get: shallowReadonlyGet }) const toReactive = value => (isObject(value) ? reactive(value) : value) const toReadonly = value => (isObject(value) ? readonly(value) : value) const toShallow = value => value const getProto = v => Reflect.getPrototypeOf(v) function get$1(target, key, isReadonly = false, isShallow = false) { // #1772: readonly(reactive(Map)) should return readonly + reactive version // of the value target = target['__v_raw' /* RAW */] const rawTarget = toRaw(target) const rawKey = toRaw(key) if (key !== rawKey) { !isReadonly && track(rawTarget, 'get' /* GET */, key) } !isReadonly && track(rawTarget, 'get' /* GET */, rawKey) const { has } = getProto(rawTarget) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive if (has.call(rawTarget, key)) { return wrap(target.get(key)) } else if (has.call(rawTarget, rawKey)) { return wrap(target.get(rawKey)) } } function has$1(key, isReadonly = false) { const target = this['__v_raw' /* RAW */] const rawTarget = toRaw(target) const rawKey = toRaw(key) if (key !== rawKey) { !isReadonly && track(rawTarget, 'has' /* HAS */, key) } !isReadonly && track(rawTarget, 'has' /* HAS */, rawKey) return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey) } function size(target, isReadonly = false) { target = target['__v_raw' /* RAW */] !isReadonly && track(toRaw(target), 'iterate' /* ITERATE */, ITERATE_KEY) return Reflect.get(target, 'size', target) } function add(value) { value = toRaw(value) const target = toRaw(this) const proto = getProto(target) const hadKey = proto.has.call(target, value) const result = proto.add.call(target, value) if (!hadKey) { trigger(target, 'add' /* ADD */, value, value) } return result } function set$1(key, value) { value = toRaw(value) const target = toRaw(this) const { has, get, set } = getProto(target) let hadKey = has.call(target, key) if (!hadKey) { key = toRaw(key) hadKey = has.call(target, key) } else if (process.env.NODE_ENV !== 'production') { checkIdentityKeys(target, has, key) } const oldValue = get.call(target, key) const result = set.call(target, key, value) if (!hadKey) { trigger(target, 'add' /* ADD */, key, value) } else if (hasChanged(value, oldValue)) { trigger(target, 'set' /* SET */, key, value, oldValue) } return result } function deleteEntry(key) { const target = toRaw(this) const { has, get, delete: del } = getProto(target) let hadKey = has.call(target, key) if (!hadKey) { key = toRaw(key) hadKey = has.call(target, key) } else if (process.env.NODE_ENV !== 'production') { checkIdentityKeys(target, has, key) } const oldValue = get ? get.call(target, key) : undefined // forward the operation before queueing reactions const result = del.call(target, key) if (hadKey) { trigger(target, 'delete' /* DELETE */, key, undefined, oldValue) } return result } function clear() { const target = toRaw(this) const hadItems = target.size !== 0 const oldTarget = process.env.NODE_ENV !== 'production' ? target instanceof Map ? new Map(target) : new Set(target) : undefined // forward the operation before queueing reactions const result = getProto(target).clear.call(target) if (hadItems) { trigger(target, 'clear' /* CLEAR */, undefined, undefined, oldTarget) } return result } function createForEach(isReadonly, isShallow) { return function forEach(callback, thisArg) { const observed = this const target = observed['__v_raw' /* RAW */] const rawTarget = toRaw(target) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive !isReadonly && track(rawTarget, 'iterate' /* ITERATE */, ITERATE_KEY) return target.forEach((value, key) => { // important: make sure the callback is // 1. invoked with the reactive map as `this` and 3rd arg // 2. the value received should be a corresponding reactive/readonly. return callback.call(thisArg, wrap(value), wrap(key), observed) }) } } function createIterableMethod(method, isReadonly, isShallow) { return function(...args) { const target = this['__v_raw' /* RAW */] const rawTarget = toRaw(target) const isMap = rawTarget instanceof Map const isPair = method === 'entries' || (method === Symbol.iterator && isMap) const isKeyOnly = method === 'keys' && isMap const innerIterator = target[method](...args) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive !isReadonly && track( rawTarget, 'iterate' /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY ) // return a wrapped iterator which returns observed versions of the // values emitted from the real iterator return { // iterator protocol next() { const { value, done } = innerIterator.next() return done ? { value, done } : { value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), done } }, // iterable protocol [Symbol.iterator]() { return this } } } } function createReadonlyMethod(type) { return function(...args) { if (process.env.NODE_ENV !== 'production') { const key = args[0] ? `on key "${args[0]}" ` : `` console.warn( `${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this) ) } return type === 'delete' /* DELETE */ ? false : this } } const mutableInstrumentations = { get(key) { return get$1(this, key) }, get size() { return size(this) }, has: has$1, add, set: set$1, delete: deleteEntry, clear, forEach: createForEach(false, false) } const shallowInstrumentations = { get(key) { return get$1(this, key, false, true) }, get size() { return size(this) }, has: has$1, add, set: set$1, delete: deleteEntry, clear, forEach: createForEach(false, true) } const readonlyInstrumentations = { get(key) { return get$1(this, key, true) }, get size() { return size(this, true) }, has(key) { return has$1.call(this, key, true) }, add: createReadonlyMethod('add' /* ADD */), set: createReadonlyMethod('set' /* SET */), delete: createReadonlyMethod('delete' /* DELETE */), clear: createReadonlyMethod('clear' /* CLEAR */), forEach: createForEach(true, false) } const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator] iteratorMethods.forEach(method => { mutableInstrumentations[method] = createIterableMethod(method, false, false) readonlyInstrumentations[method] = createIterableMethod(method, true, false) shallowInstrumentations[method] = createIterableMethod(method, false, true) }) function createInstrumentationGetter(isReadonly, shallow) { const instrumentations = shallow ? shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations return (target, key, receiver) => { if (key === '__v_isReactive' /* IS_REACTIVE */) { return !isReadonly } else if (key === '__v_isReadonly' /* IS_READONLY */) { return isReadonly } else if (key === '__v_raw' /* RAW */) { return target } return Reflect.get( hasOwn(instrumentations, key) && key in target ? instrumentations : target, key, receiver ) } } const mutableCollectionHandlers = { get: createInstrumentationGetter(false, false) } const shallowCollectionHandlers = { get: createInstrumentationGetter(false, true) } const readonlyCollectionHandlers = { get: createInstrumentationGetter(true, false) } function checkIdentityKeys(target, has, key) { const rawKey = toRaw(key) if (rawKey !== key && has.call(target, rawKey)) { const type = toRawType(target) console.warn( `Reactive ${type} contains both the raw and reactive ` + `versions of the same object${type === `Map` ? `as keys` : ``}, ` + `which can lead to inconsistencies. ` + `Avoid differentiating between the raw and reactive versions ` + `of an object and only use the reactive version if possible.` ) } } const reactiveMap = new WeakMap() const readonlyMap = new WeakMap() function targetTypeMap(rawType) { switch (rawType) { case 'Object': case 'Array': return 1 /* COMMON */ case 'Map': case 'Set': case 'WeakMap': case 'WeakSet': return 2 /* COLLECTION */ default: return 0 /* INVALID */ } } function getTargetType(value) { return value['__v_skip' /* SKIP */] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value)) } function reactive(target) { // if trying to observe a readonly proxy, return the readonly version. if (target && target['__v_isReadonly' /* IS_READONLY */]) { return target } return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers ) } // Return a reactive-copy of the original object, where only the root level // properties are reactive, and does NOT unwrap refs nor recursively convert // returned properties. function shallowReactive(target) { return createReactiveObject( target, false, shallowReactiveHandlers, shallowCollectionHandlers ) } function readonly(target) { return createReactiveObject( target, true, readonlyHandlers, readonlyCollectionHandlers ) } // Return a reactive-copy of the original object, where only the root level // properties are readonly, and does NOT unwrap refs nor recursively convert // returned properties. // This is used for creating the props proxy object for stateful components. function shallowReadonly(target) { return createReactiveObject( target, true, shallowReadonlyHandlers, readonlyCollectionHandlers ) } function createReactiveObject( target, isReadonly, baseHandlers, collectionHandlers ) { if (!isObject(target)) { if (process.env.NODE_ENV !== 'production') { console.warn(`value cannot be made reactive: ${String(target)}`) } return target } // target is already a Proxy, return it. // exception: calling readonly() on a reactive object if ( target['__v_raw' /* RAW */] && !(isReadonly && target['__v_isReactive' /* IS_REACTIVE */]) ) { return target } // target already has corresponding Proxy const proxyMap = isReadonly ? readonlyMap : reactiveMap const existingProxy = proxyMap.get(target) if (existingProxy) { return existingProxy } // only a whitelist of value types can be observed. const targetType = getTargetType(target) if (targetType === 0 /* INVALID */) { return target } const proxy = new Proxy( target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers ) proxyMap.set(target, proxy) return proxy } function isReactive(value) { if (isReadonly(value)) { return isReactive(value['__v_raw' /* RAW */]) } return !!(value && value['__v_isReactive' /* IS_REACTIVE */]) } function isReadonly(value) { return !!(value && value['__v_isReadonly' /* IS_READONLY */]) } function isProxy(value) { return isReactive(value) || isReadonly(value) } function toRaw(observed) { return (observed && toRaw(observed['__v_raw' /* RAW */])) || observed } function markRaw(value) { def(value, '__v_skip' /* SKIP */, true) return value } const convert = val => (isObject(val) ? reactive(val) : val) function isRef(r) { return Boolean(r && r.__v_isRef === true) } function ref(value) { return createRef(value) } function shallowRef(value) { return createRef(value, true) } class RefImpl { constructor(_rawValue, _shallow = false) { this._rawValue = _rawValue this._shallow = _shallow this.__v_isRef = true this._value = _shallow ? _rawValue : convert(_rawValue) } get value() { track(toRaw(this), 'get' /* GET */, 'value') return this._value } set value(newVal) { if (hasChanged(toRaw(newVal), this._rawValue)) { this._rawValue = newVal this._value = this._shallow ? newVal : convert(newVal) trigger(toRaw(this), 'set' /* SET */, 'value', newVal) } } } function createRef(rawValue, shallow = false) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow) } function triggerRef(ref) { trigger( ref, 'set' /* SET */, 'value', process.env.NODE_ENV !== 'production' ? ref.value : void 0 ) } function unref(ref) { return isRef(ref) ? ref.value : ref } const shallowUnwrapHandlers = { get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), set: (target, key, value, receiver) => { const oldValue = target[key] if (isRef(oldValue) && !isRef(value)) { oldValue.value = value return true } else { return Reflect.set(target, key, value, receiver) } } } function proxyRefs(objectWithRefs) { return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers) } class CustomRefImpl { constructor(factory) { this.__v_isRef = true const { get, set } = factory( () => track(this, 'get' /* GET */, 'value'), () => trigger(this, 'set' /* SET */, 'value') ) this._get = get this._set = set } get value() { return this._get() } set value(newVal) { this._set(newVal) } } function customRef(factory) { return new CustomRefImpl(factory) } function toRefs(object) { if (process.env.NODE_ENV !== 'production' && !isProxy(object)) { console.warn(`toRefs() expects a reactive object but received a plain one.`) } const ret = isArray(object) ? new Array(object.length) : {} for (const key in object) { ret[key] = toRef(object, key) } return ret } class ObjectRefImpl { constructor(_object, _key) { this._object = _object this._key = _key this.__v_isRef = true } get value() { return this._object[this._key] } set value(newVal) { this._object[this._key] = newVal } } function toRef(object, key) { return new ObjectRefImpl(object, key) } class ComputedRefImpl { constructor(getter, _setter, isReadonly) { this._setter = _setter this._dirty = true this.__v_isRef = true this.effect = effect(getter, { lazy: true, scheduler: () => { if (!this._dirty) { this._dirty = true trigger(toRaw(this), 'set' /* SET */, 'value') } } }) this['__v_isReadonly' /* IS_READONLY */] = isReadonly } get value() { if (this._dirty) { this._value = this.effect() this._dirty = false } track(toRaw(this), 'get' /* GET */, 'value') return this._value } set value(newValue) { this._setter(newValue) } } function computed(getterOrOptions) { let getter let setter if (isFunction(getterOrOptions)) { getter = getterOrOptions setter = process.env.NODE_ENV !== 'production' ? () => { console.warn('Write operation failed: computed value is readonly') } : NOOP } else { getter = getterOrOptions.get setter = getterOrOptions.set } return new ComputedRefImpl( getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set ) } const stack = [] function pushWarningContext(vnode) { stack.push(vnode) } function popWarningContext() { stack.pop() } function warn(msg, ...args) { // avoid props formatting or warn handler tracking deps that might be mutated // during patch, leading to infinite recursion. pauseTracking() const instance = stack.length ? stack[stack.length - 1].component : null const appWarnHandler = instance && instance.appContext.config.warnHandler const trace = getComponentTrace() if (appWarnHandler) { callWithErrorHandling(appWarnHandler, instance, 11 /* APP_WARN_HANDLER */, [ msg + args.join(''), instance && instance.proxy, trace .map(({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`) .join('\n'), trace ]) } else { const warnArgs = [`[Vue warn]: ${msg}`, ...args] /* istanbul ignore if */ if ( trace.length && // avoid spamming console during tests !false ) { warnArgs.push(`\n`, ...formatTrace(trace)) } console.warn(...warnArgs) } resetTracking() } function getComponentTrace() { let currentVNode = stack[stack.length - 1] if (!currentVNode) { return [] } // we can't just use the stack because it will be incomplete during updates // that did not start from the root. Re-construct the parent chain using // instance parent pointers. const normalizedStack = [] while (currentVNode) { const last = normalizedStack[0] if (last && last.vnode === currentVNode) { last.recurseCount++ } else { normalizedStack.push({ vnode: currentVNode, recurseCount: 0 }) } const parentInstance = currentVNode.component && currentVNode.component.parent currentVNode = parentInstance && parentInstance.vnode } return normalizedStack } /* istanbul ignore next */ function formatTrace(trace) { const logs = [] trace.forEach((entry, i) => { logs.push(...(i === 0 ? [] : [`\n`]), ...formatTraceEntry(entry)) }) return logs } function formatTraceEntry({ vnode, recurseCount }) { const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : `` const isRoot = vnode.component ? vnode.component.parent == null : false const open = ` at <${formatComponentName( vnode.component, vnode.type, isRoot )}` const close = `>` + postfix return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close] } /* istanbul ignore next */ function formatProps(props) { const res = [] const keys = Object.keys(props) keys.slice(0, 3).forEach(key => { res.push(...formatProp(key, props[key])) }) if (keys.length > 3) { res.push(` ...`) } return res } /* istanbul ignore next */ function formatProp(key, value, raw) { if (isString(value)) { value = JSON.stringify(value) return raw ? value : [`${key}=${value}`] } else if ( typeof value === 'number' || typeof value === 'boolean' || value == null ) { return raw ? value : [`${key}=${value}`] } else if (isRef(value)) { value = formatProp(key, toRaw(value.value), true) return raw ? value : [`${key}=Ref<`, value, `>`] } else if (isFunction(value)) { return [`${key}=fn${value.name ? `<${value.name}>` : ``}`] } else { value = toRaw(value) return raw ? value : [`${key}=`, value] } } const ErrorTypeStrings = { ['bc' /* BEFORE_CREATE */]: 'beforeCreate hook', ['c' /* CREATED */]: 'created hook', ['bm' /* BEFORE_MOUNT */]: 'beforeMount hook', ['m' /* MOUNTED */]: 'mounted hook', ['bu' /* BEFORE_UPDATE */]: 'beforeUpdate hook', ['u' /* UPDATED */]: 'updated', ['bum' /* BEFORE_UNMOUNT */]: 'beforeUnmount hook', ['um' /* UNMOUNTED */]: 'unmounted hook', ['a' /* ACTIVATED */]: 'activated hook', ['da' /* DEACTIVATED */]: 'deactivated hook', ['ec' /* ERROR_CAPTURED */]: 'errorCaptured hook', ['rtc' /* RENDER_TRACKED */]: 'renderTracked hook', ['rtg' /* RENDER_TRIGGERED */]: 'renderTriggered hook', [0 /* SETUP_FUNCTION */]: 'setup function', [1 /* RENDER_FUNCTION */]: 'render function', [2 /* WATCH_GETTER */]: 'watcher getter', [3 /* WATCH_CALLBACK */]: 'watcher callback', [4 /* WATCH_CLEANUP */]: 'watcher cleanup function', [5 /* NATIVE_EVENT_HANDLER */]: 'native event handler', [6 /* COMPONENT_EVENT_HANDLER */]: 'component event handler', [7 /* VNODE_HOOK */]: 'vnode hook', [8 /* DIRECTIVE_HOOK */]: 'directive hook', [9 /* TRANSITION_HOOK */]: 'transition hook', [10 /* APP_ERROR_HANDLER */]: 'app errorHandler', [11 /* APP_WARN_HANDLER */]: 'app warnHandler', [12 /* FUNCTION_REF */]: 'ref function', [13 /* ASYNC_COMPONENT_LOADER */]: 'async component loader', [14 /* SCHEDULER */]: 'scheduler flush. This is likely a Vue internals bug. ' + 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next' } function callWithErrorHandling(fn, instance, type, args) { let res try { res = args ? fn(...args) : fn() } catch (err) { handleError(err, instance, type) } return res } function callWithAsyncErrorHandling(fn, instance, type, args) { if (isFunction(fn)) { const res = callWithErrorHandling(fn, instance, type, args) if (res && isPromise(res)) { res.catch(err => { handleError(err, instance, type) }) } return res } const values = [] for (let i = 0; i < fn.length; i++) { values.push(callWithAsyncErrorHandling(fn[i], instance, type, args)) } return values } function handleError(err, instance, type) { const contextVNode = instance ? instance.vnode : null if (instance) { let cur = instance.parent // the exposed instance is the render proxy to keep it consistent with 2.x const exposedInstance = instance.proxy // in production the hook receives only the error code const errorInfo = process.env.NODE_ENV !== 'production' ? ErrorTypeStrings[type] || type : type // fixed by xxxxxxx while (cur) { const errorCapturedHooks = cur.ec if (errorCapturedHooks) { for (let i = 0; i < errorCapturedHooks.length; i++) { if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { return } } } cur = cur.parent } // app-level handling const appErrorHandler = instance.appContext.config.errorHandler if (appErrorHandler) { callWithErrorHandling(appErrorHandler, null, 10 /* APP_ERROR_HANDLER */, [ err, exposedInstance, errorInfo ]) return } } logError(err, type, contextVNode) } // fixed by xxxxxx function logError(err, type, contextVNode) { if (process.env.NODE_ENV !== 'production') { const info = ErrorTypeStrings[type] || type // fixed by xxxxxx if (contextVNode) { pushWarningContext(contextVNode) } warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`) if (contextVNode) { popWarningContext() } // crash in dev so it's more noticeable throw err } else { // recover in prod to reduce the impact on end-user console.error(err) } } let isFlushing = false let isFlushPending = false // fixed by xxxxxx const queue = [] let flushIndex = 0 const pendingPreFlushCbs = [] let activePreFlushCbs = null let preFlushIndex = 0 const pendingPostFlushCbs = [] let activePostFlushCbs = null let postFlushIndex = 0 const resolvedPromise = Promise.resolve() let currentFlushPromise = null let currentPreFlushParentJob = null const RECURSION_LIMIT = 100 function nextTick(fn) { const p = currentFlushPromise || resolvedPromise return fn ? p.then(fn) : p } function queueJob(job) { // the dedupe search uses the startIndex argument of Array.includes() // by default the search index includes the current job that is being run // so it cannot recursively trigger itself again. // if the job is a watch() callback, the search will start with a +1 index to // allow it recursively trigger itself - it is the user's responsibility to // ensure it doesn't end up in an infinite loop. if ( (!queue.length || !queue.includes( job, isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex )) && job !== currentPreFlushParentJob ) { queue.push(job) queueFlush() } } function queueFlush() { if (!isFlushing && !isFlushPending) { isFlushPending = true currentFlushPromise = resolvedPromise.then(flushJobs) } } function queueCb(cb, activeQueue, pendingQueue, index) { if (!isArray(cb)) { if ( !activeQueue || !activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index) ) { pendingQueue.push(cb) } } else { // if cb is an array, it is a component lifecycle hook which can only be // triggered by a job, which is already deduped in the main queue, so // we can skip duplicate check here to improve perf pendingQueue.push(...cb) } queueFlush() } function queuePreFlushCb(cb) { queueCb(cb, activePreFlushCbs, pendingPreFlushCbs, preFlushIndex) } function queuePostFlushCb(cb) { queueCb(cb, activePostFlushCbs, pendingPostFlushCbs, postFlushIndex) } function flushPreFlushCbs(seen, parentJob = null) { if (pendingPreFlushCbs.length) { currentPreFlushParentJob = parentJob activePreFlushCbs = [...new Set(pendingPreFlushCbs)] pendingPreFlushCbs.length = 0 if (process.env.NODE_ENV !== 'production') { seen = seen || new Map() } for ( preFlushIndex = 0; preFlushIndex < activePreFlushCbs.length; preFlushIndex++ ) { if (process.env.NODE_ENV !== 'production') { checkRecursiveUpdates(seen, activePreFlushCbs[preFlushIndex]) } activePreFlushCbs[preFlushIndex]() } activePreFlushCbs = null preFlushIndex = 0 currentPreFlushParentJob = null // recursively flush until it drains flushPreFlushCbs(seen, parentJob) } } function flushPostFlushCbs(seen) { if (pendingPostFlushCbs.length) { const deduped = [...new Set(pendingPostFlushCbs)] pendingPostFlushCbs.length = 0 // #1947 already has active queue, nested flushPostFlushCbs call if (activePostFlushCbs) { activePostFlushCbs.push(...deduped) return } activePostFlushCbs = deduped if (process.env.NODE_ENV !== 'production') { seen = seen || new Map() } activePostFlushCbs.sort((a, b) => getId(a) - getId(b)) for ( postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++ ) { if (process.env.NODE_ENV !== 'production') { checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex]) } activePostFlushCbs[postFlushIndex]() } activePostFlushCbs = null postFlushIndex = 0 } } const getId = job => (job.id == null ? Infinity : job.id) function flushJobs(seen) { isFlushPending = false isFlushing = true if (process.env.NODE_ENV !== 'production') { seen = seen || new Map() } flushPreFlushCbs(seen) // Sort queue before flush. // This ensures that: // 1. Components are updated from parent to child. (because parent is always // created before the child so its render effect will have smaller // priority number) // 2. If a component is unmounted during a parent component's update, // its update can be skipped. // Jobs can never be null before flush starts, since they are only invalidated // during execution of another flushed job. queue.sort((a, b) => getId(a) - getId(b)) try { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex] if (job) { if (process.env.NODE_ENV !== 'production') { checkRecursiveUpdates(seen, job) } callWithErrorHandling(job, null, 14 /* SCHEDULER */) } } } finally { flushIndex = 0 queue.length = 0 flushPostFlushCbs(seen) isFlushing = false currentFlushPromise = null // some postFlushCb queued jobs! // keep flushing until it drains. if (queue.length || pendingPostFlushCbs.length) { flushJobs(seen) } } } function checkRecursiveUpdates(seen, fn) { if (!seen.has(fn)) { seen.set(fn, 1) } else { const count = seen.get(fn) if (count > RECURSION_LIMIT) { throw new Error( `Maximum recursive updates exceeded. ` + `This means you have a reactive effect that is mutating its own ` + `dependencies and thus recursively triggering itself. Possible sources ` + `include component template, render function, updated hook or ` + `watcher source function.` ) } else { seen.set(fn, count + 1) } } } // mark the current rendering instance for asset resolution (e.g. // resolveComponent, resolveDirective) during render let currentRenderingInstance = null function markAttrsAccessed() {} function emit(instance, event, ...args) { const props = instance.vnode.props || EMPTY_OBJ if (process.env.NODE_ENV !== 'production') { const { emitsOptions, propsOptions: [propsOptions] } = instance if (emitsOptions) { if (!(event in emitsOptions)) { if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { warn( `Component emitted event "${event}" but it is neither declared in ` + `the emits option nor as an "on${capitalize(event)}" prop.` ) } } else { const validator = emitsOptions[event] if (isFunction(validator)) { const isValid = validator(...args) if (!isValid) { warn( `Invalid event arguments: event validation failed for event "${event}".` ) } } } } } if (process.env.NODE_ENV !== 'production' || false); let handlerName = `on${capitalize(event)}` let handler = props[handlerName] // for v-model update:xxx events, also trigger kebab-case equivalent // for props passed via kebab-case if (!handler && event.startsWith('update:')) { handlerName = `on${capitalize(hyphenate(event))}` handler = props[handlerName] } if (!handler) { handler = props[handlerName + `Once`] if (!instance.emitted) { ;(instance.emitted = {})[handlerName] = true } else if (instance.emitted[handlerName]) { return } } if (handler) { callWithAsyncErrorHandling( handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args ) } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { const appId = appContext.app ? appContext.app._uid : -1 const cache = comp.__emits || (comp.__emits = {}) const cached = cache[appId] if (cached !== undefined) { return cached } const raw = comp.emits let normalized = {} // apply mixin/extends props let hasExtends = false if (__VUE_OPTIONS_API__ && !isFunction(comp)) { const extendEmits = raw => { hasExtends = true extend(normalized, normalizeEmitsOptions(raw, appContext, true)) } if (!asMixin && appContext.mixins.length) { appContext.mixins.forEach(extendEmits) } if (comp.extends) { extendEmits(comp.extends) } if (comp.mixins) { comp.mixins.forEach(extendEmits) } } if (!raw && !hasExtends) { return (cache[appId] = null) } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)) } else { extend(normalized, raw) } return (cache[appId] = normalized) } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are // both considered matched listeners. function isEmitListener(options, key) { if (!options || !isOn(key)) { return false } key = key.replace(/Once$/, '') return ( hasOwn(options, key[2].toLowerCase() + key.slice(3)) || hasOwn(options, key.slice(2)) ) } function initProps( instance, rawProps, isStateful, // result of bitwise flag comparison isSSR = false ) { const props = {} const attrs = {} // def(attrs, InternalObjectKey, 1) // fixed by xxxxxx def(attrs, '__vInternal', 1) setFullProps(instance, rawProps, props, attrs) // validation if (process.env.NODE_ENV !== 'production') { validateProps(props, instance) } if (isStateful) { // stateful instance.props = isSSR ? props : shallowReactive(props) } else { if (!instance.type.props) { // functional w/ optional props, props === attrs instance.props = attrs } else { // functional w/ declared props instance.props = props } } instance.attrs = attrs } function setFullProps(instance, rawProps, props, attrs) { const [options, needCastKeys] = instance.propsOptions if (rawProps) { for (const key in rawProps) { const value = rawProps[key] // key, ref are reserved and never passed down if (isReservedProp(key)) { continue } // prop option names are camelized during normalization, so to support // kebab -> camel conversion here we need to camelize the key. let camelKey if (options && hasOwn(options, (camelKey = camelize(key)))) { props[camelKey] = value } 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 attrs[key] = value } } } if (needCastKeys) { const rawCurrentProps = toRaw(props) for (let i = 0; i < needCastKeys.length; i++) { const key = needCastKeys[i] props[key] = resolvePropValue( options, rawCurrentProps, key, rawCurrentProps[key] ) } } } function resolvePropValue(options, props, key, value) { const opt = options[key] if (opt != null) { const hasDefault = hasOwn(opt, 'default') // default values if (hasDefault && value === undefined) { const defaultValue = opt.default value = opt.type !== Function && isFunction(defaultValue) ? defaultValue(props) : defaultValue } // boolean casting if (opt[0 /* shouldCast */]) { if (!hasOwn(props, key) && !hasDefault) { value = false } else if ( opt[1 /* shouldCastTrue */] && (value === '' || value === hyphenate(key)) ) { value = true } } } return value } function normalizePropsOptions(comp, appContext, asMixin = false) { 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 const normalized = {} const needCastKeys = [] // apply mixin/extends props let hasExtends = false if (__VUE_OPTIONS_API__ && !isFunction(comp)) { const extendProps = 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) { extendProps(comp.extends) } if (comp.mixins) { comp.mixins.forEach(extendProps) } } if (!raw && !hasExtends) { return (cache[appId] = EMPTY_ARR) } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { if (process.env.NODE_ENV !== 'production' && !isString(raw[i])) { warn(`props must be strings when using array syntax.`, raw[i]) } const normalizedKey = camelize(raw[i]) if (validatePropName(normalizedKey)) { normalized[normalizedKey] = EMPTY_OBJ } } } else if (raw) { if (process.env.NODE_ENV !== 'production' && !isObject(raw)) { warn(`invalid props options`, raw) } for (const key in raw) { const normalizedKey = camelize(key) if (validatePropName(normalizedKey)) { const opt = raw[key] const prop = (normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : opt) if (prop) { const booleanIndex = getTypeIndex(Boolean, prop.type) const stringIndex = getTypeIndex(String, prop.type) prop[0 /* shouldCast */] = booleanIndex > -1 prop[1 /* shouldCastTrue */] = stringIndex < 0 || booleanIndex < stringIndex // if the prop needs boolean casting or default value if (booleanIndex > -1 || hasOwn(prop, 'default')) { needCastKeys.push(normalizedKey) } } } } } return (cache[appId] = [normalized, needCastKeys]) } // use function string name to check type constructors // so that it works across vms / iframes. function getType(ctor) { const match = ctor && ctor.toString().match(/^\s*function (\w+)/) return match ? match[1] : '' } function isSameType(a, b) { return getType(a) === getType(b) } function getTypeIndex(type, expectedTypes) { if (isArray(expectedTypes)) { for (let i = 0, len = expectedTypes.length; i < len; i++) { if (isSameType(expectedTypes[i], type)) { return i } } } else if (isFunction(expectedTypes)) { return isSameType(expectedTypes, type) ? 0 : -1 } return -1 } /** * dev only */ function validateProps(props, instance) { const rawValues = toRaw(props) const options = instance.propsOptions[0] for (const key in options) { let opt = options[key] if (opt == null) continue validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)) } } /** * dev only */ function validatePropName(key) { if (key[0] !== '$') { return true } else if (process.env.NODE_ENV !== 'production') { warn(`Invalid prop name: "${key}" is a reserved property.`) } return false } /** * dev only */ function validateProp(name, value, prop, isAbsent) { const { type, required, validator } = prop // required! if (required && isAbsent) { warn('Missing required prop: "' + name + '"') return } // missing but optional if (value == null && !prop.required) { return } // type check if (type != null && type !== true) { let isValid = false const types = isArray(type) ? type : [type] const expectedTypes = [] // value is valid as long as one of the specified types match for (let i = 0; i < types.length && !isValid; i++) { const { valid, expectedType } = assertType(value, types[i]) expectedTypes.push(expectedType || '') isValid = valid } if (!isValid) { warn(getInvalidTypeMessage(name, value, expectedTypes)) return } } // custom validator if (validator && !validator(value)) { warn('Invalid prop: custom validator check failed for prop "' + name + '".') } } const isSimpleType = /*#__PURE__*/ makeMap( 'String,Number,Boolean,Function,Symbol' ) /** * dev only */ function assertType(value, type) { let valid const expectedType = getType(type) if (isSimpleType(expectedType)) { const t = typeof value valid = t === expectedType.toLowerCase() // for primitive wrapper objects if (!valid && t === 'object') { valid = value instanceof type } } else if (expectedType === 'Object') { valid = isObject(value) } else if (expectedType === 'Array') { valid = isArray(value) } else { valid = value instanceof type } return { valid, expectedType } } /** * dev only */ function getInvalidTypeMessage(name, value, expectedTypes) { let message = `Invalid prop: type check failed for prop "${name}".` + ` Expected ${expectedTypes.map(capitalize).join(', ')}` const expectedType = expectedTypes[0] const receivedType = toRawType(value) const expectedValue = styleValue(value, expectedType) const receivedValue = styleValue(value, receivedType) // check if we need to specify expected value if ( expectedTypes.length === 1 && isExplicable(expectedType) && !isBoolean(expectedType, receivedType) ) { message += ` with value ${expectedValue}` } message += `, got ${receivedType} ` // check if we need to specify received value if (isExplicable(receivedType)) { message += `with value ${receivedValue}.` } return message } /** * dev only */ function styleValue(value, type) { if (type === 'String') { return `"${value}"` } else if (type === 'Number') { return `${Number(value)}` } else { return `${value}` } } /** * dev only */ function isExplicable(type) { const explicitTypes = ['string', 'number', 'boolean'] return explicitTypes.some(elem => type.toLowerCase() === elem) } /** * dev only */ function isBoolean(...args) { return args.some(elem => elem.toLowerCase() === 'boolean') } function injectHook(type, hook, target = currentInstance, prepend = false) { if (target) { const hooks = target[type] || (target[type] = []) // cache the error handling wrapper for injected hooks so the same hook // can be properly deduped by the scheduler. "__weh" stands for "with error // handling". const wrappedHook = hook.__weh || (hook.__weh = (...args) => { if (target.isUnmounted) { return } // disable tracking inside all lifecycle hooks // since they can potentially be called inside effects. pauseTracking() // Set currentInstance during hook invocation. // This assumes the hook does not synchronously trigger other hooks, which // can only be false when the user does something really funky. setCurrentInstance(target) const res = callWithAsyncErrorHandling(hook, target, type, args) setCurrentInstance(null) resetTracking() return res }) if (prepend) { hooks.unshift(wrappedHook) } else { hooks.push(wrappedHook) } return wrappedHook } else if (process.env.NODE_ENV !== 'production') { const apiName = `on${capitalize( ErrorTypeStrings[type].replace(/ hook$/, '') )}` warn( `${apiName} is called when there is no active component instance to be ` + `associated with. ` + `Lifecycle injection APIs can only be used during execution of setup().` + `` ) } } const createHook = lifecycle => (hook, target = currentInstance) => // post-create lifecycle registrations are noops during SSR !isInSSRComponentSetup && injectHook(lifecycle, hook, target) const onBeforeMount = createHook('bm' /* BEFORE_MOUNT */) const onMounted = createHook('m' /* MOUNTED */) const onBeforeUpdate = createHook('bu' /* BEFORE_UPDATE */) const onUpdated = createHook('u' /* UPDATED */) const onBeforeUnmount = createHook('bum' /* BEFORE_UNMOUNT */) const onUnmounted = createHook('um' /* UNMOUNTED */) const onRenderTriggered = createHook('rtg' /* RENDER_TRIGGERED */) const onRenderTracked = createHook('rtc' /* RENDER_TRACKED */) const onErrorCaptured = (hook, target = currentInstance) => { injectHook('ec' /* ERROR_CAPTURED */, hook, target) } const isKeepAlive = vnode => vnode.type.__isKeepAlive function onActivated(hook, target) { registerKeepAliveHook(hook, 'a' /* ACTIVATED */, target) } function onDeactivated(hook, target) { registerKeepAliveHook(hook, 'da' /* DEACTIVATED */, target) } function registerKeepAliveHook(hook, type, target = currentInstance) { // cache the deactivate branch check wrapper for injected hooks so the same // hook can be properly deduped by the scheduler. "__wdc" stands for "with // deactivation check". const wrappedHook = hook.__wdc || (hook.__wdc = () => { // only fire the hook if the target instance is NOT in a deactivated branch. let current = target while (current) { if (current.isDeactivated) { return } current = current.parent } hook() }) injectHook(type, wrappedHook, target) // In addition to registering it on the target instance, we walk up the parent // chain and register it on all ancestor instances that are keep-alive roots. // This avoids the need to walk the entire component tree when invoking these // hooks, and more importantly, avoids the need to track child components in // arrays. if (target) { let current = target.parent while (current && current.parent) { if (isKeepAlive(current.parent.vnode)) { injectToKeepAliveRoot(wrappedHook, type, target, current) } current = current.parent } } } function injectToKeepAliveRoot(hook, type, target, keepAliveRoot) { // injectHook wraps the original for error handling, so make sure to remove // the wrapped version. const injected = injectHook(type, hook, keepAliveRoot, true /* prepend */) onUnmounted(() => { remove(keepAliveRoot[type], injected) }, target) } /** Runtime helper for applying directives to a vnode. Example usage: const comp = resolveComponent('comp') const foo = resolveDirective('foo') const bar = resolveDirective('bar') return withDirectives(h(comp), [ [foo, this.x], [bar, this.y] ]) */ const isBuiltInDirective = /*#__PURE__*/ makeMap( 'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text' ) function validateDirectiveName(name) { if (isBuiltInDirective(name)) { warn('Do not use built-in directive ids as custom directive id: ' + name) } } function createAppContext() { return { app: null, config: { isNativeTag: NO, performance: false, globalProperties: {}, optionMergeStrategies: {}, isCustomElement: NO, errorHandler: undefined, warnHandler: undefined }, mixins: [], components: {}, directives: {}, provides: Object.create(null) } } let uid$1 = 0 // fixed by xxxxxx function createAppAPI() { return function createApp(rootComponent, rootProps = null) { if (rootProps != null && !isObject(rootProps)) { process.env.NODE_ENV !== 'production' && warn(`root props passed to app.mount() must be an object.`) rootProps = null } const context = createAppContext() const installedPlugins = new Set() // fixed by xxxxxx // let isMounted = false const app = (context.app = { _uid: uid$1++, _component: rootComponent, _props: rootProps, _container: null, _context: context, version, get config() { return context.config }, set config(v) { if (process.env.NODE_ENV !== 'production') { warn( `app.config cannot be replaced. Modify individual options instead.` ) } }, use(plugin, ...options) { if (installedPlugins.has(plugin)) { process.env.NODE_ENV !== 'production' && warn(`Plugin has already been applied to target app.`) } else if (plugin && isFunction(plugin.install)) { installedPlugins.add(plugin) plugin.install(app, ...options) } else if (isFunction(plugin)) { installedPlugins.add(plugin) plugin(app, ...options) } else if (process.env.NODE_ENV !== 'production') { warn( `A plugin must either be a function or an object with an "install" ` + `function.` ) } return app }, mixin(mixin) { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin) } else if (process.env.NODE_ENV !== 'production') { warn( 'Mixin has already been applied to target app' + (mixin.name ? `: ${mixin.name}` : '') ) } } else if (process.env.NODE_ENV !== 'production') { warn('Mixins are only available in builds supporting Options API') } return app }, component(name, component) { if (process.env.NODE_ENV !== 'production') { validateComponentName(name, context.config) } if (!component) { return context.components[name] } if (process.env.NODE_ENV !== 'production' && context.components[name]) { warn(`Component "${name}" has already been registered in target app.`) } context.components[name] = component return app }, directive(name, directive) { if (process.env.NODE_ENV !== 'production') { validateDirectiveName(name) } if (!directive) { return context.directives[name] } if (process.env.NODE_ENV !== 'production' && context.directives[name]) { warn(`Directive "${name}" has already been registered in target app.`) } context.directives[name] = directive return app }, // fixed by xxxxxx mount() {}, // fixed by xxxxxx unmount() {}, provide(key, value) { if (process.env.NODE_ENV !== 'production' && key in context.provides) { warn( `App already provides property with key "${String(key)}". ` + `It will be overwritten with the new value.` ) } // TypeScript doesn't allow symbols as index type // https://github.com/Microsoft/TypeScript/issues/24587 context.provides[key] = value return app } }) return app } } const queuePostRenderEffect = queuePostFlushCb // Simple effect. function watchEffect(effect, options) { return doWatch(effect, null, options) } // initial value for watchers to trigger on undefined initial values const INITIAL_WATCHER_VALUE = {} // implementation function watch(source, cb, options) { if (process.env.NODE_ENV !== 'production' && !isFunction(cb)) { warn( `\`watch(fn, options?)\` signature has been moved to a separate API. ` + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + `supports \`watch(source, cb, options?) signature.` ) } return doWatch(source, cb, options) } function doWatch( source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ, instance = currentInstance ) { if (process.env.NODE_ENV !== 'production' && !cb) { if (immediate !== undefined) { warn( `watch() "immediate" option is only respected when using the ` + `watch(source, callback, options?) signature.` ) } if (deep !== undefined) { warn( `watch() "deep" option is only respected when using the ` + `watch(source, callback, options?) signature.` ) } } const warnInvalidSource = s => { warn( `Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + `a reactive object, or an array of these types.` ) } let getter const isRefSource = isRef(source) if (isRefSource) { getter = () => source.value } else if (isReactive(source)) { getter = () => source deep = true } else if (isArray(source)) { getter = () => source.map(s => { if (isRef(s)) { return s.value } else if (isReactive(s)) { return traverse(s) } else if (isFunction(s)) { return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */) } else { process.env.NODE_ENV !== 'production' && warnInvalidSource(s) } }) } else if (isFunction(source)) { if (cb) { // getter with cb getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */) } else { // no cb -> simple effect getter = () => { if (instance && instance.isUnmounted) { return } if (cleanup) { cleanup() } return callWithErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [ onInvalidate ]) } } } else { getter = NOOP process.env.NODE_ENV !== 'production' && warnInvalidSource(source) } if (cb && deep) { const baseGetter = getter getter = () => traverse(baseGetter()) } let cleanup const onInvalidate = fn => { cleanup = runner.options.onStop = () => { callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */) } } let oldValue = isArray(source) ? [] : INITIAL_WATCHER_VALUE const job = () => { if (!runner.active) { return } if (cb) { // watch(source, cb) const newValue = runner() if (deep || isRefSource || hasChanged(newValue, oldValue)) { // cleanup before running cb again if (cleanup) { cleanup() } callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ newValue, // pass undefined as the old value when it's changed for the first time oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, onInvalidate ]) oldValue = newValue } } else { // watchEffect runner() } } // important: mark the job as a watcher callback so that scheduler knows it // it is allowed to self-trigger (#1727) job.allowRecurse = !!cb let scheduler if (flush === 'sync') { scheduler = job } else if (flush === 'pre') { // ensure it's queued before component updates (which have positive ids) job.id = -1 scheduler = () => { if (!instance || instance.isMounted) { queuePreFlushCb(job) } else { // with 'pre' option, the first call must happen before // the component is mounted so it is called synchronously. job() } } } else { scheduler = () => queuePostRenderEffect(job, instance && instance.suspense) } const runner = effect(getter, { lazy: true, onTrack, onTrigger, scheduler }) recordInstanceBoundEffect(runner) // initial run if (cb) { if (immediate) { job() } else { oldValue = runner() } } else { runner() } return () => { stop(runner) if (instance) { remove(instance.effects, runner) } } } // this.$watch function instanceWatch(source, cb, options) { const publicThis = this.proxy const getter = isString(source) ? () => publicThis[source] : source.bind(publicThis) return doWatch(getter, cb.bind(publicThis), options, this) } function traverse(value, seen = new Set()) { if (!isObject(value) || seen.has(value)) { return value } seen.add(value) if (isRef(value)) { traverse(value.value, seen) } else if (isArray(value)) { for (let i = 0; i < value.length; i++) { traverse(value[i], seen) } } else if (value instanceof Map) { value.forEach((v, key) => { // to register mutation dep for existing keys traverse(value.get(key), seen) }) } else if (value instanceof Set) { value.forEach(v => { traverse(v, seen) }) } else { for (const key in value) { traverse(value[key], seen) } } return value } function provide(key, value) { if (!currentInstance) { if (process.env.NODE_ENV !== 'production') { warn(`provide() can only be used inside setup().`) } } else { let provides = currentInstance.provides // by default an instance inherits its parent's provides object // but when it needs to provide values of its own, it creates its // own provides object using parent provides object as prototype. // this way in `inject` we can simply look up injections from direct // parent and let the prototype chain do the work. const parentProvides = currentInstance.parent && currentInstance.parent.provides if (parentProvides === provides) { provides = currentInstance.provides = Object.create(parentProvides) } // TS doesn't allow symbol as index type provides[key] = value } } function inject(key, defaultValue) { // fallback to `currentRenderingInstance` so that this can be called in // a functional component const instance = currentInstance || currentRenderingInstance if (instance) { const provides = instance.provides if (key in provides) { // TS doesn't allow symbol as index type return provides[key] } else if (arguments.length > 1) { return defaultValue } else if (process.env.NODE_ENV !== 'production') { warn(`injection "${String(key)}" not found.`) } } else if (process.env.NODE_ENV !== 'production') { warn(`inject() can only be used inside setup() or functional components.`) } } function createDuplicateChecker() { const cache = Object.create(null) return (type, key) => { if (cache[key]) { warn(`${type} property "${key}" is already defined in ${cache[key]}.`) } else { cache[key] = type } } } let isInBeforeCreate = false function applyOptions( instance, options, deferredData = [], deferredWatch = [], asMixin = false ) { const { // composition mixins, extends: extendsOptions, // state data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, // assets components, directives, // lifecycle beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeUnmount, unmounted, render, renderTracked, renderTriggered, errorCaptured } = options const publicThis = instance.proxy const ctx = instance.ctx const globalMixins = instance.appContext.mixins if (asMixin && render && instance.render === NOOP) { instance.render = render } // applyOptions is called non-as-mixin once per instance if (!asMixin) { isInBeforeCreate = true callSyncHook('beforeCreate', options, publicThis, globalMixins) isInBeforeCreate = false // global mixins are applied first applyMixins(instance, globalMixins, deferredData, deferredWatch) } // extending a base component... if (extendsOptions) { applyOptions(instance, extendsOptions, deferredData, deferredWatch, true) } // local mixins if (mixins) { applyMixins(instance, mixins, deferredData, deferredWatch) } const checkDuplicateProperties = process.env.NODE_ENV !== 'production' ? createDuplicateChecker() : null if (process.env.NODE_ENV !== 'production') { const [propsOptions] = instance.propsOptions if (propsOptions) { for (const key in propsOptions) { checkDuplicateProperties('Props' /* PROPS */, key) } } } // options initialization order (to be consistent with Vue 2): // - props (already done outside of this function) // - inject // - methods // - data (deferred since it relies on `this` access) // - computed // - watch (deferred since it relies on `this` access) // fixed by xxxxxx if (!__VUE_CREATED_DEFERRED__ && injectOptions) { if (isArray(injectOptions)) { for (let i = 0; i < injectOptions.length; i++) { const key = injectOptions[i] ctx[key] = inject(key) if (process.env.NODE_ENV !== 'production') { checkDuplicateProperties('Inject' /* INJECT */, key) } } } else { for (const key in injectOptions) { const opt = injectOptions[key] if (isObject(opt)) { ctx[key] = inject(opt.from, opt.default) } else { ctx[key] = inject(opt) } if (process.env.NODE_ENV !== 'production') { checkDuplicateProperties('Inject' /* INJECT */, key) } } } } if (methods) { for (const key in methods) { const methodHandler = methods[key] if (isFunction(methodHandler)) { ctx[key] = methodHandler.bind(publicThis) if (process.env.NODE_ENV !== 'production') { checkDuplicateProperties('Methods' /* METHODS */, key) } } else if (process.env.NODE_ENV !== 'production') { warn( `Method "${key}" has type "${typeof methodHandler}" in the component definition. ` + `Did you reference the function correctly?` ) } } } if (!asMixin) { if (deferredData.length) { deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)) } if (dataOptions) { resolveData(instance, dataOptions, publicThis) } if (process.env.NODE_ENV !== 'production') { const rawData = toRaw(instance.data) for (const key in rawData) { checkDuplicateProperties('Data' /* DATA */, key) // expose data on ctx during dev if (key[0] !== '$' && key[0] !== '_') { Object.defineProperty(ctx, key, { configurable: true, enumerable: true, get: () => rawData[key], set: NOOP }) } } } } else if (dataOptions) { deferredData.push(dataOptions) } if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key] const get = isFunction(opt) ? opt.bind(publicThis, publicThis) : isFunction(opt.get) ? opt.get.bind(publicThis, publicThis) : NOOP if (process.env.NODE_ENV !== 'production' && get === NOOP) { warn(`Computed property "${key}" has no getter.`) } const set = !isFunction(opt) && isFunction(opt.set) ? opt.set.bind(publicThis) : process.env.NODE_ENV !== 'production' ? () => { warn( `Write operation failed: computed property "${key}" is readonly.` ) } : NOOP const c = computed$1({ get, set }) Object.defineProperty(ctx, key, { enumerable: true, configurable: true, get: () => c.value, set: v => (c.value = v) }) if (process.env.NODE_ENV !== 'production') { checkDuplicateProperties('Computed' /* COMPUTED */, key) } } } if (watchOptions) { deferredWatch.push(watchOptions) } if (!asMixin && deferredWatch.length) { deferredWatch.forEach(watchOptions => { for (const key in watchOptions) { createWatcher(watchOptions[key], ctx, publicThis, key) } }) } // fixed by xxxxxx if (!__VUE_CREATED_DEFERRED__ && provideOptions) { const provides = isFunction(provideOptions) ? provideOptions.call(publicThis) : provideOptions for (const key in provides) { provide(key, provides[key]) } } // asset options. // To reduce memory usage, only components with mixins or extends will have // resolved asset registry attached to instance. if (asMixin) { if (components) { extend( instance.components || (instance.components = extend({}, instance.type.components)), components ) } if (directives) { extend( instance.directives || (instance.directives = extend({}, instance.type.directives)), directives ) } } // fixed by xxxxxx // lifecycle options if (__VUE_CREATED_DEFERRED__) { ctx.$callSyncHook = function(name) { return callSyncHook(name, options, publicThis, globalMixins) } } else if (!asMixin) { callSyncHook('created', options, publicThis, globalMixins) } if (beforeMount) { onBeforeMount(beforeMount.bind(publicThis)) } if (mounted) { onMounted(mounted.bind(publicThis)) } if (beforeUpdate) { onBeforeUpdate(beforeUpdate.bind(publicThis)) } if (updated) { onUpdated(updated.bind(publicThis)) } if (activated) { onActivated(activated.bind(publicThis)) } if (deactivated) { onDeactivated(deactivated.bind(publicThis)) } if (errorCaptured) { onErrorCaptured(errorCaptured.bind(publicThis)) } if (renderTracked) { onRenderTracked(renderTracked.bind(publicThis)) } if (renderTriggered) { onRenderTriggered(renderTriggered.bind(publicThis)) } if (beforeUnmount) { onBeforeUnmount(beforeUnmount.bind(publicThis)) } if (unmounted) { onUnmounted(unmounted.bind(publicThis)) } // fixed by xxxxxx if (instance.ctx.$onApplyOptions) { instance.ctx.$onApplyOptions(options, instance, publicThis) } } function callSyncHook(name, options, ctx, globalMixins) { callHookFromMixins(name, globalMixins, ctx) const { extends: base, mixins } = options if (base) { callHookFromExtends(name, base, ctx) } if (mixins) { callHookFromMixins(name, mixins, ctx) } const selfHook = options[name] if (selfHook) { selfHook.call(ctx) } } function callHookFromExtends(name, base, ctx) { if (base.extends) { callHookFromExtends(name, base.extends, ctx) } const baseHook = base[name] if (baseHook) { baseHook.call(ctx) } } function callHookFromMixins(name, mixins, ctx) { for (let i = 0; i < mixins.length; i++) { const chainedMixins = mixins[i].mixins if (chainedMixins) { callHookFromMixins(name, chainedMixins, ctx) } const fn = mixins[i][name] if (fn) { fn.call(ctx) } } } function applyMixins(instance, mixins, deferredData, deferredWatch) { for (let i = 0; i < mixins.length; i++) { applyOptions(instance, mixins[i], deferredData, deferredWatch, true) } } function resolveData(instance, dataFn, publicThis) { if (process.env.NODE_ENV !== 'production' && !isFunction(dataFn)) { warn( `The data option must be a function. ` + `Plain object usage is no longer supported.` ) } const data = dataFn.call(publicThis, publicThis) if (process.env.NODE_ENV !== 'production' && isPromise(data)) { warn( `data() returned a Promise - note data() cannot be async; If you ` + `intend to perform data fetching before component renders, use ` + `async setup() + .` ) } if (!isObject(data)) { process.env.NODE_ENV !== 'production' && warn(`data() should return an object.`) } else if (instance.data === EMPTY_OBJ) { instance.data = reactive(data) } else { // existing data: this is a mixin or extends. extend(instance.data, data) } } function createWatcher(raw, ctx, publicThis, key) { const getter = () => publicThis[key] if (isString(raw)) { const handler = ctx[raw] if (isFunction(handler)) { watch(getter, handler) } else if (process.env.NODE_ENV !== 'production') { warn(`Invalid watch handler specified by key "${raw}"`, handler) } } else if (isFunction(raw)) { watch(getter, raw.bind(publicThis)) } else if (isObject(raw)) { if (isArray(raw)) { raw.forEach(r => createWatcher(r, ctx, publicThis, key)) } else { const handler = isFunction(raw.handler) ? raw.handler.bind(publicThis) : ctx[raw.handler] if (isFunction(handler)) { watch(getter, handler, raw) } else if (process.env.NODE_ENV !== 'production') { warn(`Invalid watch handler specified by key "${raw.handler}"`, handler) } } } else if (process.env.NODE_ENV !== 'production') { warn(`Invalid watch option: "${key}"`) } } function resolveMergedOptions(instance) { const raw = instance.type const { __merged, mixins, extends: extendsOptions } = raw if (__merged) return __merged const globalMixins = instance.appContext.mixins if (!globalMixins.length && !mixins && !extendsOptions) return raw const options = {} globalMixins.forEach(m => mergeOptions(options, m, instance)) mergeOptions(options, raw, instance) return (raw.__merged = options) } function mergeOptions(to, from, instance) { const strats = instance.appContext.config.optionMergeStrategies const { mixins, extends: extendsOptions } = from extendsOptions && mergeOptions(to, extendsOptions, instance) mixins && mixins.forEach(m => mergeOptions(to, m, instance)) for (const key in from) { if (strats && hasOwn(strats, key)) { to[key] = strats[key](to[key], from[key], instance.proxy, key) } else { to[key] = from[key] } } } const publicPropertiesMap = extend(Object.create(null), { $: i => i, $el: i => i.vnode.el, $data: i => i.data, $props: i => process.env.NODE_ENV !== 'production' ? shallowReadonly(i.props) : i.props, $attrs: i => process.env.NODE_ENV !== 'production' ? shallowReadonly(i.attrs) : i.attrs, $slots: i => process.env.NODE_ENV !== 'production' ? shallowReadonly(i.slots) : i.slots, $refs: i => process.env.NODE_ENV !== 'production' ? shallowReadonly(i.refs) : i.refs, $parent: i => i.parent && i.parent.proxy, $root: i => i.root && i.root.proxy, $emit: i => i.emit, $options: i => (__VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type), $forceUpdate: i => () => queueJob(i.update), // $nextTick: () => nextTick, // fixed by xxxxxx $watch: i => (__VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP) }) const PublicInstanceProxyHandlers = { get({ _: instance }, key) { const { ctx, setupState, data, props, accessCache, type, appContext } = instance // let @vue/reactivity know it should never observe Vue public instances. if (key === '__v_skip' /* SKIP */) { return true } // data / props / ctx // This getter gets called for every property access on the render context // during render and is a major hotspot. The most expensive part of this // is the multiple hasOwn() calls. It's much faster to do a simple property // access on a plain object, so we use an accessCache object (with null // prototype) to memoize what access type a key corresponds to. let normalizedProps if (key[0] !== '$') { const n = accessCache[key] if (n !== undefined) { switch (n) { case 0 /* SETUP */: return setupState[key] case 1 /* DATA */: return data[key] case 3 /* CONTEXT */: return ctx[key] case 2 /* PROPS */: return props[key] // default: just fallthrough } } else if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) { accessCache[key] = 0 /* SETUP */ return setupState[key] } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { accessCache[key] = 1 /* DATA */ return data[key] } else if ( // only cache other properties when instance has declared (thus stable) // props (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key) ) { accessCache[key] = 2 /* PROPS */ return props[key] } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { accessCache[key] = 3 /* CONTEXT */ return ctx[key] } else if (!__VUE_OPTIONS_API__ || !isInBeforeCreate) { accessCache[key] = 4 /* OTHER */ } } const publicGetter = publicPropertiesMap[key] let cssModule, globalProperties // public $xxx properties if (publicGetter) { if (key === '$attrs') { track(instance, 'get' /* GET */, key) process.env.NODE_ENV !== 'production' && markAttrsAccessed() } return publicGetter(instance) } else if ( // css module (injected by vue-loader) (cssModule = type.__cssModules) && (cssModule = cssModule[key]) ) { return cssModule } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { // user may set custom properties to `this` that start with `$` accessCache[key] = 3 /* CONTEXT */ return ctx[key] } else if ( // global properties ((globalProperties = appContext.config.globalProperties), hasOwn(globalProperties, key)) ) { return globalProperties[key] } else if ( process.env.NODE_ENV !== 'production' && currentRenderingInstance && (!isString(key) || // #1091 avoid internal isRef/isVNode checks on component instance leading // to infinite warning loop key.indexOf('__v') !== 0) ) { if ( data !== EMPTY_OBJ && (key[0] === '$' || key[0] === '_') && hasOwn(data, key) ) { warn( `Property ${JSON.stringify( key )} must be accessed via $data because it starts with a reserved ` + `character ("$" or "_") and is not proxied on the render context.` ) } else { warn( `Property ${JSON.stringify(key)} was accessed during render ` + `but is not defined on instance.` ) } } }, set({ _: instance }, key, value) { const { data, setupState, ctx } = instance if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) { setupState[key] = value } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { data[key] = value } else if (key in instance.props) { process.env.NODE_ENV !== 'production' && warn( `Attempting to mutate prop "${key}". Props are readonly.`, instance ) return false } if (key[0] === '$' && key.slice(1) in instance) { process.env.NODE_ENV !== 'production' && warn( `Attempting to mutate public property "${key}". ` + `Properties starting with $ are reserved and readonly.`, instance ) return false } else { if ( process.env.NODE_ENV !== 'production' && key in instance.appContext.config.globalProperties ) { Object.defineProperty(ctx, key, { enumerable: true, configurable: true, value }) } else { ctx[key] = value } } return true }, has( { _: { data, setupState, accessCache, ctx, appContext, propsOptions } }, key ) { let normalizedProps return ( accessCache[key] !== undefined || (data !== EMPTY_OBJ && hasOwn(data, key)) || (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) || ((normalizedProps = propsOptions[0]) && hasOwn(normalizedProps, key)) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || hasOwn(appContext.config.globalProperties, key) ) } } if (process.env.NODE_ENV !== 'production' && !false) { PublicInstanceProxyHandlers.ownKeys = target => { warn( `Avoid app logic that relies on enumerating keys on a component instance. ` + `The keys will be empty in production mode to avoid performance overhead.` ) return Reflect.ownKeys(target) } } const RuntimeCompiledPublicInstanceProxyHandlers = extend( {}, PublicInstanceProxyHandlers, { get(target, key) { // fast path for unscopables when using `with` block if (key === Symbol.unscopables) { return } return PublicInstanceProxyHandlers.get(target, key, target) }, has(_, key) { const has = key[0] !== '_' && !isGloballyWhitelisted(key) if ( process.env.NODE_ENV !== 'production' && !has && PublicInstanceProxyHandlers.has(_, key) ) { warn( `Property ${JSON.stringify( key )} should not start with _ which is a reserved prefix for Vue internals.` ) } return has } } ) // In dev mode, the proxy target exposes the same properties as seen on `this` // for easier console inspection. In prod mode it will be an empty object so // these properties definitions can be skipped. function createRenderContext(instance) { const target = {} // expose internal instance for proxy handlers Object.defineProperty(target, `_`, { configurable: true, enumerable: false, get: () => instance }) // expose public properties Object.keys(publicPropertiesMap).forEach(key => { Object.defineProperty(target, key, { configurable: true, enumerable: false, get: () => publicPropertiesMap[key](instance), // intercepted by the proxy so no need for implementation, // but needed to prevent set errors set: NOOP }) }) // expose global properties const { globalProperties } = instance.appContext.config Object.keys(globalProperties).forEach(key => { Object.defineProperty(target, key, { configurable: true, enumerable: false, get: () => globalProperties[key], set: NOOP }) }) return target } // dev only function exposePropsOnRenderContext(instance) { const { ctx, propsOptions: [propsOptions] } = instance if (propsOptions) { Object.keys(propsOptions).forEach(key => { Object.defineProperty(ctx, key, { enumerable: true, configurable: true, get: () => instance.props[key], set: NOOP }) }) } } // dev only function exposeSetupStateOnRenderContext(instance) { const { ctx, setupState } = instance Object.keys(toRaw(setupState)).forEach(key => { if (key[0] === '$' || key[0] === '_') { warn( `setup() return property ${JSON.stringify( key )} should not start with "$" or "_" ` + `which are reserved prefixes for Vue internals.` ) return } Object.defineProperty(ctx, key, { enumerable: true, configurable: true, get: () => setupState[key], set: NOOP }) }) } const emptyAppContext = createAppContext() let uid$2 = 0 function createComponentInstance(vnode, parent, suspense) { const type = vnode.type // inherit parent app context - or - if root, adopt from root vnode const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext const instance = { uid: uid$2++, vnode, type, parent, appContext, root: null, next: null, subTree: null, update: null, render: null, proxy: null, withProxy: null, effects: null, provides: parent ? parent.provides : Object.create(appContext.provides), accessCache: null, renderCache: [], // local resovled assets components: null, directives: null, // resolved props and emits options propsOptions: normalizePropsOptions(type, appContext), emitsOptions: normalizeEmitsOptions(type, appContext), // emit emit: null, emitted: null, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, props: EMPTY_OBJ, attrs: EMPTY_OBJ, slots: EMPTY_OBJ, refs: EMPTY_OBJ, setupState: EMPTY_OBJ, setupContext: null, // suspense related suspense, asyncDep: null, asyncResolved: false, // lifecycle hooks // not using enums here because it results in computed properties isMounted: false, isUnmounted: false, isDeactivated: false, bc: null, c: null, bm: null, m: null, bu: null, u: null, um: null, bum: null, da: null, a: null, rtg: null, rtc: null, ec: null } if (process.env.NODE_ENV !== 'production') { instance.ctx = createRenderContext(instance) } else { instance.ctx = { _: instance } } instance.root = parent ? parent.root : instance instance.emit = emit.bind(null, instance) if (process.env.NODE_ENV !== 'production' || false); return instance } let currentInstance = null const setCurrentInstance = instance => { currentInstance = instance } const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component') function validateComponentName(name, config) { const appIsNativeTag = config.isNativeTag || NO if (isBuiltInTag(name) || appIsNativeTag(name)) { warn( 'Do not use built-in or reserved HTML elements as component id: ' + name ) } } let isInSSRComponentSetup = false function setupComponent(instance, isSSR = false) { isInSSRComponentSetup = isSSR const { props, /* children, */ shapeFlag } = instance.vnode const isStateful = shapeFlag & 4 /* STATEFUL_COMPONENT */ initProps(instance, props, isStateful, isSSR) // initSlots(instance, children) // fixed by xxxxxx const setupResult = isStateful ? setupStatefulComponent(instance, isSSR) : undefined isInSSRComponentSetup = false return setupResult } function setupStatefulComponent(instance, isSSR) { const Component = instance.type if (process.env.NODE_ENV !== 'production') { if (Component.name) { validateComponentName(Component.name, instance.appContext.config) } if (Component.components) { const names = Object.keys(Component.components) for (let i = 0; i < names.length; i++) { validateComponentName(names[i], instance.appContext.config) } } if (Component.directives) { const names = Object.keys(Component.directives) for (let i = 0; i < names.length; i++) { validateDirectiveName(names[i]) } } } // 0. create render proxy property access cache instance.accessCache = {} // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers) if (process.env.NODE_ENV !== 'production') { exposePropsOnRenderContext(instance) } // 2. call setup() const { setup } = Component if (setup) { const setupContext = (instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null) currentInstance = instance pauseTracking() const setupResult = callWithErrorHandling( setup, instance, 0 /* SETUP_FUNCTION */, [ process.env.NODE_ENV !== 'production' ? shallowReadonly(instance.props) : instance.props, setupContext ] ) resetTracking() currentInstance = null if (isPromise(setupResult)) { if (isSSR) { // return the promise so server-renderer can wait on it return setupResult.then(resolvedResult => { handleSetupResult(instance, resolvedResult) }) } else if (process.env.NODE_ENV !== 'production') { warn( `setup() returned a Promise, but the version of Vue you are using ` + `does not support it yet.` ) } } else { handleSetupResult(instance, setupResult) } } else { finishComponentSetup(instance) } } function handleSetupResult(instance, setupResult, isSSR) { if (isFunction(setupResult)) { // setup returned an inline render function instance.render = setupResult } else if (isObject(setupResult)) { // if ((process.env.NODE_ENV !== 'production') && isVNode(setupResult)) { // warn( // `setup() should not return VNodes directly - ` + // `return a render function instead.` // ) // } // setup returned bindings. // assuming a render function compiled from template is present. if (process.env.NODE_ENV !== 'production' || false) { instance.devtoolsRawSetupState = setupResult } instance.setupState = proxyRefs(setupResult) if (process.env.NODE_ENV !== 'production') { exposeSetupStateOnRenderContext(instance) } } else if ( process.env.NODE_ENV !== 'production' && setupResult !== undefined ) { warn( `setup() should return an object. Received: ${ setupResult === null ? 'null' : typeof setupResult }` ) } finishComponentSetup(instance) } function finishComponentSetup(instance, isSSR) { const Component = instance.type // template / render function normalization if (!instance.render) { instance.render = Component.render || NOOP // for runtime-compiled render functions using `with` blocks, the render // proxy used needs a different `has` handler which is more performant and // also only allows a whitelist of globals to fallthrough. if (instance.render._rc) { instance.withProxy = new Proxy( instance.ctx, RuntimeCompiledPublicInstanceProxyHandlers ) } } // support for 2.x options if (__VUE_OPTIONS_API__) { currentInstance = instance applyOptions(instance, Component) currentInstance = null } // warn missing template/render if ( process.env.NODE_ENV !== 'production' && !Component.render && instance.render === NOOP ) { /* istanbul ignore if */ if (Component.template) { warn( `Component provided template option but ` + `runtime compilation is not supported in this build of Vue.` + ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` /* should not happen */ ) } else { warn(`Component is missing template or render function.`) } } } const attrHandlers = { get: (target, key) => { if (process.env.NODE_ENV !== 'production'); return target[key] }, set: () => { warn(`setupContext.attrs is readonly.`) return false }, deleteProperty: () => { warn(`setupContext.attrs is readonly.`) return false } } function createSetupContext(instance) { if (process.env.NODE_ENV !== 'production') { // We use getters in dev in case libs like test-utils overwrite instance // properties (overwrites should not be done in prod) return Object.freeze({ get attrs() { return new Proxy(instance.attrs, attrHandlers) }, get slots() { return shallowReadonly(instance.slots) }, get emit() { return (event, ...args) => instance.emit(event, ...args) } }) } else { return { attrs: instance.attrs, slots: instance.slots, emit: instance.emit } } } // record effects created during a component's setup() so that they can be // stopped when the component unmounts function recordInstanceBoundEffect(effect) { if (currentInstance) { ;(currentInstance.effects || (currentInstance.effects = [])).push(effect) } } const classifyRE = /(?:^|[-_])(\w)/g const classify = str => str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '') /* istanbul ignore next */ function formatComponentName(instance, Component, isRoot = false) { let name = isFunction(Component) ? Component.displayName || Component.name : Component.name if (!name && Component.__file) { const match = Component.__file.match(/([^/\\]+)\.vue$/) if (match) { name = match[1] } } if (!name && instance && instance.parent) { // try to infer the name based on reverse resolution const inferFromRegistry = registry => { for (const key in registry) { if (registry[key] === Component) { return key } } } name = inferFromRegistry( instance.components || instance.parent.type.components ) || inferFromRegistry(instance.appContext.components) } return name ? classify(name) : isRoot ? `App` : `Anonymous` } function computed$1(getterOrOptions) { const c = computed(getterOrOptions) recordInstanceBoundEffect(c.effect) return c } // Core API ------------------------------------------------------------------ const version = '3.0.0-rc.10' // import deepCopy from './deepCopy' /** * https://raw.githubusercontent.com/Tencent/westore/master/packages/westore/utils/diff.js */ const ARRAYTYPE = '[object Array]' const OBJECTTYPE = '[object Object]' // const FUNCTIONTYPE = '[object Function]' function diff(current, pre) { const result = {} syncKeys(current, pre) _diff(current, pre, '', result) return result } function syncKeys(current, pre) { current = unref(current) if (current === pre) return const rootCurrentType = toTypeString(current) const rootPreType = toTypeString(pre) if (rootCurrentType == OBJECTTYPE && rootPreType == OBJECTTYPE) { for (let key in pre) { const currentValue = current[key] if (currentValue === undefined) { current[key] = null } else { syncKeys(currentValue, pre[key]) } } } else if (rootCurrentType == ARRAYTYPE && rootPreType == ARRAYTYPE) { if (current.length >= pre.length) { pre.forEach((item, index) => { syncKeys(current[index], item) }) } } } function _diff(current, pre, path, result) { current = unref(current) if (current === pre) return const rootCurrentType = toTypeString(current) const rootPreType = toTypeString(pre) if (rootCurrentType == OBJECTTYPE) { if ( rootPreType != OBJECTTYPE || Object.keys(current).length < Object.keys(pre).length ) { setResult(result, path, current) } else { for (let key in current) { const currentValue = unref(current[key]) const preValue = pre[key] const currentType = toTypeString(currentValue) const preType = toTypeString(preValue) if (currentType != ARRAYTYPE && currentType != OBJECTTYPE) { if (currentValue != preValue) { setResult( result, (path == '' ? '' : path + '.') + key, currentValue ) } } else if (currentType == ARRAYTYPE) { if (preType != ARRAYTYPE) { setResult( result, (path == '' ? '' : path + '.') + key, currentValue ) } else { if (currentValue.length < preValue.length) { setResult( result, (path == '' ? '' : path + '.') + key, currentValue ) } else { currentValue.forEach((item, index) => { _diff( item, preValue[index], (path == '' ? '' : path + '.') + key + '[' + index + ']', result ) }) } } } else if (currentType == OBJECTTYPE) { if ( preType != OBJECTTYPE || Object.keys(currentValue).length < Object.keys(preValue).length ) { setResult( result, (path == '' ? '' : path + '.') + key, currentValue ) } else { for (let subKey in currentValue) { _diff( currentValue[subKey], preValue[subKey], (path == '' ? '' : path + '.') + key + '.' + subKey, result ) } } } } } } else if (rootCurrentType == ARRAYTYPE) { if (rootPreType != ARRAYTYPE) { setResult(result, path, current) } else { if (current.length < pre.length) { setResult(result, path, current) } else { current.forEach((item, index) => { _diff(item, pre[index], path + '[' + index + ']', result) }) } } } else { setResult(result, path, current) } } function setResult(result, k, v) { result[k] = v //deepCopy(v) } function hasComponentEffect(instance) { return queue.includes(instance.update) } function flushCallbacks(instance) { const ctx = instance.ctx const callbacks = ctx.__next_tick_callbacks if (callbacks && callbacks.length) { if (process.env.VUE_APP_DEBUG) { const mpInstance = ctx.$scope console.log( '[' + +new Date() + '][' + (mpInstance.is || mpInstance.route) + '][' + instance.uid + ']:flushCallbacks[' + callbacks.length + ']' ) } const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } } function nextTick$1(instance, fn) { const ctx = instance.ctx if (!ctx.__next_tick_pending && !hasComponentEffect(instance)) { if (process.env.VUE_APP_DEBUG) { const mpInstance = ctx.$scope console.log( '[' + +new Date() + '][' + (mpInstance.is || mpInstance.route) + '][' + instance.uid + ']:nextVueTick' ) } return nextTick(fn && fn.bind(instance.proxy)) } if (process.env.VUE_APP_DEBUG) { const mpInstance = ctx.$scope console.log( '[' + +new Date() + '][' + (mpInstance.is || mpInstance.route) + '][' + instance.uid + ']:nextMPTick' ) } let _resolve if (!ctx.__next_tick_callbacks) { ctx.__next_tick_callbacks = [] } ctx.__next_tick_callbacks.push(() => { if (fn) { callWithErrorHandling( fn.bind(instance.proxy), instance, 14 /* SCHEDULER */ ) } else if (_resolve) { _resolve(instance.proxy) } }) return new Promise(resolve => { _resolve = resolve }) } function getMPInstanceData(instance, keys) { const data = instance.data const ret = Object.create(null) //仅同步 data 中有的数据 keys.forEach(key => { ret[key] = data[key] }) return ret } function getVueInstanceData(instance) { const { data, setupState, ctx } = instance const keys = new Set() const ret = Object.create(null) Object.keys(setupState).forEach(key => { keys.add(key) ret[key] = setupState[key] }) if (data) { Object.keys(data).forEach(key => { if (!keys.has(key)) { keys.add(key) ret[key] = data[key] } }) } if (__VUE_OPTIONS_API__) { if (ctx.$computedKeys) { ctx.$computedKeys.forEach(key => { if (!keys.has(key)) { keys.add(key) ret[key] = ctx[key] } }) } } if (ctx.$mp) { // TODO extend(ret, ctx.$mp.data || {}) } // TODO form-field // track return { keys, data: JSON.parse(JSON.stringify(ret)) } } function patch(instance) { const ctx = instance.ctx const mpType = ctx.mpType if (mpType === 'page' || mpType === 'component') { const start = Date.now() const mpInstance = ctx.$scope const { keys, data } = getVueInstanceData(instance) // data.__webviewId__ = mpInstance.data.__webviewId__ const diffData = diff(data, getMPInstanceData(mpInstance, keys)) if (Object.keys(diffData).length) { if (process.env.VUE_APP_DEBUG) { console.log( '[' + +new Date() + '][' + (mpInstance.is || mpInstance.route) + '][' + instance.uid + '][耗时' + (Date.now() - start) + ']差量更新', JSON.stringify(diffData) ) } ctx.__next_tick_pending = true mpInstance.setData(diffData, () => { ctx.__next_tick_pending = false flushCallbacks(instance) }) } else { flushCallbacks(instance) } } } function initAppConfig(appConfig) { appConfig.globalProperties.$nextTick = function $nextTick(fn) { return nextTick$1(this.$, fn) } } function onApplyOptions(options, instance, publicThis) { instance.appContext.config.globalProperties.$applyOptions( options, instance, publicThis ) const computedOptions = options.computed if (computedOptions) { const keys = Object.keys(computedOptions) if (keys.length) { const ctx = instance.ctx if (!ctx.$computedKeys) { ctx.$computedKeys = [] } ctx.$computedKeys.push(...keys) } } // remove delete instance.ctx.$onApplyOptions } var MPType ;(function(MPType) { MPType['APP'] = 'app' MPType['PAGE'] = 'page' MPType['COMPONENT'] = 'component' })(MPType || (MPType = {})) const queuePostRenderEffect$1 = queuePostFlushCb function mountComponent(initialVNode, options) { const instance = (initialVNode.component = createComponentInstance( initialVNode, options.parentComponent, null )) if (__VUE_OPTIONS_API__) { instance.ctx.$onApplyOptions = onApplyOptions instance.ctx.$children = [] } if (options.mpType === 'app') { instance.render = NOOP } if (options.onBeforeSetup) { options.onBeforeSetup(instance, options) } if (process.env.NODE_ENV !== 'production') { pushWarningContext(initialVNode) } setupComponent(instance) if (__VUE_OPTIONS_API__) { // $children if (options.parentComponent && instance.proxy) { options.parentComponent.ctx.$children.push(instance.proxy) } } setupRenderEffect(instance) if (process.env.NODE_ENV !== 'production') { popWarningContext() } return instance.proxy } const prodEffectOptions = { scheduler: queueJob } function createDevEffectOptions(instance) { return { scheduler: queueJob, onTrack: instance.rtc ? e => invokeArrayFns(instance.rtc, e) : void 0, onTrigger: instance.rtg ? e => invokeArrayFns(instance.rtg, e) : void 0 } } function setupRenderEffect(instance) { // create reactive effect for rendering instance.update = effect(function componentEffect() { if (!instance.isMounted) { instance.render && instance.render.call(instance.proxy) patch(instance) } else { instance.render && instance.render.call(instance.proxy) // updateComponent const { bu, u } = instance // beforeUpdate hook if (bu) { invokeArrayFns(bu) } patch(instance) // updated hook if (u) { queuePostRenderEffect$1(u) } } }, process.env.NODE_ENV !== 'production' ? createDevEffectOptions(instance) : prodEffectOptions) } function unmountComponent(instance) { const { bum, effects, update, um } = instance // beforeUnmount hook if (bum) { invokeArrayFns(bum) } if (effects) { for (let i = 0; i < effects.length; i++) { stop(effects[i]) } } // update may be null if a component is unmounted before its async // setup has resolved. if (update) { stop(update) } // unmounted hook if (um) { queuePostRenderEffect$1(um) } queuePostRenderEffect$1(() => { instance.isUnmounted = true }) } const oldCreateApp = createAppAPI() function createVueApp(rootComponent, rootProps = null) { const app = oldCreateApp(rootComponent, rootProps) const appContext = app._context initAppConfig(appContext.config) const createVNode = initialVNode => { initialVNode.appContext = appContext initialVNode.shapeFlag = 6 /* COMPONENT */ return initialVNode } const createComponent = function createComponent(initialVNode, options) { return mountComponent(createVNode(initialVNode), options) } const destroyComponent = function destroyComponent(component) { return component && unmountComponent(component.$) } app.mount = function mount() { rootComponent.render = NOOP const instance = mountComponent(createVNode({ type: rootComponent }), { mpType: MPType.APP, mpInstance: null, parentComponent: null, slots: [], props: null }) instance.$app = app instance.$createComponent = createComponent instance.$destroyComponent = destroyComponent appContext.$appInstance = instance return instance } app.unmount = function unmount() { warn(`Cannot unmount an app.`) } return app } export { callWithAsyncErrorHandling, callWithErrorHandling, computed$1 as computed, createVueApp, customRef, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, logError, markRaw, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, provide, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, triggerRef, unref, version, warn, watch, watchEffect }