From e60444a474566a813abb443f61d973cd60b1564a Mon Sep 17 00:00:00 2001 From: tofulm Date: Mon, 24 Jan 2022 16:55:48 +0100 Subject: [PATCH] maj de vue en 3.2.29 --- js/vue.js | 3029 +++++++++++++++++++++++-------------------------- js/vue.min.js | 2 +- 2 files changed, 1449 insertions(+), 1582 deletions(-) diff --git a/js/vue.js b/js/vue.js index b9dd2f3..d8f2eb7 100644 --- a/js/vue.js +++ b/js/vue.js @@ -110,7 +110,7 @@ var Vue = (function (exports) { const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); /** * Boolean attributes should be included if the value is truthy or ''. - * e.g. ` compiles to `{ multiple: '' }` */ function includeBooleanAttr(value) { return !!value || value === ''; @@ -209,8 +209,20 @@ var Vue = (function (exports) { 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' + 'text,textPath,title,tspan,unknown,use,view'; const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr'; + /** + * Compiler only. + * Do NOT use in runtime code paths unless behind `true` flag. + */ const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS); + /** + * Compiler only. + * Do NOT use in runtime code paths unless behind `true` flag. + */ const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS); + /** + * Compiler only. + * Do NOT use in runtime code paths unless behind `true` flag. + */ const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS); function looseCompareArrays(a, b) { @@ -344,7 +356,7 @@ var Vue = (function (exports) { '' + parseInt(key, 10) === key; const isReservedProp = /*#__PURE__*/ makeMap( // the leading comma is intentional so empty string "" is also included - ',key,ref,' + + ',key,ref,ref_for,ref_key,' + 'onVnodeBeforeMount,onVnodeMounted,' + 'onVnodeBeforeUpdate,onVnodeUpdated,' + 'onVnodeBeforeUnmount,onVnodeUnmounted'); @@ -533,7 +545,7 @@ var Vue = (function (exports) { let effectTrackDepth = 0; let trackOpBit = 1; /** - * The bitwise track markers support at most 30 levels op recursion. + * The bitwise track markers support at most 30 levels of recursion. * This value is chosen to enable modern JS engines to use a SMI on all platforms. * When recursion depth is greater, fall back to using a full cleanup. */ @@ -554,7 +566,7 @@ var Vue = (function (exports) { if (!this.active) { return this.fn(); } - if (!effectStack.includes(this)) { + if (!effectStack.length || !effectStack.includes(this)) { try { effectStack.push((activeEffect = this)); enableTracking(); @@ -810,6 +822,9 @@ var Vue = (function (exports) { else if (key === "__v_isReadonly" /* IS_READONLY */) { return isReadonly; } + else if (key === "__v_isShallow" /* IS_SHALLOW */) { + return shallow; + } else if (key === "__v_raw" /* RAW */ && receiver === (isReadonly @@ -854,9 +869,14 @@ var Vue = (function (exports) { function createSetter(shallow = false) { return function set(target, key, value, receiver) { let oldValue = target[key]; - if (!shallow) { - value = toRaw(value); - oldValue = toRaw(oldValue); + if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) { + return false; + } + if (!shallow && !isReadonly(value)) { + if (!isShallow(value)) { + value = toRaw(value); + oldValue = toRaw(oldValue); + } if (!isArray(target) && isRef(oldValue) && !isRef(value)) { oldValue.value = value; return true; @@ -931,8 +951,6 @@ var Vue = (function (exports) { 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) { @@ -1245,7 +1263,7 @@ var Vue = (function (exports) { } function reactive(target) { // if trying to observe a readonly proxy, return the readonly version. - if (target && target["__v_isReadonly" /* IS_READONLY */]) { + if (isReadonly(target)) { return target; } return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap); @@ -1310,6 +1328,9 @@ var Vue = (function (exports) { function isReadonly(value) { return !!(value && value["__v_isReadonly" /* IS_READONLY */]); } + function isShallow(value) { + return !!(value && value["__v_isShallow" /* IS_SHALLOW */]); + } function isProxy(value) { return isReactive(value) || isReadonly(value); } @@ -1320,7 +1341,9 @@ var Vue = (function (exports) { function markRaw(value) { def(value, "__v_skip" /* SKIP */, true); return value; - } + } + const toReactive = (value) => isObject(value) ? reactive(value) : value; + const toReadonly = (value) => isObject(value) ? readonly(value) : value; function trackRefValue(ref) { if (isTracking()) { @@ -1350,43 +1373,42 @@ var Vue = (function (exports) { } } } - const convert = (val) => isObject(val) ? reactive(val) : val; function isRef(r) { return Boolean(r && r.__v_isRef === true); } function ref(value) { - return createRef(value); + return createRef(value, false); } function shallowRef(value) { return createRef(value, true); } + function createRef(rawValue, shallow) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); + } class RefImpl { - constructor(value, _shallow = false) { - this._shallow = _shallow; + constructor(value, __v_isShallow) { + this.__v_isShallow = __v_isShallow; this.dep = undefined; this.__v_isRef = true; - this._rawValue = _shallow ? value : toRaw(value); - this._value = _shallow ? value : convert(value); + this._rawValue = __v_isShallow ? value : toRaw(value); + this._value = __v_isShallow ? value : toReactive(value); } get value() { trackRefValue(this); return this._value; } set value(newVal) { - newVal = this._shallow ? newVal : toRaw(newVal); + newVal = this.__v_isShallow ? newVal : toRaw(newVal); if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal; - this._value = this._shallow ? newVal : convert(newVal); + this._value = this.__v_isShallow ? newVal : toReactive(newVal); triggerRefValue(this, newVal); } } } - function createRef(rawValue, shallow = false) { - if (isRef(rawValue)) { - return rawValue; - } - return new RefImpl(rawValue, shallow); - } function triggerRef(ref) { triggerRefValue(ref, ref.value ); } @@ -1440,42 +1462,48 @@ var Vue = (function (exports) { return ret; } class ObjectRefImpl { - constructor(_object, _key) { + constructor(_object, _key, _defaultValue) { this._object = _object; this._key = _key; + this._defaultValue = _defaultValue; this.__v_isRef = true; } get value() { - return this._object[this._key]; + const val = this._object[this._key]; + return val === undefined ? this._defaultValue : val; } set value(newVal) { this._object[this._key] = newVal; } } - function toRef(object, key) { + function toRef(object, key, defaultValue) { const val = object[key]; - return isRef(val) ? val : new ObjectRefImpl(object, key); + return isRef(val) + ? val + : new ObjectRefImpl(object, key, defaultValue); } class ComputedRefImpl { - constructor(getter, _setter, isReadonly) { + constructor(getter, _setter, isReadonly, isSSR) { this._setter = _setter; this.dep = undefined; - this._dirty = true; this.__v_isRef = true; + this._dirty = true; this.effect = new ReactiveEffect(getter, () => { if (!this._dirty) { this._dirty = true; triggerRefValue(this); } }); + this.effect.computed = this; + this.effect.active = this._cacheable = !isSSR; this["__v_isReadonly" /* IS_READONLY */] = isReadonly; } get value() { // the computed ref may get wrapped by other proxies e.g. readonly() #3376 const self = toRaw(this); trackRefValue(self); - if (self._dirty) { + if (self._dirty || !self._cacheable) { self._dirty = false; self._value = self.effect.run(); } @@ -1485,10 +1513,11 @@ var Vue = (function (exports) { this._setter(newValue); } } - function computed(getterOrOptions, debugOptions) { + function computed(getterOrOptions, debugOptions, isSSR = false) { let getter; let setter; - if (isFunction(getterOrOptions)) { + const onlyGetter = isFunction(getterOrOptions); + if (onlyGetter) { getter = getterOrOptions; setter = () => { console.warn('Write operation failed: computed value is readonly'); @@ -1499,14 +1528,436 @@ var Vue = (function (exports) { getter = getterOrOptions.get; setter = getterOrOptions.set; } - const cRef = new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set); - if (debugOptions) { + const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR); + if (debugOptions && !isSSR) { cRef.effect.onTrack = debugOptions.onTrack; cRef.effect.onTrigger = debugOptions.onTrigger; } return cRef; } + const stack = []; + function pushWarningContext(vnode) { + stack.push(vnode); + } + function popWarningContext() { + stack.pop(); + } + function warn$1(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 = { + ["sp" /* SERVER_PREFETCH */]: 'serverPrefetch hook', + ["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/core' + }; + 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, throwInDev = true) { + 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 = ErrorTypeStrings[type] ; + while (cur) { + const errorCapturedHooks = cur.ec; + if (errorCapturedHooks) { + for (let i = 0; i < errorCapturedHooks.length; i++) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { + 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, throwInDev); + } + function logError(err, type, contextVNode, throwInDev = true) { + { + const info = ErrorTypeStrings[type]; + if (contextVNode) { + pushWarningContext(contextVNode); + } + warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`); + if (contextVNode) { + popWarningContext(); + } + // crash in dev by default so it's more noticeable + if (throwInDev) { + throw err; + } + else { + 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(this ? fn.bind(this) : fn) : p; + } + // #2768 + // Use binary-search to find a suitable position in the queue, + // so that the queue maintains the increasing order of job's id, + // which can prevent the job from being skipped and also can avoid repeated patching. + function findInsertionIndex(id) { + // the start index should be `flushIndex + 1` + let start = flushIndex + 1; + let end = queue.length; + while (start < end) { + const middle = (start + end) >>> 1; + const middleJobId = getId(queue[middle]); + middleJobId < id ? (start = middle + 1) : (end = middle); + } + return start; + } + 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) { + if (job.id == null) { + queue.push(job); + } + else { + queue.splice(findInsertionIndex(job.id), 0, job); + } + queueFlush(); + } + } + function queueFlush() { + if (!isFlushing && !isFlushPending) { + isFlushPending = true; + currentFlushPromise = resolvedPromise.then(flushJobs); + } + } + function invalidateJob(job) { + const i = queue.indexOf(job); + if (i > flushIndex) { + queue.splice(i, 1); + } + } + 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; + { + seen = seen || new Map(); + } + for (preFlushIndex = 0; preFlushIndex < activePreFlushCbs.length; preFlushIndex++) { + if (checkRecursiveUpdates(seen, activePreFlushCbs[preFlushIndex])) { + continue; + } + 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; + { + seen = seen || new Map(); + } + activePostFlushCbs.sort((a, b) => getId(a) - getId(b)); + for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) { + if (checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex])) { + continue; + } + activePostFlushCbs[postFlushIndex](); + } + activePostFlushCbs = null; + postFlushIndex = 0; + } + } + const getId = (job) => job.id == null ? Infinity : job.id; + function flushJobs(seen) { + isFlushPending = false; + isFlushing = true; + { + 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. + queue.sort((a, b) => getId(a) - getId(b)); + // conditional usage of checkRecursiveUpdate must be determined out of + // try ... catch block since Rollup by default de-optimizes treeshaking + // inside try-catch. This can leave all warning code unshaked. Although + // they would get eventually shaken by a minifier like terser, some minifiers + // would fail to do that (e.g. https://github.com/evanw/esbuild/issues/1610) + const check = (job) => checkRecursiveUpdates(seen, job) + ; + try { + for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { + const job = queue[flushIndex]; + if (job && job.active !== false) { + if (true && check(job)) { + continue; + } + // console.log(`running:`, job.id) + 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 || + pendingPreFlushCbs.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) { + const instance = fn.ownerInstance; + const componentName = instance && getComponentName(instance.type); + warn$1(`Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. ` + + `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.`); + return true; + } + else { + seen.set(fn, count + 1); + } + } + } + /* eslint-disable no-restricted-globals */ let isHmrUpdating = false; const hmrDirtyComponents = new Set(); @@ -1516,14 +1967,7 @@ var Vue = (function (exports) { // 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. { - const globalObject = typeof global !== 'undefined' - ? global - : typeof self !== 'undefined' - ? self - : typeof window !== 'undefined' - ? window - : {}; - globalObject.__VUE_HMR_RUNTIME__ = { + getGlobalThis().__VUE_HMR_RUNTIME__ = { createRecord: tryWrap(createRecord), rerender: tryWrap(rerender), reload: tryWrap(reload) @@ -1542,33 +1986,30 @@ var Vue = (function (exports) { function unregisterHMR(instance) { map.get(instance.type.__hmrId).instances.delete(instance); } - function createRecord(id, component) { - if (!component) { - warn$1(`HMR API usage is out of date.\n` + - `Please upgrade vue-loader/vite/rollup-plugin-vue or other relevant ` + - `dependency that handles Vue SFC compilation.`); - component = {}; - } + function createRecord(id, initialDef) { if (map.has(id)) { return false; } map.set(id, { - component: isClassComponent(component) ? component.__vccOpts : component, + initialDef: normalizeClassComponent(initialDef), instances: new Set() }); return true; } + function normalizeClassComponent(component) { + return isClassComponent(component) ? component.__vccOpts : component; + } function rerender(id, newRender) { const record = map.get(id); - if (!record) + if (!record) { return; - if (newRender) - record.component.render = newRender; - // Array.from creates a snapshot which avoids the set being mutated during - // updates - Array.from(record.instances).forEach(instance => { + } + // update initial record (for not-yet-rendered component) + record.initialDef.render = newRender; + [...record.instances].forEach(instance => { if (newRender) { instance.render = newRender; + normalizeClassComponent(instance.type).render = newRender; } instance.renderCache = []; // this flag forces child components with slot content to update @@ -1581,34 +2022,30 @@ var Vue = (function (exports) { const record = map.get(id); if (!record) return; - // Array.from creates a snapshot which avoids the set being mutated during - // updates - const { component, instances } = record; - if (!hmrDirtyComponents.has(component)) { - // 1. Update existing comp definition to match new one - newComp = isClassComponent(newComp) ? newComp.__vccOpts : newComp; - extend(component, newComp); - for (const key in component) { - if (key !== '__file' && !(key in newComp)) { - delete component[key]; + newComp = normalizeClassComponent(newComp); + // update initial def (for not-yet-rendered components) + updateComponentDef(record.initialDef, newComp); + // create a snapshot which avoids the set being mutated during updates + const instances = [...record.instances]; + for (const instance of instances) { + const oldComp = normalizeClassComponent(instance.type); + if (!hmrDirtyComponents.has(oldComp)) { + // 1. Update existing comp definition to match new one + if (oldComp !== record.initialDef) { + updateComponentDef(oldComp, newComp); } + // 2. mark definition dirty. This forces the renderer to replace the + // component on patch. + hmrDirtyComponents.add(oldComp); } - // 2. Mark component dirty. This forces the renderer to replace the component - // on patch. - hmrDirtyComponents.add(component); - // 3. Make sure to unmark the component after the reload. - queuePostFlushCb(() => { - hmrDirtyComponents.delete(component); - }); - } - Array.from(instances).forEach(instance => { - // invalidate options resolution cache + // 3. invalidate options resolution cache instance.appContext.optionsCache.delete(instance.type); + // 4. actually update if (instance.ceReload) { // custom element - hmrDirtyComponents.add(component); + hmrDirtyComponents.add(oldComp); instance.ceReload(newComp.styles); - hmrDirtyComponents.delete(component); + hmrDirtyComponents.delete(oldComp); } else if (instance.parent) { // 4. Force the parent instance to re-render. This will cause all updated @@ -1633,8 +2070,22 @@ var Vue = (function (exports) { else { console.warn('[HMR] Root or manually mounted instance modified. Full reload required.'); } + } + // 5. make sure to cleanup dirty hmr components after update + queuePostFlushCb(() => { + for (const instance of instances) { + hmrDirtyComponents.delete(normalizeClassComponent(instance.type)); + } }); } + function updateComponentDef(oldComp, newComp) { + extend(oldComp, newComp); + for (const key in oldComp) { + if (key !== '__file' && !(key in newComp)) { + delete oldComp[key]; + } + } + } function tryWrap(fn) { return (id, arg) => { try { @@ -1648,24 +2099,65 @@ var Vue = (function (exports) { }; } - function setDevtoolsHook(hook) { + let buffer = []; + let devtoolsNotInstalled = false; + function emit(event, ...args) { + if (exports.devtools) { + exports.devtools.emit(event, ...args); + } + else if (!devtoolsNotInstalled) { + buffer.push({ event, args }); + } + } + function setDevtoolsHook(hook, target) { + var _a, _b; exports.devtools = hook; + if (exports.devtools) { + exports.devtools.enabled = true; + buffer.forEach(({ event, args }) => exports.devtools.emit(event, ...args)); + buffer = []; + } + else if ( + // handle late devtools injection - only do this if we are in an actual + // browser environment to avoid the timer handle stalling test runner exit + // (#4815) + // eslint-disable-next-line no-restricted-globals + typeof window !== 'undefined' && + // some envs mock window but not fully + window.HTMLElement && + // also exclude jsdom + !((_b = (_a = window.navigator) === null || _a === void 0 ? void 0 : _a.userAgent) === null || _b === void 0 ? void 0 : _b.includes('jsdom'))) { + const replay = (target.__VUE_DEVTOOLS_HOOK_REPLAY__ = + target.__VUE_DEVTOOLS_HOOK_REPLAY__ || []); + replay.push((newHook) => { + setDevtoolsHook(newHook, target); + }); + // clear buffer after 3s - the user probably doesn't have devtools installed + // at all, and keeping the buffer will cause memory leaks (#4738) + setTimeout(() => { + if (!exports.devtools) { + target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null; + devtoolsNotInstalled = true; + buffer = []; + } + }, 3000); + } + else { + // non-browser env, assume not installed + devtoolsNotInstalled = true; + buffer = []; + } } function devtoolsInitApp(app, version) { - // TODO queue if devtools is undefined - if (!exports.devtools) - return; - exports.devtools.emit("app:init" /* APP_INIT */, app, version, { + emit("app:init" /* APP_INIT */, app, version, { Fragment, Text, - Comment: Comment$1, + Comment, Static }); } function devtoolsUnmountApp(app) { - if (!exports.devtools) - return; - exports.devtools.emit("app:unmount" /* APP_UNMOUNT */, app); + emit("app:unmount" /* APP_UNMOUNT */, app); } const devtoolsComponentAdded = /*#__PURE__*/ createDevtoolsComponentHook("component:added" /* COMPONENT_ADDED */); const devtoolsComponentUpdated = @@ -1674,356 +2166,21 @@ var Vue = (function (exports) { /*#__PURE__*/ createDevtoolsComponentHook("component:removed" /* COMPONENT_REMOVED */); function createDevtoolsComponentHook(hook) { return (component) => { - if (!exports.devtools) - return; - exports.devtools.emit(hook, component.appContext.app, component.uid, component.parent ? component.parent.uid : undefined, component); + emit(hook, component.appContext.app, component.uid, component.parent ? component.parent.uid : undefined, component); }; } const devtoolsPerfStart = /*#__PURE__*/ createDevtoolsPerformanceHook("perf:start" /* PERFORMANCE_START */); const devtoolsPerfEnd = /*#__PURE__*/ createDevtoolsPerformanceHook("perf:end" /* PERFORMANCE_END */); function createDevtoolsPerformanceHook(hook) { return (component, type, time) => { - if (!exports.devtools) - return; - exports.devtools.emit(hook, component.appContext.app, component.uid, component, type, time); + emit(hook, component.appContext.app, component.uid, component, type, time); }; } function devtoolsComponentEmit(component, event, params) { - if (!exports.devtools) - return; - exports.devtools.emit("component:emit" /* COMPONENT_EMIT */, component.appContext.app, component, event, params); + emit("component:emit" /* COMPONENT_EMIT */, component.appContext.app, component, event, params); } - const deprecationData = { - ["GLOBAL_MOUNT" /* GLOBAL_MOUNT */]: { - message: `The global app bootstrapping API has changed: vm.$mount() and the "el" ` + - `option have been removed. Use createApp(RootComponent).mount() instead.`, - link: `https://v3.vuejs.org/guide/migration/global-api.html#mounting-app-instance` - }, - ["GLOBAL_MOUNT_CONTAINER" /* GLOBAL_MOUNT_CONTAINER */]: { - message: `Vue detected directives on the mount container. ` + - `In Vue 3, the container is no longer considered part of the template ` + - `and will not be processed/replaced.`, - link: `https://v3.vuejs.org/guide/migration/mount-changes.html` - }, - ["GLOBAL_EXTEND" /* GLOBAL_EXTEND */]: { - message: `Vue.extend() has been removed in Vue 3. ` + - `Use defineComponent() instead.`, - link: `https://v3.vuejs.org/api/global-api.html#definecomponent` - }, - ["GLOBAL_PROTOTYPE" /* GLOBAL_PROTOTYPE */]: { - message: `Vue.prototype is no longer available in Vue 3. ` + - `Use app.config.globalProperties instead.`, - link: `https://v3.vuejs.org/guide/migration/global-api.html#vue-prototype-replaced-by-config-globalproperties` - }, - ["GLOBAL_SET" /* GLOBAL_SET */]: { - message: `Vue.set() has been removed as it is no longer needed in Vue 3. ` + - `Simply use native JavaScript mutations.` - }, - ["GLOBAL_DELETE" /* GLOBAL_DELETE */]: { - message: `Vue.delete() has been removed as it is no longer needed in Vue 3. ` + - `Simply use native JavaScript mutations.` - }, - ["GLOBAL_OBSERVABLE" /* GLOBAL_OBSERVABLE */]: { - message: `Vue.observable() has been removed. ` + - `Use \`import { reactive } from "vue"\` from Composition API instead.`, - link: `https://v3.vuejs.org/api/basic-reactivity.html` - }, - ["GLOBAL_PRIVATE_UTIL" /* GLOBAL_PRIVATE_UTIL */]: { - message: `Vue.util has been removed. Please refactor to avoid its usage ` + - `since it was an internal API even in Vue 2.` - }, - ["CONFIG_SILENT" /* CONFIG_SILENT */]: { - message: `config.silent has been removed because it is not good practice to ` + - `intentionally suppress warnings. You can use your browser console's ` + - `filter features to focus on relevant messages.` - }, - ["CONFIG_DEVTOOLS" /* CONFIG_DEVTOOLS */]: { - message: `config.devtools has been removed. To enable devtools for ` + - `production, configure the __VUE_PROD_DEVTOOLS__ compile-time flag.`, - link: `https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags` - }, - ["CONFIG_KEY_CODES" /* CONFIG_KEY_CODES */]: { - message: `config.keyCodes has been removed. ` + - `In Vue 3, you can directly use the kebab-case key names as v-on modifiers.`, - link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html` - }, - ["CONFIG_PRODUCTION_TIP" /* CONFIG_PRODUCTION_TIP */]: { - message: `config.productionTip has been removed.`, - link: `https://v3.vuejs.org/guide/migration/global-api.html#config-productiontip-removed` - }, - ["CONFIG_IGNORED_ELEMENTS" /* CONFIG_IGNORED_ELEMENTS */]: { - message: () => { - let msg = `config.ignoredElements has been removed.`; - if (isRuntimeOnly()) { - msg += ` Pass the "isCustomElement" option to @vue/compiler-dom instead.`; - } - else { - msg += ` Use config.isCustomElement instead.`; - } - return msg; - }, - link: `https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement` - }, - ["CONFIG_WHITESPACE" /* CONFIG_WHITESPACE */]: { - // this warning is only relevant in the full build when using runtime - // compilation, so it's put in the runtime compatConfig list. - message: `Vue 3 compiler's whitespace option will default to "condense" instead of ` + - `"preserve". To suppress this warning, provide an explicit value for ` + - `\`config.compilerOptions.whitespace\`.` - }, - ["CONFIG_OPTION_MERGE_STRATS" /* CONFIG_OPTION_MERGE_STRATS */]: { - message: `config.optionMergeStrategies no longer exposes internal strategies. ` + - `Use custom merge functions instead.` - }, - ["INSTANCE_SET" /* INSTANCE_SET */]: { - message: `vm.$set() has been removed as it is no longer needed in Vue 3. ` + - `Simply use native JavaScript mutations.` - }, - ["INSTANCE_DELETE" /* INSTANCE_DELETE */]: { - message: `vm.$delete() has been removed as it is no longer needed in Vue 3. ` + - `Simply use native JavaScript mutations.` - }, - ["INSTANCE_DESTROY" /* INSTANCE_DESTROY */]: { - message: `vm.$destroy() has been removed. Use app.unmount() instead.`, - link: `https://v3.vuejs.org/api/application-api.html#unmount` - }, - ["INSTANCE_EVENT_EMITTER" /* INSTANCE_EVENT_EMITTER */]: { - message: `vm.$on/$once/$off() have been removed. ` + - `Use an external event emitter library instead.`, - link: `https://v3.vuejs.org/guide/migration/events-api.html` - }, - ["INSTANCE_EVENT_HOOKS" /* INSTANCE_EVENT_HOOKS */]: { - message: event => `"${event}" lifecycle events are no longer supported. From templates, ` + - `use the "vnode" prefix instead of "hook:". For example, @${event} ` + - `should be changed to @vnode-${event.slice(5)}. ` + - `From JavaScript, use Composition API to dynamically register lifecycle ` + - `hooks.`, - link: `https://v3.vuejs.org/guide/migration/vnode-lifecycle-events.html` - }, - ["INSTANCE_CHILDREN" /* INSTANCE_CHILDREN */]: { - message: `vm.$children has been removed. Consider refactoring your logic ` + - `to avoid relying on direct access to child components.`, - link: `https://v3.vuejs.org/guide/migration/children.html` - }, - ["INSTANCE_LISTENERS" /* INSTANCE_LISTENERS */]: { - message: `vm.$listeners has been removed. In Vue 3, parent v-on listeners are ` + - `included in vm.$attrs and it is no longer necessary to separately use ` + - `v-on="$listeners" if you are already using v-bind="$attrs". ` + - `(Note: the Vue 3 behavior only applies if this compat config is disabled)`, - link: `https://v3.vuejs.org/guide/migration/listeners-removed.html` - }, - ["INSTANCE_SCOPED_SLOTS" /* INSTANCE_SCOPED_SLOTS */]: { - message: `vm.$scopedSlots has been removed. Use vm.$slots instead.`, - link: `https://v3.vuejs.org/guide/migration/slots-unification.html` - }, - ["INSTANCE_ATTRS_CLASS_STYLE" /* INSTANCE_ATTRS_CLASS_STYLE */]: { - message: componentName => `Component <${componentName || 'Anonymous'}> has \`inheritAttrs: false\` but is ` + - `relying on class/style fallthrough from parent. In Vue 3, class/style ` + - `are now included in $attrs and will no longer fallthrough when ` + - `inheritAttrs is false. If you are already using v-bind="$attrs" on ` + - `component root it should render the same end result. ` + - `If you are binding $attrs to a non-root element and expecting ` + - `class/style to fallthrough on root, you will need to now manually bind ` + - `them on root via :class="$attrs.class".`, - link: `https://v3.vuejs.org/guide/migration/attrs-includes-class-style.html` - }, - ["OPTIONS_DATA_FN" /* OPTIONS_DATA_FN */]: { - message: `The "data" option can no longer be a plain object. ` + - `Always use a function.`, - link: `https://v3.vuejs.org/guide/migration/data-option.html` - }, - ["OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */]: { - message: (key) => `Detected conflicting key "${key}" when merging data option values. ` + - `In Vue 3, data keys are merged shallowly and will override one another.`, - link: `https://v3.vuejs.org/guide/migration/data-option.html#mixin-merge-behavior-change` - }, - ["OPTIONS_BEFORE_DESTROY" /* OPTIONS_BEFORE_DESTROY */]: { - message: `\`beforeDestroy\` has been renamed to \`beforeUnmount\`.` - }, - ["OPTIONS_DESTROYED" /* OPTIONS_DESTROYED */]: { - message: `\`destroyed\` has been renamed to \`unmounted\`.` - }, - ["WATCH_ARRAY" /* WATCH_ARRAY */]: { - message: `"watch" option or vm.$watch on an array value will no longer ` + - `trigger on array mutation unless the "deep" option is specified. ` + - `If current usage is intended, you can disable the compat behavior and ` + - `suppress this warning with:` + - `\n\n configureCompat({ ${"WATCH_ARRAY" /* WATCH_ARRAY */}: false })\n`, - link: `https://v3.vuejs.org/guide/migration/watch.html` - }, - ["PROPS_DEFAULT_THIS" /* PROPS_DEFAULT_THIS */]: { - message: (key) => `props default value function no longer has access to "this". The compat ` + - `build only offers access to this.$options.` + - `(found in prop "${key}")`, - link: `https://v3.vuejs.org/guide/migration/props-default-this.html` - }, - ["CUSTOM_DIR" /* CUSTOM_DIR */]: { - message: (legacyHook, newHook) => `Custom directive hook "${legacyHook}" has been removed. ` + - `Use "${newHook}" instead.`, - link: `https://v3.vuejs.org/guide/migration/custom-directives.html` - }, - ["V_FOR_REF" /* V_FOR_REF */]: { - message: `Ref usage on v-for no longer creates array ref values in Vue 3. ` + - `Consider using function refs or refactor to avoid ref usage altogether.`, - link: `https://v3.vuejs.org/guide/migration/array-refs.html` - }, - ["V_ON_KEYCODE_MODIFIER" /* V_ON_KEYCODE_MODIFIER */]: { - message: `Using keyCode as v-on modifier is no longer supported. ` + - `Use kebab-case key name modifiers instead.`, - link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html` - }, - ["ATTR_FALSE_VALUE" /* ATTR_FALSE_VALUE */]: { - message: (name) => `Attribute "${name}" with v-bind value \`false\` will render ` + - `${name}="false" instead of removing it in Vue 3. To remove the attribute, ` + - `use \`null\` or \`undefined\` instead. If the usage is intended, ` + - `you can disable the compat behavior and suppress this warning with:` + - `\n\n configureCompat({ ${"ATTR_FALSE_VALUE" /* ATTR_FALSE_VALUE */}: false })\n`, - link: `https://v3.vuejs.org/guide/migration/attribute-coercion.html` - }, - ["ATTR_ENUMERATED_COERCION" /* ATTR_ENUMERATED_COERCION */]: { - message: (name, value, coerced) => `Enumerated attribute "${name}" with v-bind value \`${value}\` will ` + - `${value === null ? `be removed` : `render the value as-is`} instead of coercing the value to "${coerced}" in Vue 3. ` + - `Always use explicit "true" or "false" values for enumerated attributes. ` + - `If the usage is intended, ` + - `you can disable the compat behavior and suppress this warning with:` + - `\n\n configureCompat({ ${"ATTR_ENUMERATED_COERCION" /* ATTR_ENUMERATED_COERCION */}: false })\n`, - link: `https://v3.vuejs.org/guide/migration/attribute-coercion.html` - }, - ["TRANSITION_CLASSES" /* TRANSITION_CLASSES */]: { - message: `` // this feature cannot be runtime-detected - }, - ["TRANSITION_GROUP_ROOT" /* TRANSITION_GROUP_ROOT */]: { - message: ` no longer renders a root element by ` + - `default if no "tag" prop is specified. If you do not rely on the span ` + - `for styling, you can disable the compat behavior and suppress this ` + - `warning with:` + - `\n\n configureCompat({ ${"TRANSITION_GROUP_ROOT" /* TRANSITION_GROUP_ROOT */}: false })\n`, - link: `https://v3.vuejs.org/guide/migration/transition-group.html` - }, - ["COMPONENT_ASYNC" /* COMPONENT_ASYNC */]: { - message: (comp) => { - const name = getComponentName(comp); - return (`Async component${name ? ` <${name}>` : `s`} should be explicitly created via \`defineAsyncComponent()\` ` + - `in Vue 3. Plain functions will be treated as functional components in ` + - `non-compat build. If you have already migrated all async component ` + - `usage and intend to use plain functions for functional components, ` + - `you can disable the compat behavior and suppress this ` + - `warning with:` + - `\n\n configureCompat({ ${"COMPONENT_ASYNC" /* COMPONENT_ASYNC */}: false })\n`); - }, - link: `https://v3.vuejs.org/guide/migration/async-components.html` - }, - ["COMPONENT_FUNCTIONAL" /* COMPONENT_FUNCTIONAL */]: { - message: (comp) => { - const name = getComponentName(comp); - return (`Functional component${name ? ` <${name}>` : `s`} should be defined as a plain function in Vue 3. The "functional" ` + - `option has been removed. NOTE: Before migrating to use plain ` + - `functions for functional components, first make sure that all async ` + - `components usage have been migrated and its compat behavior has ` + - `been disabled.`); - }, - link: `https://v3.vuejs.org/guide/migration/functional-components.html` - }, - ["COMPONENT_V_MODEL" /* COMPONENT_V_MODEL */]: { - message: (comp) => { - const configMsg = `opt-in to ` + - `Vue 3 behavior on a per-component basis with \`compatConfig: { ${"COMPONENT_V_MODEL" /* COMPONENT_V_MODEL */}: false }\`.`; - if (comp.props && - (isArray(comp.props) - ? comp.props.includes('modelValue') - : hasOwn(comp.props, 'modelValue'))) { - return (`Component delcares "modelValue" prop, which is Vue 3 usage, but ` + - `is running under Vue 2 compat v-model behavior. You can ${configMsg}`); - } - return (`v-model usage on component has changed in Vue 3. Component that expects ` + - `to work with v-model should now use the "modelValue" prop and emit the ` + - `"update:modelValue" event. You can update the usage and then ${configMsg}`); - }, - link: `https://v3.vuejs.org/guide/migration/v-model.html` - }, - ["RENDER_FUNCTION" /* RENDER_FUNCTION */]: { - message: `Vue 3's render function API has changed. ` + - `You can opt-in to the new API with:` + - `\n\n configureCompat({ ${"RENDER_FUNCTION" /* RENDER_FUNCTION */}: false })\n` + - `\n (This can also be done per-component via the "compatConfig" option.)`, - link: `https://v3.vuejs.org/guide/migration/render-function-api.html` - }, - ["FILTERS" /* FILTERS */]: { - message: `filters have been removed in Vue 3. ` + - `The "|" symbol will be treated as native JavaScript bitwise OR operator. ` + - `Use method calls or computed properties instead.`, - link: `https://v3.vuejs.org/guide/migration/filters.html` - }, - ["PRIVATE_APIS" /* PRIVATE_APIS */]: { - message: name => `"${name}" is a Vue 2 private API that no longer exists in Vue 3. ` + - `If you are seeing this warning only due to a dependency, you can ` + - `suppress this warning via { PRIVATE_APIS: 'supress-warning' }.` - } - }; - const instanceWarned = Object.create(null); - const warnCount = Object.create(null); - function warnDeprecation(key, instance, ...args) { - instance = instance || getCurrentInstance(); - // check user config - const config = getCompatConfigForKey(key, instance); - if (config === 'suppress-warning') { - return; - } - const dupKey = key + args.join(''); - let compId = instance && formatComponentName(instance, instance.type); - if (compId === 'Anonymous' && instance) { - compId = instance.uid; - } - // skip if the same warning is emitted for the same component type - const componentDupKey = dupKey + compId; - if (componentDupKey in instanceWarned) { - return; - } - instanceWarned[componentDupKey] = true; - // same warning, but different component. skip the long message and just - // log the key and count. - if (dupKey in warnCount) { - warn$1(`(deprecation ${key}) (${++warnCount[dupKey] + 1})`); - return; - } - warnCount[dupKey] = 0; - const { message, link } = deprecationData[key]; - warn$1(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`); - if (!isCompatEnabled(key, instance, true)) { - console.error(`^ The above deprecation's compat behavior is disabled and will likely ` + - `lead to runtime errors.`); - } - } - const globalCompatConfig = { - MODE: 2 - }; - function getCompatConfigForKey(key, instance) { - const instanceConfig = instance && instance.type.compatConfig; - if (instanceConfig && key in instanceConfig) { - return instanceConfig[key]; - } - return globalCompatConfig[key]; - } - function isCompatEnabled(key, instance, enableForBuiltIn = false) { - // skip compat for built-in components - if (!enableForBuiltIn && instance && instance.type.__isBuiltIn) { - return false; - } - const rawMode = getCompatConfigForKey('MODE', instance) || 2; - const val = getCompatConfigForKey(key, instance); - const mode = isFunction(rawMode) - ? rawMode(instance && instance.type) - : rawMode; - if (mode === 2) { - return val !== false; - } - else { - return val === true || val === 'suppress-warning'; - } - } - - function emit(instance, event, ...rawArgs) { + function emit$1(instance, event, ...rawArgs) { const props = instance.vnode.props || EMPTY_OBJ; { const { emitsOptions, propsOptions: [propsOptions] } = instance; @@ -2248,12 +2405,12 @@ var Vue = (function (exports) { function renderComponentRoot(instance) { const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance; let result; + let fallthroughAttrs; const prev = setCurrentRenderingInstance(instance); { 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. @@ -2284,97 +2441,91 @@ var Vue = (function (exports) { ? 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 (true && - result.patchFlag > 0 && - result.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) { - ; - [root, setRoot] = getChildRoot(result); - } - if (fallthroughAttrs && inheritAttrs !== false) { - const keys = Object.keys(fallthroughAttrs); - const { shapeFlag } = root; - if (keys.length) { - if (shapeFlag & (1 /* ELEMENT */ | 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 (true && !accessedAttrs && root.type !== Comment$1) { - 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$1(`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$1(`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.`); - } - } - } - } - if (false && - isCompatEnabled("INSTANCE_ATTRS_CLASS_STYLE" /* INSTANCE_ATTRS_CLASS_STYLE */, instance) && - vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */ && - root.shapeFlag & (1 /* ELEMENT */ | 6 /* COMPONENT */)) ; - // inherit directives - if (vnode.dirs) { - if (true && !isElementRoot(root)) { - warn$1(`Runtime directive used on component with non-element root node. ` + - `The directives will not function as intended.`); - } - root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs; - } - // inherit transition data - if (vnode.transition) { - if (true && !isElementRoot(root)) { - warn$1(`Component inside renders non-element root node ` + - `that cannot be animated.`); - } - root.transition = vnode.transition; - } - if (true && setRoot) { - setRoot(root); - } - else { - result = root; - } } catch (err) { blockStack.length = 0; handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment$1); + result = createVNode(Comment); + } + // 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 (result.patchFlag > 0 && + result.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) { + [root, setRoot] = getChildRoot(result); + } + if (fallthroughAttrs && inheritAttrs !== false) { + const keys = Object.keys(fallthroughAttrs); + const { shapeFlag } = root; + if (keys.length) { + if (shapeFlag & (1 /* ELEMENT */ | 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 (!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$1(`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$1(`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 (!isElementRoot(root)) { + warn$1(`Runtime directive used on component with non-element root node. ` + + `The directives will not function as intended.`); + } + root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs; + } + // inherit transition data + if (vnode.transition) { + if (!isElementRoot(root)) { + warn$1(`Component inside renders non-element root node ` + + `that cannot be animated.`); + } + root.transition = vnode.transition; + } + if (setRoot) { + setRoot(root); + } + else { + result = root; } setCurrentRenderingInstance(prev); return result; @@ -2413,7 +2564,7 @@ var Vue = (function (exports) { const child = children[i]; if (isVNode(child)) { // ignore user comment - if (child.type !== Comment$1 || child.children === 'v-if') { + if (child.type !== Comment || child.children === 'v-if') { if (singleRoot) { // has more than 1 non-comment child, return now return; @@ -2449,7 +2600,7 @@ var Vue = (function (exports) { }; const isElementRoot = (vnode) => { return (vnode.shapeFlag & (6 /* COMPONENT */ | 1 /* ELEMENT */) || - vnode.type === Comment$1 // potential v-if branch switch + vnode.type === Comment // potential v-if branch switch ); }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { @@ -2909,8 +3060,8 @@ var Vue = (function (exports) { function normalizeSuspenseSlot(s) { let block; if (isFunction(s)) { - const isCompiledSlot = s._c; - if (isCompiledSlot) { + const trackBlock = isBlockTreeEnabled && s._c; + if (trackBlock) { // disableTracking: false // allow block tracking for compiled slots // (see ./componentRenderContext.ts) @@ -2918,7 +3069,7 @@ var Vue = (function (exports) { openBlock(); } s = s(); - if (isCompiledSlot) { + if (trackBlock) { s._d = true; block = currentBlock; closeBlock(); @@ -2990,7 +3141,7 @@ var Vue = (function (exports) { if (instance) { // #2400 // to support `app.use` plugins, - // fallback to appContext's `provides` if the intance is at root + // fallback to appContext's `provides` if the instance is at root const provides = instance.parent == null ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides; @@ -3012,6 +3163,255 @@ var Vue = (function (exports) { } } + // Simple effect. + function watchEffect(effect, options) { + return doWatch(effect, null, options); + } + function watchPostEffect(effect, options) { + return doWatch(effect, null, (Object.assign(options || {}, { flush: 'post' }) + )); + } + function watchSyncEffect(effect, options) { + return doWatch(effect, null, (Object.assign(options || {}, { flush: 'sync' }) + )); + } + // initial value for watchers to trigger on undefined initial values + const INITIAL_WATCHER_VALUE = {}; + // implementation + function watch(source, cb, options) { + if (!isFunction(cb)) { + warn$1(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + + `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + + `supports \`watch(source, cb, options?) signature.`); + } + return doWatch(source, cb, options); + } + function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ) { + if (!cb) { + if (immediate !== undefined) { + warn$1(`watch() "immediate" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); + } + if (deep !== undefined) { + warn$1(`watch() "deep" option is only respected when using the ` + + `watch(source, callback, options?) signature.`); + } + } + const warnInvalidSource = (s) => { + warn$1(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + + `a reactive object, or an array of these types.`); + }; + const instance = currentInstance; + let getter; + let forceTrigger = false; + let isMultiSource = false; + if (isRef(source)) { + getter = () => source.value; + forceTrigger = isShallow(source); + } + else if (isReactive(source)) { + getter = () => source; + deep = true; + } + else if (isArray(source)) { + isMultiSource = true; + forceTrigger = source.some(isReactive); + getter = () => source.map(s => { + if (isRef(s)) { + return s.value; + } + else if (isReactive(s)) { + return traverse(s); + } + else if (isFunction(s)) { + return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); + } + else { + warnInvalidSource(s); + } + }); + } + else if (isFunction(source)) { + if (cb) { + // getter with cb + getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); + } + else { + // no cb -> simple effect + getter = () => { + if (instance && instance.isUnmounted) { + return; + } + if (cleanup) { + cleanup(); + } + return callWithAsyncErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onCleanup]); + }; + } + } + else { + getter = NOOP; + warnInvalidSource(source); + } + if (cb && deep) { + const baseGetter = getter; + getter = () => traverse(baseGetter()); + } + let cleanup; + let onCleanup = (fn) => { + cleanup = effect.onStop = () => { + callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); + }; + }; + let oldValue = isMultiSource ? [] : INITIAL_WATCHER_VALUE; + const job = () => { + if (!effect.active) { + return; + } + if (cb) { + // watch(source, cb) + const newValue = effect.run(); + if (deep || + forceTrigger || + (isMultiSource + ? newValue.some((v, i) => hasChanged(v, oldValue[i])) + : hasChanged(newValue, oldValue)) || + (false )) { + // cleanup before running cb again + if (cleanup) { + cleanup(); + } + callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ + newValue, + // pass undefined as the old value when it's changed for the first time + oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, + onCleanup + ]); + oldValue = newValue; + } + } + else { + // watchEffect + effect.run(); + } + }; + // important: mark the job as a watcher callback so that scheduler knows + // it is allowed to self-trigger (#1727) + job.allowRecurse = !!cb; + let scheduler; + if (flush === 'sync') { + scheduler = job; // the scheduler function gets called directly + } + else if (flush === 'post') { + scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); + } + else { + // default: 'pre' + scheduler = () => { + if (!instance || instance.isMounted) { + queuePreFlushCb(job); + } + else { + // with 'pre' option, the first call must happen before + // the component is mounted so it is called synchronously. + job(); + } + }; + } + const effect = new ReactiveEffect(getter, scheduler); + { + effect.onTrack = onTrack; + effect.onTrigger = onTrigger; + } + // initial run + if (cb) { + if (immediate) { + job(); + } + else { + oldValue = effect.run(); + } + } + else if (flush === 'post') { + queuePostRenderEffect(effect.run.bind(effect), instance && instance.suspense); + } + else { + effect.run(); + } + return () => { + effect.stop(); + if (instance && instance.scope) { + remove(instance.scope.effects, effect); + } + }; + } + // this.$watch + function instanceWatch(source, value, options) { + const publicThis = this.proxy; + const getter = isString(source) + ? source.includes('.') + ? createPathGetter(publicThis, source) + : () => publicThis[source] + : source.bind(publicThis, publicThis); + let cb; + if (isFunction(value)) { + cb = value; + } + else { + cb = value.handler; + options = value; + } + const cur = currentInstance; + setCurrentInstance(this); + const res = doWatch(getter, cb.bind(publicThis), options); + if (cur) { + setCurrentInstance(cur); + } + else { + unsetCurrentInstance(); + } + return res; + } + function createPathGetter(ctx, path) { + const segments = path.split('.'); + return () => { + let cur = ctx; + for (let i = 0; i < segments.length && cur; i++) { + cur = cur[segments[i]]; + } + return cur; + }; + } + function traverse(value, seen) { + if (!isObject(value) || value["__v_skip" /* SKIP */]) { + return value; + } + seen = seen || new Set(); + if (seen.has(value)) { + return value; + } + seen.add(value); + if (isRef(value)) { + traverse(value.value, seen); + } + else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + traverse(value[i], seen); + } + } + else if (isSet(value) || isMap(value)) { + value.forEach((v) => { + traverse(v, seen); + }); + } + else if (isPlainObject(value)) { + for (const key in value) { + traverse(value[key], seen); + } + } + return value; + } + function useTransitionState() { const state = { isMounted: false, @@ -3069,7 +3469,8 @@ var Vue = (function (exports) { const rawProps = toRaw(props); const { mode } = rawProps; // check mode - if (mode && !['in-out', 'out-in', 'default'].includes(mode)) { + if (mode && + mode !== 'in-out' && mode !== 'out-in' && mode !== 'default') { warn$1(`invalid mode: ${mode}`); } // at this point children has a guaranteed length of 1. @@ -3101,7 +3502,7 @@ var Vue = (function (exports) { } // handle mode if (oldInnerChild && - oldInnerChild.type !== Comment$1 && + oldInnerChild.type !== Comment && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { const leavingHooks = resolveTransitionHooks(oldInnerChild, rawProps, state, instance); // update old tree's hooks in case of dynamic transition @@ -3116,7 +3517,7 @@ var Vue = (function (exports) { }; return emptyPlaceholder(child); } - else if (mode === 'in-out' && innerChild.type !== Comment$1) { + else if (mode === 'in-out' && innerChild.type !== Comment) { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType(state, oldInnerChild); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; @@ -3308,7 +3709,7 @@ var Vue = (function (exports) { ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if - else if (keepComment || child.type !== Comment$1) { + else if (keepComment || child.type !== Comment) { ret.push(child); } } @@ -3542,7 +3943,7 @@ var Vue = (function (exports) { function unmount(vnode) { // reset the shapeFlag so it can be properly unmounted resetShapeFlag(vnode); - _unmount(vnode, instance, parentSuspense); + _unmount(vnode, instance, parentSuspense, true); } function pruneCache(filter) { cache.forEach((vnode, key) => { @@ -3681,7 +4082,7 @@ var Vue = (function (exports) { return pattern.some((p) => matches(p, name)); } else if (isString(pattern)) { - return pattern.split(',').indexOf(name) > -1; + return pattern.split(',').includes(name); } else if (pattern.test) { return pattern.test(name); @@ -3709,7 +4110,7 @@ var Vue = (function (exports) { } current = current.parent; } - hook(); + return hook(); }); injectHook(type, wrappedHook, target); // In addition to registering it on the target instance, we walk up the parent @@ -3934,7 +4335,7 @@ var Vue = (function (exports) { warn$1(`Write operation failed: computed property "${key}" is readonly.`); } ; - const c = computed({ + const c = computed$1({ get, set }); @@ -4165,7 +4566,9 @@ var Vue = (function (exports) { beforeUpdate: mergeAsArray, updated: mergeAsArray, beforeDestroy: mergeAsArray, + beforeUnmount: mergeAsArray, destroyed: mergeAsArray, + unmounted: mergeAsArray, activated: mergeAsArray, deactivated: mergeAsArray, errorCaptured: mergeAsArray, @@ -4331,7 +4734,9 @@ var Vue = (function (exports) { // 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)) { + if (!rawProps || + (!hasOwn(rawProps, key) && + (!false ))) { delete attrs[key]; hasAttrsChanged = true; } @@ -4369,7 +4774,7 @@ var Vue = (function (exports) { } } else if (!isEmitListener(instance.emitsOptions, key)) { - if (value !== attrs[key]) { + if (!(key in attrs) || value !== attrs[key]) { attrs[key] = value; hasAttrsChanged = true; } @@ -4781,7 +5186,7 @@ var Vue = (function (exports) { [bar, this.y] ]) */ - const isBuiltInDirective = /*#__PURE__*/ makeMap('bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text'); + const isBuiltInDirective = /*#__PURE__*/ makeMap('bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo'); function validateDirectiveName(name) { if (isBuiltInDirective(name)) { warn$1('Do not use built-in directive ids as custom directive id: ' + name); @@ -4972,7 +5377,7 @@ var Vue = (function (exports) { app._instance = vnode.component; devtoolsInitApp(app, version); } - return vnode.component.proxy; + return getExposeProxy(vnode.component) || vnode.component.proxy; } else { warn$1(`App has already been mounted.\n` + @@ -5009,6 +5414,102 @@ var Vue = (function (exports) { }; } + /** + * Function for handling a template ref + */ + function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) { + if (isArray(rawRef)) { + rawRef.forEach((r, i) => setRef(r, oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef), parentSuspense, vnode, isUnmount)); + return; + } + if (isAsyncWrapper(vnode) && !isUnmount) { + // when mounting async components, nothing needs to be done, + // because the template ref is forwarded to inner component + return; + } + const refValue = vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */ + ? getExposeProxy(vnode.component) || vnode.component.proxy + : vnode.el; + const value = isUnmount ? null : refValue; + const { i: owner, r: ref } = rawRef; + if (!owner) { + warn$1(`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.r; + const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs; + const setupState = owner.setupState; + // dynamic ref changed. 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 (isFunction(ref)) { + callWithErrorHandling(ref, owner, 12 /* FUNCTION_REF */, [value, refs]); + } + else { + const _isString = isString(ref); + const _isRef = isRef(ref); + if (_isString || _isRef) { + const doSet = () => { + if (rawRef.f) { + const existing = _isString ? refs[ref] : ref.value; + if (isUnmount) { + isArray(existing) && remove(existing, refValue); + } + else { + if (!isArray(existing)) { + if (_isString) { + refs[ref] = [refValue]; + } + else { + ref.value = [refValue]; + if (rawRef.k) + refs[rawRef.k] = ref.value; + } + } + else if (!existing.includes(refValue)) { + existing.push(refValue); + } + } + } + else if (_isString) { + refs[ref] = value; + if (hasOwn(setupState, ref)) { + setupState[ref] = value; + } + } + else if (isRef(ref)) { + ref.value = value; + if (rawRef.k) + refs[rawRef.k] = value; + } + else { + warn$1('Invalid template ref type:', ref, `(${typeof ref})`); + } + }; + if (value) { + doSet.id = -1; + queuePostRenderEffect(doSet, parentSuspense); + } + else { + doSet(); + } + } + else { + warn$1('Invalid template ref type:', ref, `(${typeof ref})`); + } + } + } + let hasMismatch = false; const isSVGContainer = (container) => /svg/.test(container.namespaceURI) && container.tagName !== 'foreignObject'; const isComment = (node) => node.nodeType === 8 /* COMMENT */; @@ -5058,7 +5559,7 @@ var Vue = (function (exports) { nextNode = nextSibling(node); } break; - case Comment$1: + case Comment: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } @@ -5178,14 +5679,14 @@ var Vue = (function (exports) { for (const key in props) { if ((forcePatchValue && key.endsWith('value')) || (isOn(key) && !isReservedProp(key))) { - patchProp(el, key, null, props[key]); + patchProp(el, key, null, props[key], false, undefined, parentComponent); } } } else if (props.onClick) { // Fast path for click listeners (which is most often) to avoid // iterating through props. - patchProp(el, 'onClick', null, props.onClick); + patchProp(el, 'onClick', null, props.onClick, false, undefined, parentComponent); } } // vnode / directive hooks @@ -5331,6 +5832,7 @@ var Vue = (function (exports) { return [hydrate, hydrateNode]; } + /* eslint-disable no-restricted-globals */ let supported; let perf; function startMeasure(instance, type) { @@ -5358,7 +5860,6 @@ var Vue = (function (exports) { if (supported !== undefined) { return supported; } - /* eslint-disable no-restricted-globals */ if (typeof window !== 'undefined' && window.performance) { supported = true; perf = window.performance; @@ -5366,7 +5867,6 @@ var Vue = (function (exports) { else { supported = false; } - /* eslint-enable no-restricted-globals */ return supported; } @@ -5398,10 +5898,10 @@ var Vue = (function (exports) { } // implementation function baseCreateRenderer(options, createHydrationFns) { + const target = getGlobalThis(); + target.__VUE__ = true; { - const target = getGlobalThis(); - target.__VUE__ = true; - setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__); + setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target); } const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, 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 = () => {}` @@ -5425,7 +5925,7 @@ var Vue = (function (exports) { case Text: processText(n1, n2, container, anchor); break; - case Comment$1: + case Comment: processCommentNode(n1, n2, container, anchor); break; case Static: @@ -5482,7 +5982,7 @@ var Vue = (function (exports) { } }; const mountStaticNode = (n2, container, anchor, isSVG) => { - [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG); + [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG, n2.el, n2.anchor); }; /** * Dev / HMR only @@ -5641,12 +6141,15 @@ var Vue = (function (exports) { const oldProps = n1.props || EMPTY_OBJ; const newProps = n2.props || EMPTY_OBJ; let vnodeHook; + // disable recurse in beforeUpdate hooks + parentComponent && toggleRecurse(parentComponent, false); if ((vnodeHook = newProps.onVnodeBeforeUpdate)) { invokeVNodeHook(vnodeHook, parentComponent, n2, n1); } if (dirs) { invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate'); } + parentComponent && toggleRecurse(parentComponent, true); if (isHmrUpdating) { // HMR updated, force full diff patchFlag = 0; @@ -5875,7 +6378,7 @@ var Vue = (function (exports) { // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { - const placeholder = (instance.subTree = createVNode(Comment$1)); + const placeholder = (instance.subTree = createVNode(Comment)); processCommentNode(null, placeholder, container, anchor); } return; @@ -5926,7 +6429,7 @@ var Vue = (function (exports) { const { el, props } = initialVNode; const { bm, m, parent } = instance; const isAsyncWrapperVNode = isAsyncWrapper(initialVNode); - effect.allowRecurse = false; + toggleRecurse(instance, false); // beforeMount hook if (bm) { invokeArrayFns(bm); @@ -5936,7 +6439,7 @@ var Vue = (function (exports) { (vnodeHook = props && props.onVnodeBeforeMount)) { invokeVNodeHook(vnodeHook, parent, initialVNode); } - effect.allowRecurse = true; + toggleRecurse(instance, true); if (el && hydrateNode) { // vnode has adopted host node - perform hydration instead of mount. const hydrateSubTree = () => { @@ -6018,7 +6521,7 @@ var Vue = (function (exports) { pushWarningContext(next || instance.vnode); } // Disallow component effect recursion during pre-lifecycle hooks. - effect.allowRecurse = false; + toggleRecurse(instance, false); if (next) { next.el = vnode.el; updateComponentPreRender(instance, next, optimized); @@ -6034,7 +6537,7 @@ var Vue = (function (exports) { if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) { invokeVNodeHook(vnodeHook, parent, next, vnode); } - effect.allowRecurse = true; + toggleRecurse(instance, true); // render { startMeasure(instance, `render`); @@ -6080,13 +6583,13 @@ var Vue = (function (exports) { } }; // create reactive effect for rendering - const effect = new ReactiveEffect(componentUpdateFn, () => queueJob(instance.update), instance.scope // track it in component's effect scope - ); + const effect = (instance.effect = new ReactiveEffect(componentUpdateFn, () => queueJob(instance.update), instance.scope // track it in component's effect scope + )); const update = (instance.update = effect.run.bind(effect)); update.id = instance.uid; // allowRecurse // #1801, #2043 component render effects should allow recursive updates - effect.allowRecurse = update.allowRecurse = true; + toggleRecurse(instance, true); { effect.onTrack = instance.rtc ? e => invokeArrayFns(instance.rtc, e) @@ -6610,85 +7113,8 @@ var Vue = (function (exports) { createApp: createAppAPI(render, hydrate) }; } - function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) { - if (isArray(rawRef)) { - rawRef.forEach((r, i) => setRef(r, oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef), parentSuspense, vnode, isUnmount)); - return; - } - if (isAsyncWrapper(vnode) && !isUnmount) { - // when mounting async components, nothing needs to be done, - // because the template ref is forwarded to inner component - return; - } - const refValue = vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */ - ? getExposeProxy(vnode.component) || vnode.component.proxy - : vnode.el; - const value = isUnmount ? null : refValue; - const { i: owner, r: ref } = rawRef; - if (!owner) { - warn$1(`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.r; - const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs; - const setupState = owner.setupState; - // dynamic ref changed. 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, owner, 12 /* FUNCTION_REF */, [value, refs]); - } - else { - warn$1('Invalid template ref type:', value, `(${typeof value})`); - } - } - function invokeVNodeHook(hook, instance, vnode, prevVNode = null) { - callWithAsyncErrorHandling(hook, instance, 7 /* VNODE_HOOK */, [ - vnode, - prevVNode - ]); + function toggleRecurse({ effect, update }, allowed) { + effect.allowRecurse = update.allowRecurse = allowed; } /** * #1156 @@ -6698,8 +7124,8 @@ var Vue = (function (exports) { * * #2080 * Inside keyed `template` fragment static children, if a fragment is moved, - * the children will always moved so that need inherit el form previous nodes - * to ensure correct moved position. + * the children will always be moved. Therefore, in order to ensure correct move + * position, el should be inherited from previous nodes. */ function traverseStaticChildren(n1, n2, shallow = false) { const ch1 = n1.children; @@ -6720,7 +7146,7 @@ var Vue = (function (exports) { } // also inherit for comment nodes, but not placeholders (e.g. v-if which // would have received .el during block patch) - if (c2.type === Comment$1 && !c2.el) { + if (c2.type === Comment && !c2.el) { c2.el = c1.el; } } @@ -7012,7 +7438,11 @@ var Vue = (function (exports) { return Component; } if (warnMissing && !res) { - warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + const extra = type === COMPONENTS + ? `\nIf this is a native custom element, make sure to exclude it from ` + + `component resolution via compilerOptions.isCustomElement.` + : ``; + warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`); } return res; } @@ -7030,7 +7460,7 @@ var Vue = (function (exports) { const Fragment = Symbol('Fragment' ); const Text = Symbol('Text' ); - const Comment$1 = Symbol('Comment' ); + const Comment = Symbol('Comment' ); const Static = Symbol('Static' ); // 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 @@ -7143,10 +7573,10 @@ var Vue = (function (exports) { }; const InternalObjectKey = `__vInternal`; const normalizeKey = ({ key }) => key != null ? key : null; - const normalizeRef = ({ ref }) => { + const normalizeRef = ({ ref, ref_key, ref_for }) => { return (ref != null ? isString(ref) || isRef(ref) || isFunction(ref) - ? { i: currentRenderingInstance, r: ref } + ? { i: currentRenderingInstance, r: ref, k: ref_key, f: !!ref_for } : ref : null); }; @@ -7220,7 +7650,7 @@ var Vue = (function (exports) { if (!type) { warn$1(`Invalid vnode type when creating vnode: ${type}.`); } - type = Comment$1; + type = Comment; } if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like @@ -7313,7 +7743,7 @@ var Vue = (function (exports) { 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 + // note: preserve flag for fragments since they use the flag for children // fast paths only. patchFlag: extraProps && vnode.type !== Fragment ? patchFlag === -1 // hoisted node @@ -7373,13 +7803,13 @@ var Vue = (function (exports) { // block to ensure correct updates. asBlock = false) { return asBlock - ? (openBlock(), createBlock(Comment$1, null, text)) - : createVNode(Comment$1, null, text); + ? (openBlock(), createBlock(Comment, null, text)) + : createVNode(Comment, null, text); } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder - return createVNode(Comment$1); + return createVNode(Comment); } else if (isArray(child)) { // fragment @@ -7475,7 +7905,9 @@ var Vue = (function (exports) { else if (isOn(key)) { const existing = ret[key]; const incoming = toMerge[key]; - if (existing !== incoming) { + if (incoming && + existing !== incoming && + !(isArray(existing) && existing.includes(incoming))) { ret[key] = existing ? [].concat(existing, incoming) : incoming; @@ -7487,6 +7919,12 @@ var Vue = (function (exports) { } } return ret; + } + function invokeVNodeHook(hook, instance, vnode, prevVNode = null) { + callWithAsyncErrorHandling(hook, instance, 7 /* VNODE_HOOK */, [ + vnode, + prevVNode + ]); } /** @@ -7596,7 +8034,7 @@ var Vue = (function (exports) { return vnodes.some(child => { if (!isVNode(child)) return true; - if (child.type === Comment$1) + if (child.type === Comment) return false; if (child.type === Fragment && !ensureValidVNode(child.children)) @@ -7678,23 +8116,23 @@ var Vue = (function (exports) { const n = accessCache[key]; if (n !== undefined) { switch (n) { - case 0 /* SETUP */: + case 1 /* SETUP */: return setupState[key]; - case 1 /* DATA */: + case 2 /* DATA */: return data[key]; - case 3 /* CONTEXT */: + case 4 /* CONTEXT */: return ctx[key]; - case 2 /* PROPS */: + case 3 /* PROPS */: return props[key]; // default: just fallthrough } } else if (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) { - accessCache[key] = 0 /* SETUP */; + accessCache[key] = 1 /* SETUP */; return setupState[key]; } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { - accessCache[key] = 1 /* DATA */; + accessCache[key] = 2 /* DATA */; return data[key]; } else if ( @@ -7702,15 +8140,15 @@ var Vue = (function (exports) { // props (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key)) { - accessCache[key] = 2 /* PROPS */; + accessCache[key] = 3 /* PROPS */; return props[key]; } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { - accessCache[key] = 3 /* CONTEXT */; + accessCache[key] = 4 /* CONTEXT */; return ctx[key]; } else if (shouldCacheAccess) { - accessCache[key] = 4 /* OTHER */; + accessCache[key] = 0 /* OTHER */; } } const publicGetter = publicPropertiesMap[key]; @@ -7731,7 +8169,7 @@ var Vue = (function (exports) { } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { // user may set custom properties to `this` that start with `$` - accessCache[key] = 3 /* CONTEXT */; + accessCache[key] = 4 /* CONTEXT */; return ctx[key]; } else if ( @@ -7792,7 +8230,7 @@ var Vue = (function (exports) { }, has({ _: { data, setupState, accessCache, ctx, appContext, propsOptions } }, key) { let normalizedProps; - return (accessCache[key] !== undefined || + return (!!accessCache[key] || (data !== EMPTY_OBJ && hasOwn(data, key)) || (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) || ((normalizedProps = propsOptions[0]) && hasOwn(normalizedProps, key)) || @@ -7867,17 +8305,19 @@ var Vue = (function (exports) { function exposeSetupStateOnRenderContext(instance) { const { ctx, setupState } = instance; Object.keys(toRaw(setupState)).forEach(key => { - if (!setupState.__isScriptSetup && (key[0] === '$' || key[0] === '_')) { - warn$1(`setup() return property ${JSON.stringify(key)} should not start with "$" or "_" ` + - `which are reserved prefixes for Vue internals.`); - return; + if (!setupState.__isScriptSetup) { + if (key[0] === '$' || key[0] === '_') { + warn$1(`setup() return property ${JSON.stringify(key)} should not start with "$" or "_" ` + + `which are reserved prefixes for Vue internals.`); + return; + } + Object.defineProperty(ctx, key, { + enumerable: true, + configurable: true, + get: () => setupState[key], + set: NOOP + }); } - Object.defineProperty(ctx, key, { - enumerable: true, - configurable: true, - get: () => setupState[key], - set: NOOP - }); }); } @@ -7896,6 +8336,7 @@ var Vue = (function (exports) { root: null, next: null, subTree: null, + effect: null, update: null, scope: new EffectScope(true /* detached */), render: null, @@ -7957,7 +8398,7 @@ var Vue = (function (exports) { instance.ctx = createDevRenderContext(instance); } instance.root = parent ? parent.root : instance; - instance.emit = emit.bind(null, instance); + instance.emit = emit$1.bind(null, instance); // apply custom element special handling if (vnode.ce) { vnode.ce(instance); @@ -8111,9 +8552,11 @@ var Vue = (function (exports) { function finishComponentSetup(instance, isSSR, skipOptions) { const Component = instance.type; // template / render function normalization + // could be already set when returned from setup() if (!instance.render) { - // could be set from setup() - if (compile && !Component.render) { + // only do on-the-fly compile if not in SSR - SSR on-the-fly compilation + // is done by server-renderer + if (!isSSR && compile && !Component.render) { const template = Component.template; if (template) { { @@ -8255,669 +8698,10 @@ var Vue = (function (exports) { return isFunction(value) && '__vccOpts' in value; } - const stack = []; - function pushWarningContext(vnode) { - stack.push(vnode); - } - function popWarningContext() { - stack.pop(); - } - function warn$1(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 = { - ["sp" /* SERVER_PREFETCH */]: 'serverPrefetch hook', - ["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, throwInDev = true) { - 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 = ErrorTypeStrings[type] ; - while (cur) { - const errorCapturedHooks = cur.ec; - if (errorCapturedHooks) { - for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { - 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, throwInDev); - } - function logError(err, type, contextVNode, throwInDev = true) { - { - const info = ErrorTypeStrings[type]; - if (contextVNode) { - pushWarningContext(contextVNode); - } - warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`); - if (contextVNode) { - popWarningContext(); - } - // crash in dev by default so it's more noticeable - if (throwInDev) { - throw err; - } - else { - 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(this ? fn.bind(this) : fn) : p; - } - // #2768 - // Use binary-search to find a suitable position in the queue, - // so that the queue maintains the increasing order of job's id, - // which can prevent the job from being skipped and also can avoid repeated patching. - function findInsertionIndex(id) { - // the start index should be `flushIndex + 1` - let start = flushIndex + 1; - let end = queue.length; - while (start < end) { - const middle = (start + end) >>> 1; - const middleJobId = getId(queue[middle]); - middleJobId < id ? (start = middle + 1) : (end = middle); - } - return start; - } - 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) { - if (job.id == null) { - queue.push(job); - } - else { - queue.splice(findInsertionIndex(job.id), 0, job); - } - queueFlush(); - } - } - function queueFlush() { - if (!isFlushing && !isFlushPending) { - isFlushPending = true; - currentFlushPromise = resolvedPromise.then(flushJobs); - } - } - function invalidateJob(job) { - const i = queue.indexOf(job); - if (i > flushIndex) { - queue.splice(i, 1); - } - } - 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; - { - seen = seen || new Map(); - } - for (preFlushIndex = 0; preFlushIndex < activePreFlushCbs.length; preFlushIndex++) { - if (checkRecursiveUpdates(seen, activePreFlushCbs[preFlushIndex])) { - continue; - } - 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; - { - seen = seen || new Map(); - } - activePostFlushCbs.sort((a, b) => getId(a) - getId(b)); - for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) { - if (checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex])) { - continue; - } - activePostFlushCbs[postFlushIndex](); - } - activePostFlushCbs = null; - postFlushIndex = 0; - } - } - const getId = (job) => job.id == null ? Infinity : job.id; - function flushJobs(seen) { - isFlushPending = false; - isFlushing = true; - { - 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. - queue.sort((a, b) => getId(a) - getId(b)); - try { - for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { - const job = queue[flushIndex]; - if (job && job.active !== false) { - if (true && checkRecursiveUpdates(seen, job)) { - continue; - } - // console.log(`running:`, job.id) - 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 || - pendingPreFlushCbs.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) { - const instance = fn.ownerInstance; - const componentName = instance && getComponentName(instance.type); - warn$1(`Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. ` + - `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.`); - return true; - } - else { - seen.set(fn, count + 1); - } - } - } - - // Simple effect. - function watchEffect(effect, options) { - return doWatch(effect, null, options); - } - function watchPostEffect(effect, options) { - return doWatch(effect, null, (Object.assign(options || {}, { flush: 'post' }) - )); - } - function watchSyncEffect(effect, options) { - return doWatch(effect, null, (Object.assign(options || {}, { flush: 'sync' }) - )); - } - // initial value for watchers to trigger on undefined initial values - const INITIAL_WATCHER_VALUE = {}; - // implementation - function watch(source, cb, options) { - if (!isFunction(cb)) { - warn$1(`\`watch(fn, options?)\` signature has been moved to a separate API. ` + - `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` + - `supports \`watch(source, cb, options?) signature.`); - } - return doWatch(source, cb, options); - } - function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EMPTY_OBJ) { - if (!cb) { - if (immediate !== undefined) { - warn$1(`watch() "immediate" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); - } - if (deep !== undefined) { - warn$1(`watch() "deep" option is only respected when using the ` + - `watch(source, callback, options?) signature.`); - } - } - const warnInvalidSource = (s) => { - warn$1(`Invalid watch source: `, s, `A watch source can only be a getter/effect function, a ref, ` + - `a reactive object, or an array of these types.`); - }; - const instance = currentInstance; - let getter; - let forceTrigger = false; - let isMultiSource = false; - if (isRef(source)) { - getter = () => source.value; - forceTrigger = !!source._shallow; - } - else if (isReactive(source)) { - getter = () => source; - deep = true; - } - else if (isArray(source)) { - isMultiSource = true; - forceTrigger = source.some(isReactive); - getter = () => source.map(s => { - if (isRef(s)) { - return s.value; - } - else if (isReactive(s)) { - return traverse(s); - } - else if (isFunction(s)) { - return callWithErrorHandling(s, instance, 2 /* WATCH_GETTER */); - } - else { - warnInvalidSource(s); - } - }); - } - else if (isFunction(source)) { - if (cb) { - // getter with cb - getter = () => callWithErrorHandling(source, instance, 2 /* WATCH_GETTER */); - } - else { - // no cb -> simple effect - getter = () => { - if (instance && instance.isUnmounted) { - return; - } - if (cleanup) { - cleanup(); - } - return callWithAsyncErrorHandling(source, instance, 3 /* WATCH_CALLBACK */, [onInvalidate]); - }; - } - } - else { - getter = NOOP; - warnInvalidSource(source); - } - if (cb && deep) { - const baseGetter = getter; - getter = () => traverse(baseGetter()); - } - let cleanup; - let onInvalidate = (fn) => { - cleanup = effect.onStop = () => { - callWithErrorHandling(fn, instance, 4 /* WATCH_CLEANUP */); - }; - }; - let oldValue = isMultiSource ? [] : INITIAL_WATCHER_VALUE; - const job = () => { - if (!effect.active) { - return; - } - if (cb) { - // watch(source, cb) - const newValue = effect.run(); - if (deep || - forceTrigger || - (isMultiSource - ? newValue.some((v, i) => hasChanged(v, oldValue[i])) - : hasChanged(newValue, oldValue)) || - (false )) { - // cleanup before running cb again - if (cleanup) { - cleanup(); - } - callWithAsyncErrorHandling(cb, instance, 3 /* WATCH_CALLBACK */, [ - newValue, - // pass undefined as the old value when it's changed for the first time - oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue, - onInvalidate - ]); - oldValue = newValue; - } - } - else { - // watchEffect - effect.run(); - } - }; - // important: mark the job as a watcher callback so that scheduler knows - // it is allowed to self-trigger (#1727) - job.allowRecurse = !!cb; - let scheduler; - if (flush === 'sync') { - scheduler = job; // the scheduler function gets called directly - } - else if (flush === 'post') { - scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); - } - else { - // default: 'pre' - scheduler = () => { - if (!instance || instance.isMounted) { - queuePreFlushCb(job); - } - else { - // with 'pre' option, the first call must happen before - // the component is mounted so it is called synchronously. - job(); - } - }; - } - const effect = new ReactiveEffect(getter, scheduler); - { - effect.onTrack = onTrack; - effect.onTrigger = onTrigger; - } - // initial run - if (cb) { - if (immediate) { - job(); - } - else { - oldValue = effect.run(); - } - } - else if (flush === 'post') { - queuePostRenderEffect(effect.run.bind(effect), instance && instance.suspense); - } - else { - effect.run(); - } - return () => { - effect.stop(); - if (instance && instance.scope) { - remove(instance.scope.effects, effect); - } - }; - } - // this.$watch - function instanceWatch(source, value, options) { - const publicThis = this.proxy; - const getter = isString(source) - ? source.includes('.') - ? createPathGetter(publicThis, source) - : () => publicThis[source] - : source.bind(publicThis, publicThis); - let cb; - if (isFunction(value)) { - cb = value; - } - else { - cb = value.handler; - options = value; - } - const cur = currentInstance; - setCurrentInstance(this); - const res = doWatch(getter, cb.bind(publicThis), options); - if (cur) { - setCurrentInstance(cur); - } - else { - unsetCurrentInstance(); - } - return res; - } - function createPathGetter(ctx, path) { - const segments = path.split('.'); - return () => { - let cur = ctx; - for (let i = 0; i < segments.length && cur; i++) { - cur = cur[segments[i]]; - } - return cur; - }; - } - function traverse(value, seen = new Set()) { - if (!isObject(value) || value["__v_skip" /* SKIP */]) { - return value; - } - seen = seen || new Set(); - if (seen.has(value)) { - return value; - } - seen.add(value); - if (isRef(value)) { - traverse(value.value, seen); - } - else if (isArray(value)) { - for (let i = 0; i < value.length; i++) { - traverse(value[i], seen); - } - } - else if (isSet(value) || isMap(value)) { - value.forEach((v) => { - traverse(v, seen); - }); - } - else if (isPlainObject(value)) { - for (const key in value) { - traverse(value[key], seen); - } - } - return value; - } + const computed$1 = ((getterOrOptions, debugOptions) => { + // @ts-ignore + return computed(getterOrOptions, debugOptions, isInSSRComponentSetup); + }); // dev only const warnRuntimeUsage = (method) => warn$1(`${method}() is a compiler-hint helper that is only usable inside ` + @@ -8942,7 +8726,7 @@ var Vue = (function (exports) { * instance properties when it is accessed by a parent component via template * refs. * - * `