import { isSymbol, extend, isObject, toRawType, def, isArray, isString, isFunction, isPromise, capitalize, EMPTY_ARR, normalizeClass, normalizeStyle, isOn, remove, EMPTY_OBJ, NOOP, isGloballyWhitelisted, toNumber, invokeArrayFns, looseIndexOf, looseEqual, hyphenate, isHTMLTag, isSVGTag, isIntegerKey, hasOwn, hasChanged, camelize, getGlobalThis, isReservedProp, NO, isModelListener, makeMap, isSpecialBooleanAttr } from '@vue/shared'; export { camelize, capitalize, toDisplayString } 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; 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); } function logError(err, type, contextVNode) { if (process.env.NODE_ENV !== 'production') { const info = ErrorTypeStrings[type]; 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; 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 invalidateJob(job) { const i = queue.indexOf(job); if (i > -1) { queue[i] = null; } } 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); } } } let isHmrUpdating = false; const hmrDirtyComponents = new Set(); // Expose the HMR runtime on the global object // This makes it entirely tree-shakable without polluting the exports and makes // it easier to be used in toolings like vue-loader // Note: for a component to be eligible for HMR it also needs the __hmrId option // to be set so that its instances can be registered / removed. if (process.env.NODE_ENV !== 'production') { const globalObject = typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : {}; globalObject.__VUE_HMR_RUNTIME__ = { createRecord: tryWrap(createRecord), rerender: tryWrap(rerender), reload: tryWrap(reload) }; } const map = new Map(); function registerHMR(instance) { const id = instance.type.__hmrId; let record = map.get(id); if (!record) { createRecord(id); record = map.get(id); } record.add(instance); } function unregisterHMR(instance) { map.get(instance.type.__hmrId).delete(instance); } function createRecord(id) { if (map.has(id)) { return false } map.set(id, new Set()); return true } function rerender(id, newRender) { const record = map.get(id); if (!record) return // Array.from creates a snapshot which avoids the set being mutated during // updates Array.from(record).forEach(instance => { if (newRender) { instance.render = newRender; } instance.renderCache = []; // this flag forces child components with slot content to update isHmrUpdating = true; instance.update(); isHmrUpdating = false; }); } function reload(id, newComp) { const record = map.get(id); if (!record) return // Array.from creates a snapshot which avoids the set being mutated during // updates Array.from(record).forEach(instance => { const comp = instance.type; if (!hmrDirtyComponents.has(comp)) { // 1. Update existing comp definition to match new one extend(comp, newComp); for (const key in comp) { if (!(key in newComp)) { delete comp[key]; } } // 2. Mark component dirty. This forces the renderer to replace the component // on patch. hmrDirtyComponents.add(comp); // 3. Make sure to unmark the component after the reload. queuePostFlushCb(() => { hmrDirtyComponents.delete(comp); }); } if (instance.parent) { // 4. Force the parent instance to re-render. This will cause all updated // components to be unmounted and re-mounted. Queue the update so that we // don't end up forcing the same parent to re-render multiple times. queueJob(instance.parent.update); } else if (instance.appContext.reload) { // root instance mounted via createApp() has a reload method instance.appContext.reload(); } else if (typeof window !== 'undefined') { // root instance inside tree created via raw render(). Force reload. window.location.reload(); } else { console.warn( '[HMR] Root or manually mounted instance modified. Full reload required.' ); } }); } function tryWrap(fn) { return (id, arg) => { try { return fn(id, arg) } catch (e) { console.error(e); console.warn( `[HMR] Something went wrong during Vue component hot-reload. ` + `Full reload required.` ); } } } // mark the current rendering instance for asset resolution (e.g. // resolveComponent, resolveDirective) during render let currentRenderingInstance = null; function setCurrentRenderingInstance(instance) { currentRenderingInstance = instance; } // dev only flag to track whether $attrs was used during render. // If $attrs was used during render then the warning for failed attrs // fallthrough can be suppressed. let accessedAttrs = false; function markAttrsAccessed() { accessedAttrs = true; } function renderComponentRoot(instance) { const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx } = instance; let result; currentRenderingInstance = instance; if (process.env.NODE_ENV !== 'production') { accessedAttrs = false; } try { let fallthroughAttrs; if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) { // withProxy is a proxy with a different `has` trap only for // runtime-compiled render functions using `with` block. const proxyToUse = withProxy || proxy; result = normalizeVNode( render.call( proxyToUse, proxyToUse, renderCache, props, setupState, data, ctx ) ); fallthroughAttrs = attrs; } else { // functional const render = Component; // in dev, mark attrs accessed if optional props (attrs === props) if (process.env.NODE_ENV !== 'production' && attrs === props) { markAttrsAccessed(); } result = normalizeVNode( render.length > 1 ? render( props, process.env.NODE_ENV !== 'production' ? { get attrs() { markAttrsAccessed(); return attrs }, slots, emit } : { attrs, slots, emit } ) : render(props, null /* we know it doesn't need it */) ); fallthroughAttrs = Component.props ? attrs : getFunctionalFallthrough(attrs); } // attr merging // in dev mode, comments are preserved, and it's possible for a template // to have comments along side the root element which makes it a fragment let root = result; let setRoot = undefined; if (process.env.NODE_ENV !== 'production') { ;[root, setRoot] = getChildRoot(result); } if (Component.inheritAttrs !== false && fallthroughAttrs) { const keys = Object.keys(fallthroughAttrs); const { shapeFlag } = root; if (keys.length) { if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 6 /* COMPONENT */) { if (propsOptions && keys.some(isModelListener)) { // If a v-model listener (onUpdate:xxx) has a corresponding declared // prop, it indicates this component expects to handle v-model and // it should not fallthrough. // related: #1543, #1643, #1989 fallthroughAttrs = filterModelListeners( fallthroughAttrs, propsOptions ); } root = cloneVNode(root, fallthroughAttrs); } else if ( process.env.NODE_ENV !== 'production' && !accessedAttrs && root.type !== Comment ) { const allAttrs = Object.keys(attrs); const eventAttrs = []; const extraAttrs = []; for (let i = 0, l = allAttrs.length; i < l; i++) { const key = allAttrs[i]; if (isOn(key)) { // ignore v-model handlers when they fail to fallthrough if (!isModelListener(key)) { // remove `on`, lowercase first letter to reflect event casing // accurately eventAttrs.push(key[2].toLowerCase() + key.slice(3)); } } else { extraAttrs.push(key); } } if (extraAttrs.length) { warn( `Extraneous non-props attributes (` + `${extraAttrs.join(', ')}) ` + `were passed to component but could not be automatically inherited ` + `because component renders fragment or text root nodes.` ); } if (eventAttrs.length) { warn( `Extraneous non-emits event listeners (` + `${eventAttrs.join(', ')}) ` + `were passed to component but could not be automatically inherited ` + `because component renders fragment or text root nodes. ` + `If the listener is intended to be a component custom event listener only, ` + `declare it using the "emits" option.` ); } } } } // inherit directives if (vnode.dirs) { if (process.env.NODE_ENV !== 'production' && !isElementRoot(root)) { warn( `Runtime directive used on component with non-element root node. ` + `The directives will not function as intended.` ); } root.dirs = vnode.dirs; } // inherit transition data if (vnode.transition) { if (process.env.NODE_ENV !== 'production' && !isElementRoot(root)) { warn( `Component inside renders non-element root node ` + `that cannot be animated.` ); } root.transition = vnode.transition; } if (process.env.NODE_ENV !== 'production' && setRoot) { setRoot(root); } else { result = root; } } catch (err) { handleError(err, instance, 1 /* RENDER_FUNCTION */); result = createVNode(Comment); } currentRenderingInstance = null; return result } /** * dev only */ const getChildRoot = vnode => { if (vnode.type !== Fragment) { return [vnode, undefined] } const rawChildren = vnode.children; const dynamicChildren = vnode.dynamicChildren; const children = rawChildren.filter(child => { return !( isVNode(child) && child.type === Comment && child.children !== 'v-if' ) }); if (children.length !== 1) { return [vnode, undefined] } const childRoot = children[0]; const index = rawChildren.indexOf(childRoot); const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1; const setRoot = updatedRoot => { rawChildren[index] = updatedRoot; if (dynamicIndex > -1) { dynamicChildren[dynamicIndex] = updatedRoot; } else if (dynamicChildren && updatedRoot.patchFlag > 0) { dynamicChildren.push(updatedRoot); } }; return [normalizeVNode(childRoot), setRoot] }; const getFunctionalFallthrough = attrs => { let res; for (const key in attrs) { if (key === 'class' || key === 'style' || isOn(key)) { (res || (res = {}))[key] = attrs[key]; } } return res }; const filterModelListeners = (attrs, props) => { const res = {}; for (const key in attrs) { if (!isModelListener(key) || !(key.slice(9) in props)) { res[key] = attrs[key]; } } return res }; const isElementRoot = vnode => { return ( vnode.shapeFlag & 6 /* COMPONENT */ || vnode.shapeFlag & 1 /* ELEMENT */ || vnode.type === Comment // potential v-if branch switch ) }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { const { props: prevProps, children: prevChildren } = prevVNode; const { props: nextProps, children: nextChildren, patchFlag } = nextVNode; // Parent component's render function was hot-updated. Since this may have // caused the child component's slots content to have changed, we need to // force the child to update as well. if ( process.env.NODE_ENV !== 'production' && (prevChildren || nextChildren) && isHmrUpdating ) { return true } // force child update for runtime directive or transition on component vnode. if (nextVNode.dirs || nextVNode.transition) { return true } if (optimized && patchFlag > 0) { if (patchFlag & 1024 /* DYNAMIC_SLOTS */) { // slot content that references values that might have changed, // e.g. in a v-for return true } if (patchFlag & 16 /* FULL_PROPS */) { if (!prevProps) { return !!nextProps } // presence of this flag indicates props are always non-null return hasPropsChanged(prevProps, nextProps) } else if (patchFlag & 8 /* PROPS */) { const dynamicProps = nextVNode.dynamicProps; for (let i = 0; i < dynamicProps.length; i++) { const key = dynamicProps[i]; if (nextProps[key] !== prevProps[key]) { return true } } } } else { // this path is only taken by manually written render functions // so presence of any children leads to a forced update if (prevChildren || nextChildren) { if (!nextChildren || !nextChildren.$stable) { return true } } if (prevProps === nextProps) { return false } if (!prevProps) { return !!nextProps } if (!nextProps) { return true } return hasPropsChanged(prevProps, nextProps) } return false } function hasPropsChanged(prevProps, nextProps) { const nextKeys = Object.keys(nextProps); if (nextKeys.length !== Object.keys(prevProps).length) { return true } for (let i = 0; i < nextKeys.length; i++) { const key = nextKeys[i]; if (nextProps[key] !== prevProps[key]) { return true } } return false } function updateHOCHostEl( { vnode, parent }, el // HostNode ) { while (parent && parent.subTree === vnode) { (vnode = parent.vnode).el = el; parent = parent.parent; } } const isSuspense = type => type.__isSuspense; // Suspense exposes a component-like API, and is treated like a component // in the compiler, but internally it's a special built-in type that hooks // directly into the renderer. const SuspenseImpl = { // In order to make Suspense tree-shakable, we need to avoid importing it // directly in the renderer. The renderer checks for the __isSuspense flag // on a vnode's type and calls the `process` method, passing in renderer // internals. __isSuspense: true, process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, // platform-specific impl passed from renderer rendererInternals ) { if (n1 == null) { mountSuspense( n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals ); } else { patchSuspense( n1, n2, container, anchor, parentComponent, isSVG, optimized, rendererInternals ); } }, hydrate: hydrateSuspense }; // Force-casted public typing for h and TSX props inference const Suspense = SuspenseImpl; function mountSuspense( n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals ) { const { p: patch, o: { createElement } } = rendererInternals; const hiddenContainer = createElement('div'); const suspense = (n2.suspense = createSuspenseBoundary( n2, parentSuspense, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals )); // start mounting the content subtree in an off-dom container patch( null, suspense.subTree, hiddenContainer, null, parentComponent, suspense, isSVG, optimized ); // now check if we have encountered any async deps if (suspense.deps > 0) { // mount the fallback tree patch( null, suspense.fallbackTree, container, anchor, parentComponent, null, // fallback tree will not have suspense context isSVG, optimized ); n2.el = suspense.fallbackTree.el; } else { // Suspense has no async deps. Just resolve. suspense.resolve(); } } function patchSuspense( n1, n2, container, anchor, parentComponent, isSVG, optimized, { p: patch } ) { const suspense = (n2.suspense = n1.suspense); suspense.vnode = n2; const { content, fallback } = normalizeSuspenseChildren(n2); const oldSubTree = suspense.subTree; const oldFallbackTree = suspense.fallbackTree; if (!suspense.isResolved) { patch( oldSubTree, content, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized ); if (suspense.deps > 0) { // still pending. patch the fallback tree. patch( oldFallbackTree, fallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context isSVG, optimized ); n2.el = fallback.el; } // If deps somehow becomes 0 after the patch it means the patch caused an // async dep component to unmount and removed its dep. It will cause the // suspense to resolve and we don't need to do anything here. } else { // just normal patch inner content as a fragment patch( oldSubTree, content, container, anchor, parentComponent, suspense, isSVG, optimized ); n2.el = content.el; } suspense.subTree = content; suspense.fallbackTree = fallback; } let hasWarned = false; function createSuspenseBoundary( vnode, parent, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals, isHydrating = false ) { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && !false && !hasWarned) { hasWarned = true; // @ts-ignore `console.info` cannot be null error console[console.info ? 'info' : 'log']( ` is an experimental feature and its API will likely change.` ); } const { p: patch, m: move, um: unmount, n: next, o: { parentNode } } = rendererInternals; const getCurrentTree = () => suspense.isResolved || suspense.isHydrating ? suspense.subTree : suspense.fallbackTree; const { content, fallback } = normalizeSuspenseChildren(vnode); const suspense = { vnode, parent, parentComponent, isSVG, optimized, container, hiddenContainer, anchor, deps: 0, subTree: content, fallbackTree: fallback, isHydrating, isResolved: false, isUnmounted: false, effects: [], resolve() { if (process.env.NODE_ENV !== 'production') { if (suspense.isResolved) { throw new Error( `resolveSuspense() is called on an already resolved suspense boundary.` ) } if (suspense.isUnmounted) { throw new Error( `resolveSuspense() is called on an already unmounted suspense boundary.` ) } } const { vnode, subTree, fallbackTree, effects, parentComponent, container } = suspense; if (suspense.isHydrating) { suspense.isHydrating = false; } else { // this is initial anchor on mount let { anchor } = suspense; // unmount fallback tree if (fallbackTree.el) { // if the fallback tree was mounted, it may have been moved // as part of a parent suspense. get the latest anchor for insertion anchor = next(fallbackTree); unmount(fallbackTree, parentComponent, suspense, true); } // move content from off-dom container to actual container move(subTree, container, anchor, 0 /* ENTER */); } const el = (vnode.el = subTree.el); // suspense as the root node of a component... if (parentComponent && parentComponent.subTree === vnode) { parentComponent.vnode.el = el; updateHOCHostEl(parentComponent, el); } // check if there is a pending parent suspense let parent = suspense.parent; let hasUnresolvedAncestor = false; while (parent) { if (!parent.isResolved) { // found a pending parent suspense, merge buffered post jobs // into that parent parent.effects.push(...effects); hasUnresolvedAncestor = true; break } parent = parent.parent; } // no pending parent suspense, flush all jobs if (!hasUnresolvedAncestor) { queuePostFlushCb(effects); } suspense.isResolved = true; suspense.effects = []; // invoke @resolve event const onResolve = vnode.props && vnode.props.onResolve; if (isFunction(onResolve)) { onResolve(); } }, recede() { suspense.isResolved = false; const { vnode, subTree, fallbackTree, parentComponent, container, hiddenContainer, isSVG, optimized } = suspense; // move content tree back to the off-dom container const anchor = next(subTree); move(subTree, hiddenContainer, null, 1 /* LEAVE */); // remount the fallback tree patch( null, fallbackTree, container, anchor, parentComponent, null, // fallback tree will not have suspense context isSVG, optimized ); const el = (vnode.el = fallbackTree.el); // suspense as the root node of a component... if (parentComponent && parentComponent.subTree === vnode) { parentComponent.vnode.el = el; updateHOCHostEl(parentComponent, el); } // invoke @recede event const onRecede = vnode.props && vnode.props.onRecede; if (isFunction(onRecede)) { onRecede(); } }, move(container, anchor, type) { move(getCurrentTree(), container, anchor, type); suspense.container = container; }, next() { return next(getCurrentTree()) }, registerDep(instance, setupRenderEffect) { // suspense is already resolved, need to recede. // use queueJob so it's handled synchronously after patching the current // suspense tree if (suspense.isResolved) { queueJob(() => { suspense.recede(); }); } const hydratedEl = instance.vnode.el; suspense.deps++; instance.asyncDep .catch(err => { handleError(err, instance, 0 /* SETUP_FUNCTION */); }) .then(asyncSetupResult => { // retry when the setup() promise resolves. // component may have been unmounted before resolve. if (instance.isUnmounted || suspense.isUnmounted) { return } suspense.deps--; // retry from this component instance.asyncResolved = true; const { vnode } = instance; if (process.env.NODE_ENV !== 'production') { pushWarningContext(vnode); } handleSetupResult(instance, asyncSetupResult); if (hydratedEl) { // vnode may have been replaced if an update happened before the // async dep is resolved. vnode.el = hydratedEl; } setupRenderEffect( instance, vnode, // component may have been moved before resolve. // if this is not a hydration, instance.subTree will be the comment // placeholder. hydratedEl ? parentNode(hydratedEl) : parentNode(instance.subTree.el), // anchor will not be used if this is hydration, so only need to // consider the comment placeholder case. hydratedEl ? null : next(instance.subTree), suspense, isSVG, optimized ); updateHOCHostEl(instance, vnode.el); if (process.env.NODE_ENV !== 'production') { popWarningContext(); } if (suspense.deps === 0) { suspense.resolve(); } }); }, unmount(parentSuspense, doRemove) { suspense.isUnmounted = true; unmount(suspense.subTree, parentComponent, parentSuspense, doRemove); if (!suspense.isResolved) { unmount( suspense.fallbackTree, parentComponent, parentSuspense, doRemove ); } } }; return suspense } function hydrateSuspense( node, vnode, parentComponent, parentSuspense, isSVG, optimized, rendererInternals, hydrateNode ) { /* eslint-disable no-restricted-globals */ const suspense = (vnode.suspense = createSuspenseBoundary( vnode, parentSuspense, parentComponent, node.parentNode, document.createElement('div'), null, isSVG, optimized, rendererInternals, true /* hydrating */ )); // there are two possible scenarios for server-rendered suspense: // - success: ssr content should be fully resolved // - failure: ssr content should be the fallback branch. // however, on the client we don't really know if it has failed or not // attempt to hydrate the DOM assuming it has succeeded, but we still // need to construct a suspense boundary first const result = hydrateNode( node, suspense.subTree, parentComponent, suspense, optimized ); if (suspense.deps === 0) { suspense.resolve(); } return result /* eslint-enable no-restricted-globals */ } function normalizeSuspenseChildren(vnode) { const { shapeFlag, children } = vnode; if (shapeFlag & 32 /* SLOTS_CHILDREN */) { const { default: d, fallback } = children; return { content: normalizeVNode(isFunction(d) ? d() : d), fallback: normalizeVNode(isFunction(fallback) ? fallback() : fallback) } } else { return { content: normalizeVNode(children), fallback: normalizeVNode(null) } } } function queueEffectWithSuspense(fn, suspense) { if (suspense && !suspense.isResolved) { if (isArray(fn)) { suspense.effects.push(...fn); } else { suspense.effects.push(fn); } } else { queuePostFlushCb(fn); } } let isRenderingCompiledSlot = 0; const setCompiledSlotRendering = n => (isRenderingCompiledSlot += n); /** * Compiler runtime helper for rendering `` * @private */ function renderSlot( slots, name, props = {}, // this is not a user-facing function, so the fallback is always generated by // the compiler and guaranteed to be a function returning an array fallback ) { let slot = slots[name]; if (process.env.NODE_ENV !== 'production' && slot && slot.length > 1) { warn( `SSR-optimized slot function detected in a non-SSR-optimized render ` + `function. You need to mark this component with $dynamic-slots in the ` + `parent template.` ); slot = () => []; } // a compiled slot disables block tracking by default to avoid manual // invocation interfering with template-based block tracking, but in // `renderSlot` we can be sure that it's template-based so we can force // enable it. isRenderingCompiledSlot++; const rendered = (openBlock(), createBlock( Fragment, { key: props.key }, slot ? slot(props) : fallback ? fallback() : [], slots._ === 1 /* STABLE */ ? 64 /* STABLE_FRAGMENT */ : -2 /* BAIL */ )); isRenderingCompiledSlot--; return rendered } /** * Wrap a slot function to memoize current rendering instance * @private */ function withCtx(fn, ctx = currentRenderingInstance) { if (!ctx) return fn const renderFnWithContext = (...args) => { // If a user calls a compiled slot inside a template expression (#1745), it // can mess up block tracking, so by default we need to push a null block to // avoid that. This isn't necessary if rendering a compiled ``. if (!isRenderingCompiledSlot) { openBlock(true /* null block that disables tracking */); } const owner = currentRenderingInstance; setCurrentRenderingInstance(ctx); const res = fn(...args); setCurrentRenderingInstance(owner); if (!isRenderingCompiledSlot) { closeBlock(); } return res }; renderFnWithContext._c = true; return renderFnWithContext } // SFC scoped style ID management. let currentScopeId = null; const scopeIdStack = []; /** * @private */ function pushScopeId(id) { scopeIdStack.push((currentScopeId = id)); } /** * @private */ function popScopeId() { scopeIdStack.pop(); currentScopeId = scopeIdStack[scopeIdStack.length - 1] || null; } /** * @private */ function withScopeId(id) { return fn => withCtx(function() { pushScopeId(id); const res = fn.apply(this, arguments); popScopeId(); return res }) } const isTeleport = type => type.__isTeleport; const isTeleportDisabled = props => props && (props.disabled || props.disabled === ''); const resolveTarget = (props, select) => { const targetSelector = props && props.to; if (isString(targetSelector)) { if (!select) { process.env.NODE_ENV !== 'production' && warn( `Current renderer does not support string target for Teleports. ` + `(missing querySelector renderer option)` ); return null } else { const target = select(targetSelector); if (!target) { process.env.NODE_ENV !== 'production' && warn( `Failed to locate Teleport target with selector "${targetSelector}". ` + `Note the target element must exist before the component is mounted - ` + `i.e. the target cannot be rendered by the component itself, and ` + `ideally should be outside of the entire Vue component tree.` ); } return target } } else { if ( process.env.NODE_ENV !== 'production' && !targetSelector && !isTeleportDisabled(props) ) { warn(`Invalid Teleport target: ${targetSelector}`); } return targetSelector } }; const TeleportImpl = { __isTeleport: true, process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals ) { const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; const disabled = isTeleportDisabled(n2.props); const { shapeFlag, children } = n2; if (n1 == null) { // insert anchors in the main view const placeholder = (n2.el = process.env.NODE_ENV !== 'production' ? createComment('teleport start') : createText('')); const mainAnchor = (n2.anchor = process.env.NODE_ENV !== 'production' ? createComment('teleport end') : createText('')); insert(placeholder, container, anchor); insert(mainAnchor, container, anchor); const target = (n2.target = resolveTarget(n2.props, querySelector)); const targetAnchor = (n2.targetAnchor = createText('')); if (target) { insert(targetAnchor, target); } else if (process.env.NODE_ENV !== 'production' && !disabled) { warn('Invalid Teleport target on mount:', target, `(${typeof target})`); } const mount = (container, anchor) => { // Teleport *always* has Array children. This is enforced in both the // compiler and vnode children normalization. if (shapeFlag & 16 /* ARRAY_CHILDREN */) { mountChildren( children, container, anchor, parentComponent, parentSuspense, isSVG, optimized ); } }; if (disabled) { mount(container, mainAnchor); } else if (target) { mount(target, targetAnchor); } } else { // update content n2.el = n1.el; const mainAnchor = (n2.anchor = n1.anchor); const target = (n2.target = n1.target); const targetAnchor = (n2.targetAnchor = n1.targetAnchor); const wasDisabled = isTeleportDisabled(n1.props); const currentContainer = wasDisabled ? container : target; const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; if (n2.dynamicChildren) { // fast path when the teleport happens to be a block root patchBlockChildren( n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG ); // even in block tree mode we need to make sure all root-level nodes // in the teleport inherit previous DOM references so that they can // be moved in future patches. if (n2.shapeFlag & 16 /* ARRAY_CHILDREN */) { const oldChildren = n1.children; const children = n2.children; for (let i = 0; i < children.length; i++) { // only inherit for non-patched nodes (i.e. static ones) if (!children[i].el) { children[i].el = oldChildren[i].el; } } } } else if (!optimized) { patchChildren( n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG ); } if (disabled) { if (!wasDisabled) { // enabled -> disabled // move into main container moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); } } else { // target changed if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { const nextTarget = (n2.target = resolveTarget( n2.props, querySelector )); if (nextTarget) { moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); } else if (process.env.NODE_ENV !== 'production') { warn( 'Invalid Teleport target on update:', target, `(${typeof target})` ); } } else if (wasDisabled) { // disabled -> enabled // move into teleport target moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); } } } }, remove( vnode, { r: remove, o: { remove: hostRemove } } ) { const { shapeFlag, children, anchor } = vnode; hostRemove(anchor); if (shapeFlag & 16 /* ARRAY_CHILDREN */) { for (let i = 0; i < children.length; i++) { remove(children[i]); } } }, move: moveTeleport, hydrate: hydrateTeleport }; function moveTeleport( vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */ ) { // move target anchor if this is a target change. if (moveType === 0 /* TARGET_CHANGE */) { insert(vnode.targetAnchor, container, parentAnchor); } const { el, anchor, shapeFlag, children, props } = vnode; const isReorder = moveType === 2; /* REORDER */ // move main view anchor if this is a re-order. if (isReorder) { insert(el, container, parentAnchor); } // if this is a re-order and teleport is enabled (content is in target) // do not move children. So the opposite is: only move children if this // is not a reorder, or the teleport is disabled if (!isReorder || isTeleportDisabled(props)) { // Teleport has either Array children or no children. if (shapeFlag & 16 /* ARRAY_CHILDREN */) { for (let i = 0; i < children.length; i++) { move(children[i], container, parentAnchor, 2 /* REORDER */); } } } // move main view anchor if this is a re-order. if (isReorder) { insert(anchor, container, parentAnchor); } } function hydrateTeleport( node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren ) { const target = (vnode.target = resolveTarget(vnode.props, querySelector)); if (target) { // if multiple teleports rendered to the same target element, we need to // pick up from where the last teleport finished instead of the first node const targetNode = target._lpa || target.firstChild; if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { if (isTeleportDisabled(vnode.props)) { vnode.anchor = hydrateChildren( nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized ); vnode.targetAnchor = targetNode; } else { vnode.anchor = nextSibling(node); vnode.targetAnchor = hydrateChildren( targetNode, vnode, target, parentComponent, parentSuspense, optimized ); } target._lpa = vnode.targetAnchor && nextSibling(vnode.targetAnchor); } } return vnode.anchor && nextSibling(vnode.anchor) } // Force-casted public typing for h and TSX props inference const Teleport = TeleportImpl; const COMPONENTS = 'components'; const DIRECTIVES = 'directives'; /** * @private */ function resolveComponent(name) { return resolveAsset(COMPONENTS, name) || name } const NULL_DYNAMIC_COMPONENT = Symbol(); /** * @private */ function resolveDynamicComponent(component) { if (isString(component)) { return resolveAsset(COMPONENTS, component, false) || component } else { // invalid types will fallthrough to createVNode and raise warning return component || NULL_DYNAMIC_COMPONENT } } /** * @private */ function resolveDirective(name) { return resolveAsset(DIRECTIVES, name) } // implementation function resolveAsset(type, name, warnMissing = true) { const instance = currentRenderingInstance || currentInstance; if (instance) { const Component = instance.type; // self name has highest priority if (type === COMPONENTS) { const selfName = Component.displayName || Component.name; if ( selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name))) ) { return Component } } const res = // local registration // check instance[type] first for components with mixin or extends. resolve(instance[type] || Component[type], name) || // global registration resolve(instance.appContext[type], name); if (process.env.NODE_ENV !== 'production' && warnMissing && !res) { warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); } return res } else if (process.env.NODE_ENV !== 'production') { warn( `resolve${capitalize(type.slice(0, -1))} ` + `can only be used in render() or setup().` ); } } function resolve(registry, name) { return ( registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]) ) } const Fragment = Symbol( process.env.NODE_ENV !== 'production' ? 'Fragment' : undefined ); const Text = Symbol(process.env.NODE_ENV !== 'production' ? 'Text' : undefined); const Comment = Symbol( process.env.NODE_ENV !== 'production' ? 'Comment' : undefined ); const Static = Symbol( process.env.NODE_ENV !== 'production' ? 'Static' : undefined ); // Since v-if and v-for are the two possible ways node structure can dynamically // change, once we consider v-if branches and each v-for fragment a block, we // can divide a template into nested blocks, and within each block the node // structure would be stable. This allows us to skip most children diffing // and only worry about the dynamic nodes (indicated by patch flags). const blockStack = []; let currentBlock = null; /** * Open a block. * This must be called before `createBlock`. It cannot be part of `createBlock` * because the children of the block are evaluated before `createBlock` itself * is called. The generated code typically looks like this: * * ```js * function render() { * return (openBlock(),createBlock('div', null, [...])) * } * ``` * disableTracking is true when creating a v-for fragment block, since a v-for * fragment always diffs its children. * * @private */ function openBlock(disableTracking = false) { blockStack.push((currentBlock = disableTracking ? null : [])); } function closeBlock() { blockStack.pop(); currentBlock = blockStack[blockStack.length - 1] || null; } // Whether we should be tracking dynamic child nodes inside a block. // Only tracks when this value is > 0 // We are not using a simple boolean because this value may need to be // incremented/decremented by nested usage of v-once (see below) let shouldTrack$1 = 1; /** * Block tracking sometimes needs to be disabled, for example during the * creation of a tree that needs to be cached by v-once. The compiler generates * code like this: * * ``` js * _cache[1] || ( * setBlockTracking(-1), * _cache[1] = createVNode(...), * setBlockTracking(1), * _cache[1] * ) * ``` * * @private */ function setBlockTracking(value) { shouldTrack$1 += value; } /** * Create a block root vnode. Takes the same exact arguments as `createVNode`. * A block root keeps track of dynamic nodes within the block in the * `dynamicChildren` array. * * @private */ function createBlock(type, props, children, patchFlag, dynamicProps) { const vnode = createVNode( type, props, children, patchFlag, dynamicProps, true /* isBlock: prevent a block from tracking itself */ ); // save current block children on the block vnode vnode.dynamicChildren = currentBlock || EMPTY_ARR; // close block closeBlock(); // a block is always going to be patched, so track it as a child of its // parent block if (shouldTrack$1 > 0 && currentBlock) { currentBlock.push(vnode); } return vnode } function isVNode(value) { return value ? value.__v_isVNode === true : false } function isSameVNodeType(n1, n2) { if ( process.env.NODE_ENV !== 'production' && n2.shapeFlag & 6 /* COMPONENT */ && hmrDirtyComponents.has(n2.type) ) { // HMR only: if the component has been hot-updated, force a reload. return false } return n1.type === n2.type && n1.key === n2.key } let vnodeArgsTransformer; /** * Internal API for registering an arguments transform for createVNode * used for creating stubs in the test-utils * It is *internal* but needs to be exposed for test-utils to pick up proper * typings */ function transformVNodeArgs(transformer) { vnodeArgsTransformer = transformer; } const createVNodeWithArgsTransform = (...args) => { return _createVNode( ...(vnodeArgsTransformer ? vnodeArgsTransformer(args, currentRenderingInstance) : args) ) }; const InternalObjectKey = `__vInternal`; const normalizeKey = ({ key }) => (key != null ? key : null); const normalizeRef = ({ ref }) => { return ref != null ? isArray(ref) ? ref : [currentRenderingInstance, ref] : null }; const createVNode = process.env.NODE_ENV !== 'production' ? createVNodeWithArgsTransform : _createVNode; function _createVNode( type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false ) { if (!type || type === NULL_DYNAMIC_COMPONENT) { if (process.env.NODE_ENV !== 'production' && !type) { warn(`Invalid vnode type when creating vnode: ${type}.`); } type = Comment; } if (isVNode(type)) { const cloned = cloneVNode(type, props); if (children) { normalizeChildren(cloned, children); } return cloned } // class component normalization. if (isFunction(type) && '__vccOpts' in type) { type = type.__vccOpts; } // class & style normalization. if (props) { // for reactive or proxy objects, we need to clone it to enable mutation. if (isProxy(props) || InternalObjectKey in props) { props = extend({}, props); } let { class: klass, style } = props; if (klass && !isString(klass)) { props.class = normalizeClass(klass); } if (isObject(style)) { // reactive state objects need to be cloned since they are likely to be // mutated if (isProxy(style) && !isArray(style)) { style = extend({}, style); } props.style = normalizeStyle(style); } } // encode the vnode type information into a bitmap const shapeFlag = isString(type) ? 1 /* ELEMENT */ : isSuspense(type) ? 128 /* SUSPENSE */ : isTeleport(type) ? 64 /* TELEPORT */ : isObject(type) ? 4 /* STATEFUL_COMPONENT */ : isFunction(type) ? 2 /* FUNCTIONAL_COMPONENT */ : 0; if ( process.env.NODE_ENV !== 'production' && shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type) ) { type = toRaw(type); warn( `Vue received a Component which was made a reactive object. This can ` + `lead to unnecessary performance overhead, and should be avoided by ` + `marking the component with \`markRaw\` or using \`shallowRef\` ` + `instead of \`ref\`.`, `\nComponent that was made reactive: `, type ); } const vnode = { __v_isVNode: true, ['__v_skip' /* SKIP */]: true, type, props, key: props && normalizeKey(props), ref: props && normalizeRef(props), scopeId: currentScopeId, children: null, component: null, suspense: null, dirs: null, transition: null, el: null, anchor: null, target: null, targetAnchor: null, staticCount: 0, shapeFlag, patchFlag, dynamicProps, dynamicChildren: null, appContext: null }; // validate key if (process.env.NODE_ENV !== 'production' && vnode.key !== vnode.key) { warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type); } normalizeChildren(vnode, children); if ( shouldTrack$1 > 0 && // avoid a block node from tracking itself !isBlockNode && // has current parent block currentBlock && // presence of a patch flag indicates this node needs patching on updates. // component nodes also should always be patched, because even if the // component doesn't need to update, it needs to persist the instance on to // the next vnode so that it can be properly unmounted later. (patchFlag > 0 || shapeFlag & 6) /* COMPONENT */ && // the EVENTS flag is only for hydration and if it is the only flag, the // vnode should not be considered dynamic due to handler caching. patchFlag !== 32 /* HYDRATE_EVENTS */ ) { currentBlock.push(vnode); } return vnode } function cloneVNode(vnode, extraProps) { // This is intentionally NOT using spread or extend to avoid the runtime // key enumeration cost. const { props, patchFlag } = vnode; const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props; return { __v_isVNode: true, ['__v_skip' /* SKIP */]: true, type: vnode.type, props: mergedProps, key: mergedProps && normalizeKey(mergedProps), ref: extraProps && extraProps.ref ? normalizeRef(extraProps) : vnode.ref, scopeId: vnode.scopeId, children: vnode.children, target: vnode.target, targetAnchor: vnode.targetAnchor, staticCount: vnode.staticCount, shapeFlag: vnode.shapeFlag, // if the vnode is cloned with extra props, we can no longer assume its // existing patch flag to be reliable and need to add the FULL_PROPS flag. // note: perserve flag for fragments since they use the flag for children // fast paths only. patchFlag: extraProps && vnode.type !== Fragment ? patchFlag === -1 // hoisted node ? 16 /* FULL_PROPS */ : patchFlag | 16 /* FULL_PROPS */ : patchFlag, dynamicProps: vnode.dynamicProps, dynamicChildren: vnode.dynamicChildren, appContext: vnode.appContext, dirs: vnode.dirs, transition: vnode.transition, // These should technically only be non-null on mounted VNodes. However, // they *should* be copied for kept-alive vnodes. So we just always copy // them since them being non-null during a mount doesn't affect the logic as // they will simply be overwritten. component: vnode.component, suspense: vnode.suspense, el: vnode.el, anchor: vnode.anchor } } /** * @private */ function createTextVNode(text = ' ', flag = 0) { return createVNode(Text, null, text, flag) } /** * @private */ function createStaticVNode(content, numberOfNodes) { // A static vnode can contain multiple stringified elements, and the number // of elements is necessary for hydration. const vnode = createVNode(Static, null, content); vnode.staticCount = numberOfNodes; return vnode } /** * @private */ function createCommentVNode( text = '', // when used as the v-else branch, the comment node must be created as a // block to ensure correct updates. asBlock = false ) { return asBlock ? (openBlock(), createBlock(Comment, null, text)) : createVNode(Comment, null, text) } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder return createVNode(Comment) } else if (isArray(child)) { // fragment return createVNode(Fragment, null, child) } else if (typeof child === 'object') { // already vnode, this should be the most common since compiled templates // always produce all-vnode children arrays return child.el === null ? child : cloneVNode(child) } else { // strings and numbers return createVNode(Text, null, String(child)) } } // optimized normalization for template-compiled render fns function cloneIfMounted(child) { return child.el === null ? child : cloneVNode(child) } function normalizeChildren(vnode, children) { let type = 0; const { shapeFlag } = vnode; if (children == null) { children = null; } else if (isArray(children)) { type = 16; /* ARRAY_CHILDREN */ } else if (typeof children === 'object') { if (shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) { // Normalize slot to plain children for plain element and Teleport const slot = children.default; if (slot) { // _c marker is added by withCtx() indicating this is a compiled slot slot._c && setCompiledSlotRendering(1); normalizeChildren(vnode, slot()); slot._c && setCompiledSlotRendering(-1); } return } else { type = 32; /* SLOTS_CHILDREN */ const slotFlag = children._; if (!slotFlag && !(InternalObjectKey in children)) { children._ctx = currentRenderingInstance; } else if (slotFlag === 3 /* FORWARDED */ && currentRenderingInstance) { // a child component receives forwarded slots from the parent. // its slot type is determined by its parent's slot type. if ( currentRenderingInstance.vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */ ) { children._ = 2; /* DYNAMIC */ vnode.patchFlag |= 1024; /* DYNAMIC_SLOTS */ } else { children._ = 1; /* STABLE */ } } } } else if (isFunction(children)) { children = { default: children, _ctx: currentRenderingInstance }; type = 32; /* SLOTS_CHILDREN */ } else { children = String(children); // force teleport children to array so it can be moved around if (shapeFlag & 64 /* TELEPORT */) { type = 16; /* ARRAY_CHILDREN */ children = [createTextVNode(children)]; } else { type = 8; /* TEXT_CHILDREN */ } } vnode.children = children; vnode.shapeFlag |= type; } function mergeProps(...args) { const ret = extend({}, args[0]); for (let i = 1; i < args.length; i++) { const toMerge = args[i]; for (const key in toMerge) { if (key === 'class') { if (ret.class !== toMerge.class) { ret.class = normalizeClass([ret.class, toMerge.class]); } } else if (key === 'style') { ret.style = normalizeStyle([ret.style, toMerge.style]); } else if (isOn(key)) { const existing = ret[key]; const incoming = toMerge[key]; if (existing !== incoming) { ret[key] = existing ? [].concat(existing, toMerge[key]) : incoming; } } else { ret[key] = toMerge[key]; } } } return ret } let devtools; function setDevtoolsHook(hook) { devtools = hook; } function devtoolsInitApp(app, version) { // TODO queue if devtools is undefined if (!devtools) return devtools.emit('app:init' /* APP_INIT */, app, version, { Fragment, Text, Comment, Static }); } function devtoolsUnmountApp(app) { if (!devtools) return devtools.emit('app:unmount' /* APP_UNMOUNT */, app); } const devtoolsComponentAdded = /*#__PURE__*/ createDevtoolsComponentHook( 'component:added' /* COMPONENT_ADDED */ ); const devtoolsComponentUpdated = /*#__PURE__*/ createDevtoolsComponentHook( 'component:updated' /* COMPONENT_UPDATED */ ); const devtoolsComponentRemoved = /*#__PURE__*/ createDevtoolsComponentHook( 'component:removed' /* COMPONENT_REMOVED */ ); function createDevtoolsComponentHook(hook) { return component => { if (!devtools) return devtools.emit( hook, component.appContext.app, component.uid, component.parent ? component.parent.uid : undefined ); } } function devtoolsComponentEmit(component, event, params) { if (!devtools) return devtools.emit( 'component:emit' /* COMPONENT_EMIT */, component.appContext.app, component, event, params ); } 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' || __VUE_PROD_DEVTOOLS__) { devtoolsComponentEmit(instance, event, args); } 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); 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 updateProps(instance, rawProps, rawPrevProps, optimized) { const { props, attrs, vnode: { patchFlag } } = instance; const rawCurrentProps = toRaw(props); const [options] = instance.propsOptions; if ( // always force full diff if hmr is enabled !(process.env.NODE_ENV !== 'production' && instance.type.__hmrId) && (optimized || patchFlag > 0) && !(patchFlag & 16) /* FULL_PROPS */ ) { if (patchFlag & 8 /* PROPS */) { // Compiler-generated props & no keys change, just set the updated // the props. const propsToUpdate = instance.vnode.dynamicProps; for (let i = 0; i < propsToUpdate.length; i++) { const key = propsToUpdate[i]; // PROPS flag guarantees rawProps to be non-null const value = rawProps[key]; if (options) { // attr / props separation was done on init and will be consistent // in this code path, so just check if attrs have it. if (hasOwn(attrs, key)) { attrs[key] = value; } else { const camelizedKey = camelize(key); props[camelizedKey] = resolvePropValue( options, rawCurrentProps, camelizedKey, value ); } } else { attrs[key] = value; } } } } else { // full props update. setFullProps(instance, rawProps, props, attrs); // in case of dynamic props, check if we need to delete keys from // the props object let kebabKey; for (const key in rawCurrentProps) { if ( !rawProps || // for camelCase (!hasOwn(rawProps, key) && // it's possible the original props was passed in as kebab-case // and converted to camelCase (#955) ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey))) ) { if (options) { if ( rawPrevProps && // for camelCase (rawPrevProps[key] !== undefined || // for kebab-case rawPrevProps[kebabKey] !== undefined) ) { props[key] = resolvePropValue( options, rawProps || EMPTY_OBJ, key, undefined ); } } else { delete props[key]; } } } // in the case of functional component w/o props declaration, props and // attrs point to the same object so it should already have been updated. if (attrs !== rawCurrentProps) { for (const key in attrs) { if (!rawProps || !hasOwn(rawProps, key)) { delete attrs[key]; } } } } // trigger updates for $attrs in case it's used in component slots trigger(instance, 'set' /* SET */, '$attrs'); if (process.env.NODE_ENV !== 'production' && rawProps) { validateProps(props, instance); } } 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().` + (` If you are using async setup(), make sure to register lifecycle ` + `hooks before the first await statement.`) ); } } 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); }; function useTransitionState() { const state = { isMounted: false, isLeaving: false, isUnmounting: false, leavingVNodes: new Map() }; onMounted(() => { state.isMounted = true; }); onBeforeUnmount(() => { state.isUnmounting = true; }); return state } const TransitionHookValidator = [Function, Array]; const BaseTransitionImpl = { name: `BaseTransition`, props: { mode: String, appear: Boolean, persisted: Boolean, // enter onBeforeEnter: TransitionHookValidator, onEnter: TransitionHookValidator, onAfterEnter: TransitionHookValidator, onEnterCancelled: TransitionHookValidator, // leave onBeforeLeave: TransitionHookValidator, onLeave: TransitionHookValidator, onAfterLeave: TransitionHookValidator, onLeaveCancelled: TransitionHookValidator, // appear onBeforeAppear: TransitionHookValidator, onAppear: TransitionHookValidator, onAfterAppear: TransitionHookValidator, onAppearCancelled: TransitionHookValidator }, setup(props, { slots }) { const instance = getCurrentInstance(); const state = useTransitionState(); let prevTransitionKey; return () => { const children = slots.default && getTransitionRawChildren(slots.default(), true); if (!children || !children.length) { return } // warn multiple elements if (process.env.NODE_ENV !== 'production' && children.length > 1) { warn( ' can only be used on a single element or component. Use ' + ' for lists.' ); } // there's no need to track reactivity for these props so use the raw // props for a bit better perf const rawProps = toRaw(props); const { mode } = rawProps; // check mode if ( process.env.NODE_ENV !== 'production' && mode && !['in-out', 'out-in', 'default'].includes(mode) ) { warn(`invalid mode: ${mode}`); } // at this point children has a guaranteed length of 1. const child = children[0]; if (state.isLeaving) { return emptyPlaceholder(child) } // in the case of , we need to // compare the type of the kept-alive children. const innerChild = getKeepAliveChild(child); if (!innerChild) { return emptyPlaceholder(child) } const enterHooks = (innerChild.transition = resolveTransitionHooks( innerChild, rawProps, state, instance )); const oldChild = instance.subTree; const oldInnerChild = oldChild && getKeepAliveChild(oldChild); let transitionKeyChanged = false; const { getTransitionKey } = innerChild.type; if (getTransitionKey) { const key = getTransitionKey(); if (prevTransitionKey === undefined) { prevTransitionKey = key; } else if (key !== prevTransitionKey) { prevTransitionKey = key; transitionKeyChanged = true; } } // handle mode if ( oldInnerChild && oldInnerChild.type !== Comment && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged) ) { const leavingHooks = resolveTransitionHooks( oldInnerChild, rawProps, state, instance ); // update old tree's hooks in case of dynamic transition setTransitionHooks(oldInnerChild, leavingHooks); // switching between different views if (mode === 'out-in') { state.isLeaving = true; // return placeholder node and queue update when leave finishes leavingHooks.afterLeave = () => { state.isLeaving = false; instance.update(); }; return emptyPlaceholder(child) } else if (mode === 'in-out') { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType( state, oldInnerChild ); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; // early removal callback el._leaveCb = () => { earlyRemove(); el._leaveCb = undefined; delete enterHooks.delayedLeave; }; enterHooks.delayedLeave = delayedLeave; }; } } return child } } }; // export the public type for h/tsx inference // also to avoid inline import() in generated d.ts files const BaseTransition = BaseTransitionImpl; function getLeavingNodesForType(state, vnode) { const { leavingVNodes } = state; let leavingVNodesCache = leavingVNodes.get(vnode.type); if (!leavingVNodesCache) { leavingVNodesCache = Object.create(null); leavingVNodes.set(vnode.type, leavingVNodesCache); } return leavingVNodesCache } // The transition hooks are attached to the vnode as vnode.transition // and will be called at appropriate timing in the renderer. function resolveTransitionHooks( vnode, { appear, persisted = false, onBeforeEnter, onEnter, onAfterEnter, onEnterCancelled, onBeforeLeave, onLeave, onAfterLeave, onLeaveCancelled, onBeforeAppear, onAppear, onAfterAppear, onAppearCancelled }, state, instance ) { const key = String(vnode.key); const leavingVNodesCache = getLeavingNodesForType(state, vnode); const callHook = (hook, args) => { hook && callWithAsyncErrorHandling(hook, instance, 9 /* TRANSITION_HOOK */, args); }; const hooks = { persisted, beforeEnter(el) { let hook = onBeforeEnter; if (!state.isMounted) { if (appear) { hook = onBeforeAppear || onBeforeEnter; } else { return } } // for same element (v-show) if (el._leaveCb) { el._leaveCb(true /* cancelled */); } // for toggled element with same key (v-if) const leavingVNode = leavingVNodesCache[key]; if ( leavingVNode && isSameVNodeType(vnode, leavingVNode) && leavingVNode.el._leaveCb ) { // force early removal (not cancelled) leavingVNode.el._leaveCb(); } callHook(hook, [el]); }, enter(el) { let hook = onEnter; let afterHook = onAfterEnter; let cancelHook = onEnterCancelled; if (!state.isMounted) { if (appear) { hook = onAppear || onEnter; afterHook = onAfterAppear || onAfterEnter; cancelHook = onAppearCancelled || onEnterCancelled; } else { return } } let called = false; const done = (el._enterCb = cancelled => { if (called) return called = true; if (cancelled) { callHook(cancelHook, [el]); } else { callHook(afterHook, [el]); } if (hooks.delayedLeave) { hooks.delayedLeave(); } el._enterCb = undefined; }); if (hook) { hook(el, done); if (hook.length <= 1) { done(); } } else { done(); } }, leave(el, remove) { const key = String(vnode.key); if (el._enterCb) { el._enterCb(true /* cancelled */); } if (state.isUnmounting) { return remove() } callHook(onBeforeLeave, [el]); let called = false; const done = (el._leaveCb = cancelled => { if (called) return called = true; remove(); if (cancelled) { callHook(onLeaveCancelled, [el]); } else { callHook(onAfterLeave, [el]); } el._leaveCb = undefined; if (leavingVNodesCache[key] === vnode) { delete leavingVNodesCache[key]; } }); leavingVNodesCache[key] = vnode; if (onLeave) { onLeave(el, done); if (onLeave.length <= 1) { done(); } } else { done(); } } }; return hooks } // the placeholder really only handles one special case: KeepAlive // in the case of a KeepAlive in a leave phase we need to return a KeepAlive // placeholder with empty content to avoid the KeepAlive instance from being // unmounted. function emptyPlaceholder(vnode) { if (isKeepAlive(vnode)) { vnode = cloneVNode(vnode); vnode.children = null; return vnode } } function getKeepAliveChild(vnode) { return isKeepAlive(vnode) ? vnode.children ? vnode.children[0] : undefined : vnode } function setTransitionHooks(vnode, hooks) { if (vnode.shapeFlag & 6 /* COMPONENT */ && vnode.component) { setTransitionHooks(vnode.component.subTree, hooks); } else { vnode.transition = hooks; } } function getTransitionRawChildren(children, keepComment = false) { let ret = []; let keyedFragmentCount = 0; for (let i = 0; i < children.length; i++) { const child = children[i]; // handle fragment children case, e.g. v-for if (child.type === Fragment) { if (child.patchFlag & 128 /* KEYED_FRAGMENT */) keyedFragmentCount++; ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if else if (keepComment || child.type !== Comment) { ret.push(child); } } // #1126 if a transition children list contains multiple sub fragments, these // fragments will be merged into a flat children array. Since each v-for // fragment may contain different static bindings inside, we need to de-top // these children to force full diffs to ensure correct behavior. if (keyedFragmentCount > 1) { for (let i = 0; i < ret.length; i++) { ret[i].patchFlag = -2; /* BAIL */ } } return ret } const isKeepAlive = vnode => vnode.type.__isKeepAlive; const KeepAliveImpl = { name: `KeepAlive`, // Marker for special handling inside the renderer. We are not using a === // check directly on KeepAlive in the renderer, because importing it directly // would prevent it from being tree-shaken. __isKeepAlive: true, inheritRef: true, props: { include: [String, RegExp, Array], exclude: [String, RegExp, Array], max: [String, Number] }, setup(props, { slots }) { const cache = new Map(); const keys = new Set(); let current = null; const instance = getCurrentInstance(); const parentSuspense = instance.suspense; // KeepAlive communicates with the instantiated renderer via the // ctx where the renderer passes in its internals, // and the KeepAlive instance exposes activate/deactivate implementations. // The whole point of this is to avoid importing KeepAlive directly in the // renderer to facilitate tree-shaking. const sharedContext = instance.ctx; const { renderer: { p: patch, m: move, um: _unmount, o: { createElement } } } = sharedContext; const storageContainer = createElement('div'); sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => { const instance = vnode.component; move(vnode, container, anchor, 0 /* ENTER */, parentSuspense); // in case props have changed patch( instance.vnode, vnode, container, anchor, instance, parentSuspense, isSVG, optimized ); queuePostRenderEffect(() => { instance.isDeactivated = false; if (instance.a) { invokeArrayFns(instance.a); } const vnodeHook = vnode.props && vnode.props.onVnodeMounted; if (vnodeHook) { invokeVNodeHook(vnodeHook, instance.parent, vnode); } }, parentSuspense); }; sharedContext.deactivate = vnode => { const instance = vnode.component; move(vnode, storageContainer, null, 1 /* LEAVE */, parentSuspense); queuePostRenderEffect(() => { if (instance.da) { invokeArrayFns(instance.da); } const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted; if (vnodeHook) { invokeVNodeHook(vnodeHook, instance.parent, vnode); } instance.isDeactivated = true; }, parentSuspense); }; function unmount(vnode) { // reset the shapeFlag so it can be properly unmounted resetShapeFlag(vnode); _unmount(vnode, instance, parentSuspense); } function pruneCache(filter) { cache.forEach((vnode, key) => { const name = getName(vnode.type); if (name && (!filter || !filter(name))) { pruneCacheEntry(key); } }); } function pruneCacheEntry(key) { const cached = cache.get(key); if (!current || cached.type !== current.type) { unmount(cached); } else if (current) { // current active instance should no longer be kept-alive. // we can't unmount it now but it might be later, so reset its flag now. resetShapeFlag(current); } cache.delete(key); keys.delete(key); } watch( () => [props.include, props.exclude], ([include, exclude]) => { include && pruneCache(name => matches(include, name)); exclude && pruneCache(name => matches(exclude, name)); } ); // cache sub tree in beforeMount/Update (i.e. right after the render) let pendingCacheKey = null; const cacheSubtree = () => { // fix #1621, the pendingCacheKey could be 0 if (pendingCacheKey != null) { cache.set(pendingCacheKey, instance.subTree); } }; onBeforeMount(cacheSubtree); onBeforeUpdate(cacheSubtree); onBeforeUnmount(() => { cache.forEach(cached => { const { subTree, suspense } = instance; if (cached.type === subTree.type) { // current instance will be unmounted as part of keep-alive's unmount resetShapeFlag(subTree); // but invoke its deactivated hook here const da = subTree.component.da; da && queuePostRenderEffect(da, suspense); return } unmount(cached); }); }); return () => { pendingCacheKey = null; if (!slots.default) { return null } const children = slots.default(); let vnode = children[0]; if (children.length > 1) { if (process.env.NODE_ENV !== 'production') { warn(`KeepAlive should contain exactly one component child.`); } current = null; return children } else if ( !isVNode(vnode) || !(vnode.shapeFlag & 4) /* STATEFUL_COMPONENT */ ) { current = null; return vnode } const comp = vnode.type; const name = getName(comp); const { include, exclude, max } = props; if ( (include && (!name || !matches(include, name))) || (exclude && name && matches(exclude, name)) ) { return (current = vnode) } const key = vnode.key == null ? comp : vnode.key; const cachedVNode = cache.get(key); // clone vnode if it's reused because we are going to mutate it if (vnode.el) { vnode = cloneVNode(vnode); } // #1513 it's possible for the returned vnode to be cloned due to attr // fallthrough or scopeId, so the vnode here may not be the final vnode // that is mounted. Instead of caching it directly, we store the pending // key and cache `instance.subTree` (the normalized vnode) in // beforeMount/beforeUpdate hooks. pendingCacheKey = key; if (cachedVNode) { // copy over mounted state vnode.el = cachedVNode.el; vnode.component = cachedVNode.component; if (vnode.transition) { // recursively update transition hooks on subTree setTransitionHooks(vnode, vnode.transition); } // avoid vnode being mounted as fresh vnode.shapeFlag |= 512; /* COMPONENT_KEPT_ALIVE */ // make this key the freshest keys.delete(key); keys.add(key); } else { keys.add(key); // prune oldest entry if (max && keys.size > parseInt(max, 10)) { pruneCacheEntry(keys.values().next().value); } } // avoid vnode being unmounted vnode.shapeFlag |= 256; /* COMPONENT_SHOULD_KEEP_ALIVE */ current = vnode; return vnode } } }; // export the public type for h/tsx inference // also to avoid inline import() in generated d.ts files const KeepAlive = KeepAliveImpl; function getName(comp) { return comp.displayName || comp.name } function matches(pattern, name) { if (isArray(pattern)) { return pattern.some(p => matches(p, name)) } else if (isString(pattern)) { return pattern.split(',').indexOf(name) > -1 } else if (pattern.test) { return pattern.test(name) } /* istanbul ignore next */ return false } 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); } function resetShapeFlag(vnode) { let shapeFlag = vnode.shapeFlag; if (shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) { shapeFlag -= 256; /* COMPONENT_SHOULD_KEEP_ALIVE */ } if (shapeFlag & 512 /* COMPONENT_KEPT_ALIVE */) { shapeFlag -= 512; /* COMPONENT_KEPT_ALIVE */ } vnode.shapeFlag = shapeFlag; } const isInternalKey = key => key[0] === '_' || key === '$stable'; const normalizeSlotValue = value => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value)]; const normalizeSlot = (key, rawSlot, ctx) => withCtx(props => { if (process.env.NODE_ENV !== 'production' && currentInstance) { warn( `Slot "${key}" invoked outside of the render function: ` + `this will not track dependencies used in the slot. ` + `Invoke the slot function inside the render function instead.` ); } return normalizeSlotValue(rawSlot(props)) }, ctx); const normalizeObjectSlots = (rawSlots, slots) => { const ctx = rawSlots._ctx; for (const key in rawSlots) { if (isInternalKey(key)) continue const value = rawSlots[key]; if (isFunction(value)) { slots[key] = normalizeSlot(key, value, ctx); } else if (value != null) { if (process.env.NODE_ENV !== 'production') { warn( `Non-function value encountered for slot "${key}". ` + `Prefer function slots for better performance.` ); } const normalized = normalizeSlotValue(value); slots[key] = () => normalized; } } }; const normalizeVNodeSlots = (instance, children) => { if (process.env.NODE_ENV !== 'production' && !isKeepAlive(instance.vnode)) { warn( `Non-function value encountered for default slot. ` + `Prefer function slots for better performance.` ); } const normalized = normalizeSlotValue(children); instance.slots.default = () => normalized; }; const initSlots = (instance, children) => { if (instance.vnode.shapeFlag & 32 /* SLOTS_CHILDREN */) { const type = children._; if (type) { instance.slots = children; // make compiler marker non-enumerable def(children, '_', type); } else { normalizeObjectSlots(children, (instance.slots = {})); } } else { instance.slots = {}; if (children) { normalizeVNodeSlots(instance, children); } } def(instance.slots, InternalObjectKey, 1); }; const updateSlots = (instance, children) => { const { vnode, slots } = instance; let needDeletionCheck = true; let deletionComparisonTarget = EMPTY_OBJ; if (vnode.shapeFlag & 32 /* SLOTS_CHILDREN */) { const type = children._; if (type) { // compiled slots. if (process.env.NODE_ENV !== 'production' && isHmrUpdating) { // Parent was HMR updated so slot content may have changed. // force update slots and mark instance for hmr as well extend(slots, children); } else if (type === 1 /* STABLE */) { // compiled AND stable. // no need to update, and skip stale slots removal. needDeletionCheck = false; } else { // compiled but dynamic (v-if/v-for on slots) - update slots, but skip // normalization. extend(slots, children); } } else { needDeletionCheck = !children.$stable; normalizeObjectSlots(children, slots); } deletionComparisonTarget = children; } else if (children) { // non slot object children (direct value) passed to a component normalizeVNodeSlots(instance, children); deletionComparisonTarget = { default: 1 }; } // delete stale slots if (needDeletionCheck) { for (const key in slots) { if (!isInternalKey(key) && !(key in deletionComparisonTarget)) { delete slots[key]; } } } }; /** 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); } } /** * Adds directives to a VNode. */ function withDirectives(vnode, directives) { const internalInstance = currentRenderingInstance; if (internalInstance === null) { process.env.NODE_ENV !== 'production' && warn(`withDirectives can only be used inside render functions.`); return vnode } const instance = internalInstance.proxy; const bindings = vnode.dirs || (vnode.dirs = []); for (let i = 0; i < directives.length; i++) { let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]; if (isFunction(dir)) { dir = { mounted: dir, updated: dir }; } bindings.push({ dir, instance, value, oldValue: void 0, arg, modifiers }); } return vnode } function invokeDirectiveHook(vnode, prevVNode, instance, name) { const bindings = vnode.dirs; const oldBindings = prevVNode && prevVNode.dirs; for (let i = 0; i < bindings.length; i++) { const binding = bindings[i]; if (oldBindings) { binding.oldValue = oldBindings[i].value; } const hook = binding.dir[name]; if (hook) { callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ vnode.el, binding, vnode, prevVNode ]); } } } 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; function createAppAPI(render, hydrate) { 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(); 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 }, mount(rootContainer, isHydrate) { if (!isMounted) { const vnode = createVNode(rootComponent, rootProps); // store app context on the root VNode. // this will be set on the root instance on initial mount. vnode.appContext = context; // HMR root reload if (process.env.NODE_ENV !== 'production') { context.reload = () => { render(cloneVNode(vnode), rootContainer); }; } if (isHydrate && hydrate) { hydrate(vnode, rootContainer); } else { render(vnode, rootContainer); } isMounted = true; app._container = rootContainer; rootContainer.__vue_app__ = app; if (process.env.NODE_ENV !== 'production' || __VUE_PROD_DEVTOOLS__) { devtoolsInitApp(app, version); } return vnode.component.proxy } else if (process.env.NODE_ENV !== 'production') { warn( `App has already been mounted.\n` + `If you want to remount the same app, move your app creation logic ` + `into a factory function and create fresh app instances for each ` + `mount - e.g. \`const createMyApp = () => createApp(App)\`` ); } }, unmount() { if (isMounted) { render(null, app._container); if (process.env.NODE_ENV !== 'production' || __VUE_PROD_DEVTOOLS__) { devtoolsUnmountApp(app); } } else if (process.env.NODE_ENV !== 'production') { warn(`Cannot unmount an app that is not mounted.`); } }, 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 } } let hasMismatch = false; const isSVGContainer = container => /svg/.test(container.namespaceURI) && container.tagName !== 'foreignObject'; const isComment = node => node.nodeType === 8; /* COMMENT */ // Note: hydration is DOM-specific // But we have to place it in core due to tight coupling with core - splitting // it out creates a ton of unnecessary complexity. // Hydration also depends on some renderer internal logic which needs to be // passed in via arguments. function createHydrationFunctions(rendererInternals) { const { mt: mountComponent, p: patch, o: { patchProp, nextSibling, parentNode, remove, insert, createComment } } = rendererInternals; const hydrate = (vnode, container) => { if (process.env.NODE_ENV !== 'production' && !container.hasChildNodes()) { warn( `Attempting to hydrate existing markup but container is empty. ` + `Performing full mount instead.` ); patch(null, vnode, container); return } hasMismatch = false; hydrateNode(container.firstChild, vnode, null, null); flushPostFlushCbs(); if (hasMismatch && !false) { // this error should show up in production console.error(`Hydration completed but contains mismatches.`); } }; const hydrateNode = ( node, vnode, parentComponent, parentSuspense, optimized = false ) => { const isFragmentStart = isComment(node) && node.data === '['; const onMismatch = () => handleMismatch( node, vnode, parentComponent, parentSuspense, isFragmentStart ); const { type, ref, shapeFlag } = vnode; const domType = node.nodeType; vnode.el = node; let nextNode = null; switch (type) { case Text: if (domType !== 3 /* TEXT */) { nextNode = onMismatch(); } else { if (node.data !== vnode.children) { hasMismatch = true; process.env.NODE_ENV !== 'production' && warn( `Hydration text mismatch:` + `\n- Client: ${JSON.stringify(node.data)}` + `\n- Server: ${JSON.stringify(vnode.children)}` ); node.data = vnode.children; } nextNode = nextSibling(node); } break case Comment: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } else { nextNode = nextSibling(node); } break case Static: if (domType !== 1 /* ELEMENT */) { nextNode = onMismatch(); } else { // determine anchor, adopt content nextNode = node; // if the static vnode has its content stripped during build, // adopt it from the server-rendered HTML. const needToAdoptContent = !vnode.children.length; for (let i = 0; i < vnode.staticCount; i++) { if (needToAdoptContent) vnode.children += nextNode.outerHTML; if (i === vnode.staticCount - 1) { vnode.anchor = nextNode; } nextNode = nextSibling(nextNode); } return nextNode } break case Fragment: if (!isFragmentStart) { nextNode = onMismatch(); } else { nextNode = hydrateFragment( node, vnode, parentComponent, parentSuspense, optimized ); } break default: if (shapeFlag & 1 /* ELEMENT */) { if ( domType !== 1 /* ELEMENT */ || vnode.type !== node.tagName.toLowerCase() ) { nextNode = onMismatch(); } else { nextNode = hydrateElement( node, vnode, parentComponent, parentSuspense, optimized ); } } else if (shapeFlag & 6 /* COMPONENT */) { // when setting up the render effect, if the initial vnode already // has .el set, the component will perform hydration instead of mount // on its sub-tree. const container = parentNode(node); const hydrateComponent = () => { mountComponent( vnode, container, null, parentComponent, parentSuspense, isSVGContainer(container), optimized ); }; // async component const loadAsync = vnode.type.__asyncLoader; if (loadAsync) { loadAsync().then(hydrateComponent); } else { hydrateComponent(); } // component may be async, so in the case of fragments we cannot rely // on component's rendered output to determine the end of the fragment // instead, we do a lookahead to find the end anchor node. nextNode = isFragmentStart ? locateClosingAsyncAnchor(node) : nextSibling(node); } else if (shapeFlag & 64 /* TELEPORT */) { if (domType !== 8 /* COMMENT */) { nextNode = onMismatch(); } else { nextNode = vnode.type.hydrate( node, vnode, parentComponent, parentSuspense, optimized, rendererInternals, hydrateChildren ); } } else if (shapeFlag & 128 /* SUSPENSE */) { nextNode = vnode.type.hydrate( node, vnode, parentComponent, parentSuspense, isSVGContainer(parentNode(node)), optimized, rendererInternals, hydrateNode ); } else if (process.env.NODE_ENV !== 'production') { warn('Invalid HostVNode type:', type, `(${typeof type})`); } } if (ref != null && parentComponent) { setRef(ref, null, parentComponent, parentSuspense, vnode); } return nextNode }; const hydrateElement = ( el, vnode, parentComponent, parentSuspense, optimized ) => { optimized = optimized || !!vnode.dynamicChildren; const { props, patchFlag, shapeFlag, dirs } = vnode; // skip props & children if this is hoisted static nodes if (patchFlag !== -1 /* HOISTED */) { if (dirs) { invokeDirectiveHook(vnode, null, parentComponent, 'created'); } // props if (props) { if ( !optimized || (patchFlag & 16 /* FULL_PROPS */ || patchFlag & 32) /* HYDRATE_EVENTS */ ) { for (const key in props) { if (!isReservedProp(key) && isOn(key)) { patchProp(el, key, null, props[key]); } } } else if (props.onClick) { // Fast path for click listeners (which is most often) to avoid // iterating through props. patchProp(el, 'onClick', null, props.onClick); } } // vnode / directive hooks let vnodeHooks; if ((vnodeHooks = props && props.onVnodeBeforeMount)) { invokeVNodeHook(vnodeHooks, parentComponent, vnode); } if (dirs) { invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount'); } if ((vnodeHooks = props && props.onVnodeMounted) || dirs) { queueEffectWithSuspense(() => { vnodeHooks && invokeVNodeHook(vnodeHooks, parentComponent, vnode); dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted'); }, parentSuspense); } // children if ( shapeFlag & 16 /* ARRAY_CHILDREN */ && // skip if element has innerHTML / textContent !(props && (props.innerHTML || props.textContent)) ) { let next = hydrateChildren( el.firstChild, vnode, el, parentComponent, parentSuspense, optimized ); let hasWarned = false; while (next) { hasMismatch = true; if (process.env.NODE_ENV !== 'production' && !hasWarned) { warn( `Hydration children mismatch in <${vnode.type}>: ` + `server rendered element contains more child nodes than client vdom.` ); hasWarned = true; } // The SSRed DOM contains more nodes than it should. Remove them. const cur = next; next = next.nextSibling; remove(cur); } } else if (shapeFlag & 8 /* TEXT_CHILDREN */) { if (el.textContent !== vnode.children) { hasMismatch = true; process.env.NODE_ENV !== 'production' && warn( `Hydration text content mismatch in <${vnode.type}>:\n` + `- Client: ${el.textContent}\n` + `- Server: ${vnode.children}` ); el.textContent = vnode.children; } } } return el.nextSibling }; const hydrateChildren = ( node, vnode, container, parentComponent, parentSuspense, optimized ) => { optimized = optimized || !!vnode.dynamicChildren; const children = vnode.children; const l = children.length; let hasWarned = false; for (let i = 0; i < l; i++) { const vnode = optimized ? children[i] : (children[i] = normalizeVNode(children[i])); if (node) { node = hydrateNode( node, vnode, parentComponent, parentSuspense, optimized ); } else { hasMismatch = true; if (process.env.NODE_ENV !== 'production' && !hasWarned) { warn( `Hydration children mismatch in <${container.tagName.toLowerCase()}>: ` + `server rendered element contains fewer child nodes than client vdom.` ); hasWarned = true; } // the SSRed DOM didn't contain enough nodes. Mount the missing ones. patch( null, vnode, container, null, parentComponent, parentSuspense, isSVGContainer(container) ); } } return node }; const hydrateFragment = ( node, vnode, parentComponent, parentSuspense, optimized ) => { const container = parentNode(node); const next = hydrateChildren( nextSibling(node), vnode, container, parentComponent, parentSuspense, optimized ); if (next && isComment(next) && next.data === ']') { return nextSibling((vnode.anchor = next)) } else { // fragment didn't hydrate successfully, since we didn't get a end anchor // back. This should have led to node/children mismatch warnings. hasMismatch = true; // since the anchor is missing, we need to create one and insert it insert((vnode.anchor = createComment(`]`)), container, next); return next } }; const handleMismatch = ( node, vnode, parentComponent, parentSuspense, isFragment ) => { hasMismatch = true; process.env.NODE_ENV !== 'production' && warn( `Hydration node mismatch:\n- Client vnode:`, vnode.type, `\n- Server rendered DOM:`, node, node.nodeType === 3 /* TEXT */ ? `(text)` : isComment(node) && node.data === '[' ? `(start of fragment)` : `` ); vnode.el = null; if (isFragment) { // remove excessive fragment nodes const end = locateClosingAsyncAnchor(node); while (true) { const next = nextSibling(node); if (next && next !== end) { remove(next); } else { break } } } const next = nextSibling(node); const container = parentNode(node); remove(node); patch( null, vnode, container, next, parentComponent, parentSuspense, isSVGContainer(container) ); return next }; const locateClosingAsyncAnchor = node => { let match = 0; while (node) { node = nextSibling(node); if (node && isComment(node)) { if (node.data === '[') match++; if (node.data === ']') { if (match === 0) { return nextSibling(node) } else { match--; } } } } return node }; return [hydrate, hydrateNode] } let supported; let perf; function startMeasure(instance, type) { if (instance.appContext.config.performance && isSupported()) { perf.mark(`vue-${type}-${instance.uid}`); } } function endMeasure(instance, type) { if (instance.appContext.config.performance && isSupported()) { const startTag = `vue-${type}-${instance.uid}`; const endTag = startTag + `:end`; perf.mark(endTag); perf.measure( `<${formatComponentName(instance, instance.type)}> ${type}`, startTag, endTag ); perf.clearMarks(startTag); perf.clearMarks(endTag); } } function isSupported() { if (supported !== undefined) { return supported } /* eslint-disable no-restricted-globals */ if (typeof window !== 'undefined' && window.performance) { supported = true; perf = window.performance; } else { supported = false; } /* eslint-enable no-restricted-globals */ return supported } /** * This is only called in esm-bundler builds. * It is called when a renderer is created, in `baseCreateRenderer` so that * importing runtime-core is side-effects free. * * istanbul-ignore-next */ function initFeatureFlags() { let needWarn = false; if (typeof __VUE_OPTIONS_API__ !== 'boolean') { needWarn = true; getGlobalThis().__VUE_OPTIONS_API__ = true; } if (typeof __VUE_PROD_DEVTOOLS__ !== 'boolean') { needWarn = true; getGlobalThis().__VUE_PROD_DEVTOOLS__ = false; } if (process.env.NODE_ENV !== 'production' && needWarn) { console.warn( `You are running the esm-bundler build of Vue. It is recommended to ` + `configure your bundler to explicitly replace feature flag globals ` + `with boolean literals to get proper tree-shaking in the final bundle. ` + `See http://link.vuejs.org/feature-flags for more details.` ); } } 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 } } const queuePostRenderEffect = queueEffectWithSuspense; const setRef = (rawRef, oldRawRef, parentComponent, parentSuspense, vnode) => { let value; if (!vnode) { value = null; } else { if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) { value = vnode.component.proxy; } else { value = vnode.el; } } const [owner, ref] = rawRef; if (process.env.NODE_ENV !== 'production' && !owner) { warn( `Missing ref owner context. ref cannot be used on hoisted vnodes. ` + `A vnode with ref must be created inside the render function.` ); return } const oldRef = oldRawRef && oldRawRef[1]; const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs; const setupState = owner.setupState; // unset old ref if (oldRef != null && oldRef !== ref) { if (isString(oldRef)) { refs[oldRef] = null; if (hasOwn(setupState, oldRef)) { setupState[oldRef] = null; } } else if (isRef(oldRef)) { oldRef.value = null; } } if (isString(ref)) { const doSet = () => { refs[ref] = value; if (hasOwn(setupState, ref)) { setupState[ref] = value; } }; // #1789: for non-null values, set them after render // null values means this is unmount and it should not overwrite another // ref with the same key if (value) { doSet.id = -1; queuePostRenderEffect(doSet, parentSuspense); } else { doSet(); } } else if (isRef(ref)) { const doSet = () => { ref.value = value; }; if (value) { doSet.id = -1; queuePostRenderEffect(doSet, parentSuspense); } else { doSet(); } } else if (isFunction(ref)) { callWithErrorHandling(ref, parentComponent, 12 /* FUNCTION_REF */, [ value, refs ]); } else if (process.env.NODE_ENV !== 'production') { warn('Invalid template ref type:', value, `(${typeof value})`); } }; /** * The createRenderer function accepts two generic arguments: * HostNode and HostElement, corresponding to Node and Element types in the * host environment. For example, for runtime-dom, HostNode would be the DOM * `Node` interface and HostElement would be the DOM `Element` interface. * * Custom renderers can pass in the platform specific types like this: * * ``` js * const { render, createApp } = createRenderer({ * patchProp, * ...nodeOps * }) * ``` */ function createRenderer(options) { return baseCreateRenderer(options) } // Separate API for creating hydration-enabled renderer. // Hydration logic is only used when calling this function, making it // tree-shakable. function createHydrationRenderer(options) { return baseCreateRenderer(options, createHydrationFunctions) } // implementation function baseCreateRenderer(options, createHydrationFns) { // compile-time feature flags check { initFeatureFlags(); } const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, forcePatchProp: hostForcePatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options; // Note: functions inside this closure should use `const xxx = () => {}` // style in order to prevent being inlined by minifiers. const patch = ( n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, optimized = false ) => { // patching & not same type, unmount old tree if (n1 && !isSameVNodeType(n1, n2)) { anchor = getNextHostNode(n1); unmount(n1, parentComponent, parentSuspense, true); n1 = null; } if (n2.patchFlag === -2 /* BAIL */) { optimized = false; n2.dynamicChildren = null; } const { type, ref, shapeFlag } = n2; switch (type) { case Text: processText(n1, n2, container, anchor); break case Comment: processCommentNode(n1, n2, container, anchor); break case Static: if (n1 == null) { mountStaticNode(n2, container, anchor, isSVG); } else if (process.env.NODE_ENV !== 'production') { patchStaticNode(n1, n2, container, isSVG); } break case Fragment: processFragment( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ); break default: if (shapeFlag & 1 /* ELEMENT */) { processElement( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ); } else if (shapeFlag & 6 /* COMPONENT */) { processComponent( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ); } else if (shapeFlag & 64 /* TELEPORT */) { type.process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals ); } else if (shapeFlag & 128 /* SUSPENSE */) { type.process( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals ); } else if (process.env.NODE_ENV !== 'production') { warn('Invalid VNode type:', type, `(${typeof type})`); } } // set ref if (ref != null && parentComponent) { setRef(ref, n1 && n1.ref, parentComponent, parentSuspense, n2); } }; const processText = (n1, n2, container, anchor) => { if (n1 == null) { hostInsert((n2.el = hostCreateText(n2.children)), container, anchor); } else { const el = (n2.el = n1.el); if (n2.children !== n1.children) { hostSetText(el, n2.children); } } }; const processCommentNode = (n1, n2, container, anchor) => { if (n1 == null) { hostInsert( (n2.el = hostCreateComment(n2.children || '')), container, anchor ); } else { // there's no support for dynamic comments n2.el = n1.el; } }; const mountStaticNode = (n2, container, anchor, isSVG) => { [n2.el, n2.anchor] = hostInsertStaticContent( n2.children, container, anchor, isSVG ); }; /** * Dev / HMR only */ const patchStaticNode = (n1, n2, container, isSVG) => { // static nodes are only patched during dev for HMR if (n2.children !== n1.children) { const anchor = hostNextSibling(n1.anchor); // remove existing removeStaticNode(n1) ;[n2.el, n2.anchor] = hostInsertStaticContent( n2.children, container, anchor, isSVG ); } else { n2.el = n1.el; n2.anchor = n1.anchor; } }; /** * Dev / HMR only */ const moveStaticNode = (vnode, container, anchor) => { let cur = vnode.el; const end = vnode.anchor; while (cur && cur !== end) { const next = hostNextSibling(cur); hostInsert(cur, container, anchor); cur = next; } hostInsert(end, container, anchor); }; /** * Dev / HMR only */ const removeStaticNode = vnode => { let cur = vnode.el; while (cur && cur !== vnode.anchor) { const next = hostNextSibling(cur); hostRemove(cur); cur = next; } hostRemove(vnode.anchor); }; const processElement = ( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) => { isSVG = isSVG || n2.type === 'svg'; if (n1 == null) { mountElement( n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ); } else { patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized); } }; const mountElement = ( vnode, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) => { let el; let vnodeHook; const { type, props, shapeFlag, transition, scopeId, patchFlag, dirs } = vnode; if ( !(process.env.NODE_ENV !== 'production') && vnode.el && hostCloneNode !== undefined && patchFlag === -1 /* HOISTED */ ) { // If a vnode has non-null el, it means it's being reused. // Only static vnodes can be reused, so its mounted DOM nodes should be // exactly the same, and we can simply do a clone here. // only do this in production since cloned trees cannot be HMR updated. el = vnode.el = hostCloneNode(vnode.el); } else { el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is); // mount children first, since some props may rely on child content // being already rendered, e.g. `