From 9f5545e6f45b626e771e6107ad0234af684abd3a Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Thu, 3 Jun 2021 14:29:50 +0800 Subject: [PATCH] build(deps): bump vue from 3.1.0-beta.5 to 3.1.0-beta.7 --- packages/uni-h5-vue/dist/vue.runtime.cjs.js | 732 ++++++++------- .../uni-h5-vue/dist/vue.runtime.compat.cjs.js | 859 ++++++++--------- .../uni-h5-vue/dist/vue.runtime.compat.esm.js | 863 +++++++++--------- packages/uni-h5-vue/dist/vue.runtime.esm.js | 735 ++++++++------- 4 files changed, 1678 insertions(+), 1511 deletions(-) diff --git a/packages/uni-h5-vue/dist/vue.runtime.cjs.js b/packages/uni-h5-vue/dist/vue.runtime.cjs.js index 8fe56053c..1a7e1b55b 100644 --- a/packages/uni-h5-vue/dist/vue.runtime.cjs.js +++ b/packages/uni-h5-vue/dist/vue.runtime.cjs.js @@ -35,7 +35,7 @@ let uid = 0; function createReactiveEffect(fn, options) { const effect = function reactiveEffect() { if (!effect.active) { - return options.scheduler ? undefined : fn(); + return fn(); } if (!effectStack.includes(effect)) { cleanup(effect); @@ -1261,7 +1261,7 @@ function flushJobs(seen) { try { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex]; - if (job) { + if (job && job.active !== false) { if (true && checkRecursiveUpdates(seen, job)) { continue; } @@ -1443,7 +1443,7 @@ function devtoolsInitApp(app, version) { exports.devtools.emit("app:init" /* APP_INIT */, app, version, { Fragment, Text, - Comment, + Comment: Comment$1, Static }); } @@ -1773,7 +1773,7 @@ function warnDeprecation(key, instance, ...args) { warnCount[dupKey] = 0; const { message, link } = deprecationData[key]; warn(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`); - if (!isCompatEnabled(key, instance)) { + if (!isCompatEnabled(key, instance, true)) { console.error(`^ The above deprecation's compat behavior is disabled and will likely ` + `lead to runtime errors.`); } @@ -1880,8 +1880,10 @@ function emit(instance, event, ...rawArgs) { } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__emits !== undefined) { - return comp.__emits; + const cache = appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== undefined) { + return cached; } const raw = comp.emits; let normalized = {}; @@ -1906,7 +1908,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__emits = null); + cache.set(comp, null); + return null; } if (shared.isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1914,7 +1917,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { shared.extend(normalized, raw); } - return (comp.__emits = normalized); + cache.set(comp, normalized); + return normalized; } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -2024,7 +2028,7 @@ function markAttrsAccessed() { accessedAttrs = true; } function renderComponentRoot(instance) { - const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx } = instance; + const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance; let result; const prev = setCurrentRenderingInstance(instance); { @@ -2073,7 +2077,7 @@ function renderComponentRoot(instance) { ; [root, setRoot] = getChildRoot(result); } - if (fallthroughAttrs && Component.inheritAttrs !== false) { + if (fallthroughAttrs && inheritAttrs !== false) { const keys = Object.keys(fallthroughAttrs); const { shapeFlag } = root; if (keys.length) { @@ -2088,7 +2092,7 @@ function renderComponentRoot(instance) { } root = cloneVNode(root, fallthroughAttrs); } - else if (true && !accessedAttrs && root.type !== Comment) { + else if (true && !accessedAttrs && root.type !== Comment$1) { const allAttrs = Object.keys(attrs); const eventAttrs = []; const extraAttrs = []; @@ -2154,7 +2158,7 @@ function renderComponentRoot(instance) { catch (err) { blockStack.length = 0; handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment); + result = createVNode(Comment$1); } setCurrentRenderingInstance(prev); return result; @@ -2193,7 +2197,7 @@ function filterSingleRoot(children) { const child = children[i]; if (isVNode(child)) { // ignore user comment - if (child.type !== Comment || child.children === 'v-if') { + if (child.type !== Comment$1 || child.children === 'v-if') { if (singleRoot) { // has more than 1 non-comment child, return now return; @@ -2230,7 +2234,7 @@ const filterModelListeners = (attrs, props) => { const isElementRoot = (vnode) => { return (vnode.shapeFlag & 6 /* COMPONENT */ || vnode.shapeFlag & 1 /* ELEMENT */ || - vnode.type === Comment // potential v-if branch switch + vnode.type === Comment$1 // potential v-if branch switch ); }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { @@ -2336,7 +2340,8 @@ const SuspenseImpl = { } }, hydrate: hydrateSuspense, - create: createSuspenseBoundary + create: createSuspenseBoundary, + normalize: normalizeSuspenseChildren }; // Force-casted public typing for h and TSX props inference const Suspense = (SuspenseImpl @@ -2681,24 +2686,29 @@ function hydrateSuspense(node, vnode, parentComponent, parentSuspense, isSVG, sl } function normalizeSuspenseChildren(vnode) { const { shapeFlag, children } = vnode; - let content; - let fallback; - if (shapeFlag & 32 /* SLOTS_CHILDREN */) { - content = normalizeSuspenseSlot(children.default); - fallback = normalizeSuspenseSlot(children.fallback); - } - else { - content = normalizeSuspenseSlot(children); - fallback = normalizeVNode(null); - } - return { - content, - fallback - }; + const isSlotChildren = shapeFlag & 32 /* SLOTS_CHILDREN */; + vnode.ssContent = normalizeSuspenseSlot(isSlotChildren ? children.default : children); + vnode.ssFallback = isSlotChildren + ? normalizeSuspenseSlot(children.fallback) + : createVNode(Comment); } function normalizeSuspenseSlot(s) { + let block; if (shared.isFunction(s)) { + const isCompiledSlot = s._c; + if (isCompiledSlot) { + // disableTracking: false + // allow block tracking for compiled slots + // (see ./componentRenderContext.ts) + s._d = false; + openBlock(); + } s = s(); + if (isCompiledSlot) { + s._d = true; + block = currentBlock; + closeBlock(); + } } if (shared.isArray(s)) { const singleChild = filterSingleRoot(s); @@ -2707,7 +2717,11 @@ function normalizeSuspenseSlot(s) { } s = singleChild; } - return normalizeVNode(s); + s = normalizeVNode(s); + if (block) { + s.dynamicChildren = block.filter(c => c !== s); + } + return s; } function queueEffectWithSuspense(fn, suspense) { if (suspense && suspense.pendingBranch) { @@ -2929,7 +2943,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = sh job.allowRecurse = !!cb; let scheduler; if (flush === 'sync') { - scheduler = job; + scheduler = job; // the scheduler function gets called directly } else if (flush === 'post') { scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); @@ -3005,7 +3019,9 @@ function createPathGetter(ctx, path) { }; } function traverse(value, seen = new Set()) { - if (!shared.isObject(value) || seen.has(value)) { + if (!shared.isObject(value) || + seen.has(value) || + value["__v_skip" /* SKIP */]) { return value; } seen.add(value); @@ -3119,7 +3135,7 @@ const BaseTransitionImpl = { } // handle mode if (oldInnerChild && - oldInnerChild.type !== Comment && + oldInnerChild.type !== Comment$1 && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { const leavingHooks = resolveTransitionHooks(oldInnerChild, rawProps, state, instance); // update old tree's hooks in case of dynamic transition @@ -3134,7 +3150,7 @@ const BaseTransitionImpl = { }; return emptyPlaceholder(child); } - else if (mode === 'in-out' && innerChild.type !== Comment) { + else if (mode === 'in-out' && innerChild.type !== Comment$1) { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType(state, oldInnerChild); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; @@ -3326,7 +3342,7 @@ function getTransitionRawChildren(children, keepComment = false) { ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if - else if (keepComment || child.type !== Comment) { + else if (keepComment || child.type !== Comment$1) { ret.push(child); } } @@ -3899,75 +3915,6 @@ function onErrorCaptured(hook, target = currentInstance) { injectHook("ec" /* ERROR_CAPTURED */, hook, target); } -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -/** - * @private - */ -function resolveComponent(name, maybeSelfReference) { - return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; -} -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (shared.isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; - } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); - } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // explicit self name has highest priority - if (type === COMPONENTS) { - const selfName = getComponentName(Component); - if (selfName && - (selfName === name || - selfName === shared.camelize(name) || - selfName === shared.capitalize(shared.camelize(name)))) { - return Component; - } - } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if (!res && maybeSelfReference) { - // fallback to implicit self-reference - return Component; - } - if (warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); - } - return res; - } - else { - warn(`resolve${shared.capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); - } -} -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[shared.camelize(name)] || - registry[shared.capitalize(shared.camelize(name))])); -} - function createDuplicateChecker() { const cache = Object.create(null); return (type, key) => { @@ -3980,44 +3927,32 @@ function createDuplicateChecker() { }; } let shouldCacheAccess = true; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { - const { - // composition - mixins, extends: extendsOptions, - // state - data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, - // lifecycle - beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, - // public API - expose } = options; +function applyOptions(instance) { + const options = resolveMergedOptions(instance); const publicThis = instance.proxy; const ctx = instance.ctx; - const globalMixins = instance.appContext.mixins; - if (asMixin && render && instance.render === shared.NOOP) { - instance.render = render; - } // fixed by xxxxxx const customApplyOptions = instance.appContext.config.globalProperties .$applyOptions; if (customApplyOptions) { customApplyOptions(options, instance, publicThis); } - // applyOptions is called non-as-mixin once per instance - if (!asMixin) { - shouldCacheAccess = false; - callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); - shouldCacheAccess = true; - // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); - } - // extending a base component... - if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); - } - // local mixins - if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); + // do not cache property access on public proxy during state initialization + shouldCacheAccess = false; + // call beforeCreate first before accessing other options since + // the hook may mutate resolved options (#2791) + if (options.beforeCreate) { + callHook(options.beforeCreate, instance, "bc" /* BEFORE_CREATE */); } + const { + // state + data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, + // lifecycle + created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, + // public API + expose, inheritAttrs, + // assets + components, directives, filters } = options; const checkDuplicateProperties = createDuplicateChecker() ; { const [propsOptions] = instance.propsOptions; @@ -4061,33 +3996,40 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } - if (!asMixin) { - if (deferredData.length) { - deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)); + if (dataOptions) { + if (!shared.isFunction(dataOptions)) { + warn(`The data option must be a function. ` + + `Plain object usage is no longer supported.`); } - if (dataOptions) { - // @ts-ignore dataOptions is not fully type safe - resolveData(instance, dataOptions, publicThis); + const data = dataOptions.call(publicThis, publicThis); + if (shared.isPromise(data)) { + warn(`data() returned a Promise - note data() cannot be async; If you ` + + `intend to perform data fetching before component renders, use ` + + `async setup() + .`); } - { - const rawData = toRaw(instance.data); - for (const key in rawData) { - checkDuplicateProperties("Data" /* DATA */, key); - // expose data on ctx during dev - if (key[0] !== '$' && key[0] !== '_') { - Object.defineProperty(ctx, key, { - configurable: true, - enumerable: true, - get: () => rawData[key], - set: shared.NOOP - }); + if (!shared.isObject(data)) { + warn(`data() should return an object.`); + } + else { + instance.data = reactive(data); + { + for (const key in data) { + checkDuplicateProperties("Data" /* DATA */, key); + // expose data on ctx during dev + if (key[0] !== '$' && key[0] !== '_') { + Object.defineProperty(ctx, key, { + configurable: true, + enumerable: true, + get: () => data[key], + set: shared.NOOP + }); + } } } } } - else if (dataOptions) { - deferredData.push(dataOptions); - } + // state initialization complete at this point - start caching access + shouldCacheAccess = true; if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key]; @@ -4121,42 +4063,26 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (watchOptions) { - deferredWatch.push(watchOptions); - } - if (!asMixin && deferredWatch.length) { - deferredWatch.forEach(watchOptions => { - for (const key in watchOptions) { - createWatcher(watchOptions[key], ctx, publicThis, key); - } - }); + for (const key in watchOptions) { + createWatcher(watchOptions[key], ctx, publicThis, key); + } } if (provideOptions) { - deferredProvide.push(provideOptions); - } - if (!asMixin && deferredProvide.length) { - deferredProvide.forEach(provideOptions => { - const provides = shared.isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - Reflect.ownKeys(provides).forEach(key => { - provide(key, provides[key]); - }); + const provides = shared.isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + Reflect.ownKeys(provides).forEach(key => { + provide(key, provides[key]); }); } - // asset options. - // To reduce memory usage, only components with mixins or extends will have - // resolved asset registry attached to instance. - if (asMixin) { - resolveInstanceAssets(instance, options, COMPONENTS); - resolveInstanceAssets(instance, options, DIRECTIVES); - } - // lifecycle options - if (!asMixin) { - callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); + if (created) { + callHook(created, instance, "c" /* CREATED */); } function registerLifecycleHook(register, hook) { - // Array lifecycle hooks are only present in the compat build - if (hook) { + if (shared.isArray(hook)) { + hook.forEach(_hook => register(_hook.bind(publicThis))); + } + else if (hook) { register(hook.bind(publicThis)); } } @@ -4173,105 +4099,57 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], registerLifecycleHook(onUnmounted, unmounted); registerLifecycleHook(onServerPrefetch, serverPrefetch); if (shared.isArray(expose)) { - if (!asMixin) { - if (expose.length) { - const exposed = instance.exposed || (instance.exposed = proxyRefs({})); - expose.forEach(key => { - exposed[key] = toRef(publicThis, key); - }); - } - else if (!instance.exposed) { - instance.exposed = shared.EMPTY_OBJ; - } + if (expose.length) { + const exposed = instance.exposed || (instance.exposed = proxyRefs({})); + expose.forEach(key => { + exposed[key] = toRef(publicThis, key); + }); } - else { - warn(`The \`expose\` option is ignored when used in mixins.`); + else if (!instance.exposed) { + instance.exposed = shared.EMPTY_OBJ; } } -} -function resolveInstanceAssets(instance, mixin, type) { - if (mixin[type]) { - shared.extend(instance[type] || - (instance[type] = shared.extend({}, instance.type[type])), mixin[type]); + // options that are handled when creating the instance but also need to be + // applied from mixins + if (render && instance.render === shared.NOOP) { + instance.render = render; + } + if (inheritAttrs != null) { + instance.inheritAttrs = inheritAttrs; } + // asset options. + if (components) + instance.components = components; + if (directives) + instance.directives = directives; } function resolveInjections(injectOptions, ctx, checkDuplicateProperties = shared.NOOP) { if (shared.isArray(injectOptions)) { - for (let i = 0; i < injectOptions.length; i++) { - const key = injectOptions[i]; - ctx[key] = inject(key); - { - checkDuplicateProperties("Inject" /* INJECT */, key); - } - } + injectOptions = normalizeInject(injectOptions); } - else { - for (const key in injectOptions) { - const opt = injectOptions[key]; - if (shared.isObject(opt)) { + for (const key in injectOptions) { + const opt = injectOptions[key]; + if (shared.isObject(opt)) { + if ('default' in opt) { ctx[key] = inject(opt.from || key, opt.default, true /* treat default function as factory */); } else { - ctx[key] = inject(opt); - } - { - checkDuplicateProperties("Inject" /* INJECT */, key); + ctx[key] = inject(opt.from || key); } } - } -} -function callSyncHook(name, type, options, instance, globalMixins) { - for (let i = 0; i < globalMixins.length; i++) { - callHookWithMixinAndExtends(name, type, globalMixins[i], instance); - } - callHookWithMixinAndExtends(name, type, options, instance); -} -function callHookWithMixinAndExtends(name, type, options, instance) { - const { extends: base, mixins } = options; - const selfHook = options[name]; - if (base) { - callHookWithMixinAndExtends(name, type, base, instance); - } - if (mixins) { - for (let i = 0; i < mixins.length; i++) { - callHookWithMixinAndExtends(name, type, mixins[i], instance); + else { + ctx[key] = inject(opt); } - } - if (selfHook) { - callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); - } -} -function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { - for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); - } -} -function resolveData(instance, dataFn, publicThis) { - if (!shared.isFunction(dataFn)) { - warn(`The data option must be a function. ` + - `Plain object usage is no longer supported.`); - } - shouldCacheAccess = false; - const data = dataFn.call(publicThis, publicThis); - shouldCacheAccess = true; - if (shared.isPromise(data)) { - warn(`data() returned a Promise - note data() cannot be async; If you ` + - `intend to perform data fetching before component renders, use ` + - `async setup() + .`); - } - if (!shared.isObject(data)) { - warn(`data() should return an object.`); - } - else if (instance.data === shared.EMPTY_OBJ) { - instance.data = reactive(data); - } - else { - // existing data: this is a mixin or extends. { - shared.extend(instance.data, data); + checkDuplicateProperties("Inject" /* INJECT */, key); } } } +function callHook(hook, instance, type) { + callWithAsyncErrorHandling(shared.isArray(hook) + ? hook.map(h => h.bind(instance.proxy)) + : hook.bind(instance.proxy), instance, type); +} function createWatcher(raw, ctx, publicThis, key) { const getter = key.includes('.') ? createPathGetter(publicThis, key) @@ -4308,33 +4186,115 @@ function createWatcher(raw, ctx, publicThis, key) { warn(`Invalid watch option: "${key}"`, raw); } } +/** + * Resolve merged options and cache it on the component. + * This is done only once per-component since the merging does not involve + * instances. + */ function resolveMergedOptions(instance) { - const raw = instance.type; - const { __merged, mixins, extends: extendsOptions } = raw; - if (__merged) - return __merged; - const globalMixins = instance.appContext.mixins; - if (!globalMixins.length && !mixins && !extendsOptions) - return raw; - const options = {}; - globalMixins.forEach(m => mergeOptions(options, m, instance)); - mergeOptions(options, raw, instance); - return (raw.__merged = options); -} -function mergeOptions(to, from, instance, strats = instance && instance.appContext.config.optionMergeStrategies) { + const base = instance.type; + const { mixins, extends: extendsOptions } = base; + const { mixins: globalMixins, optionsCache: cache, config: { optionMergeStrategies } } = instance.appContext; + const cached = cache.get(base); + let resolved; + if (cached) { + resolved = cached; + } + else if (!globalMixins.length && !mixins && !extendsOptions) { + { + resolved = base; + } + } + else { + resolved = {}; + if (globalMixins.length) { + globalMixins.forEach(m => mergeOptions(resolved, m, optionMergeStrategies, true)); + } + mergeOptions(resolved, base, optionMergeStrategies); + } + cache.set(base, resolved); + return resolved; +} +function mergeOptions(to, from, strats, asMixin = false) { const { mixins, extends: extendsOptions } = from; - extendsOptions && mergeOptions(to, extendsOptions, instance, strats); - mixins && - mixins.forEach((m) => mergeOptions(to, m, instance, strats)); + if (extendsOptions) { + mergeOptions(to, extendsOptions, strats, true); + } + if (mixins) { + mixins.forEach((m) => mergeOptions(to, m, strats, true)); + } for (const key in from) { - if (strats && shared.hasOwn(strats, key)) { - to[key] = strats[key](to[key], from[key], instance && instance.proxy, key); + if (asMixin && key === 'expose') { + warn(`"expose" option is ignored when declared in mixins or extends. ` + + `It should only be declared in the base component itself.`); } else { - to[key] = from[key]; + const strat = internalOptionMergeStrats[key] || (strats && strats[key]); + to[key] = strat ? strat(to[key], from[key]) : from[key]; } } return to; +} +const internalOptionMergeStrats = { + data: mergeDataFn, + props: mergeObjectOptions, + emits: mergeObjectOptions, + // objects + methods: mergeObjectOptions, + computed: mergeObjectOptions, + // lifecycle + beforeCreate: mergeHook, + created: mergeHook, + beforeMount: mergeHook, + mounted: mergeHook, + beforeUpdate: mergeHook, + updated: mergeHook, + beforeDestroy: mergeHook, + destroyed: mergeHook, + activated: mergeHook, + deactivated: mergeHook, + errorCaptured: mergeHook, + serverPrefetch: mergeHook, + // assets + components: mergeObjectOptions, + directives: mergeObjectOptions, + // watch has special merge behavior in v2, but isn't actually needed in v3. + // since we are only exposing these for compat and nobody should be relying + // on the watch-specific behavior, just expose the object merge strat. + watch: mergeObjectOptions, + // provide / inject + provide: mergeDataFn, + inject: mergeInject +}; +function mergeDataFn(to, from) { + if (!from) { + return to; + } + if (!to) { + return from; + } + return function mergedDataFn() { + return (shared.extend)(shared.isFunction(to) ? to.call(this, this) : to, shared.isFunction(from) ? from.call(this, this) : from); + }; +} +function mergeInject(to, from) { + return mergeObjectOptions(normalizeInject(to), normalizeInject(from)); +} +function normalizeInject(raw) { + if (shared.isArray(raw)) { + const res = {}; + for (let i = 0; i < raw.length; i++) { + res[raw[i]] = raw[i]; + } + return res; + } + return raw; +} +function mergeHook(to, from) { + return to ? [...new Set([].concat(to, from))] : from; +} +function mergeObjectOptions(to, from) { + return to ? shared.extend(shared.extend(Object.create(null), to), from) : from; } function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison @@ -4538,8 +4498,10 @@ function resolvePropValue(options, props, key, value, instance, isAbsent) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__props) { - return comp.__props; + const cache = appContext.propsCache; + const cached = cache.get(comp); + if (cached) { + return cached; } const raw = comp.props; const normalized = {}; @@ -4565,7 +4527,8 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__props = shared.EMPTY_ARR); + cache.set(comp, shared.EMPTY_ARR); + return shared.EMPTY_ARR; } if (shared.isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -4602,7 +4565,9 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (comp.__props = [normalized, needCastKeys]); + const res = [normalized, needCastKeys]; + cache.set(comp, res); + return res; } function validatePropName(key) { if (key[0] !== '$') { @@ -4935,12 +4900,16 @@ function invokeDirectiveHook(vnode, prevVNode, instance, name) { } let hook = binding.dir[name]; if (hook) { + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ vnode.el, binding, vnode, prevVNode ]); + resetTracking(); } } } @@ -4960,7 +4929,10 @@ function createAppContext() { mixins: [], components: {}, directives: {}, - provides: Object.create(null) + provides: Object.create(null), + optionsCache: new WeakMap(), + propsCache: new WeakMap(), + emitsCache: new WeakMap() }; } let uid$1 = 0; @@ -5010,11 +4982,6 @@ function createAppAPI(render, hydrate) { { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); - // global mixin with props/emits de-optimizes props/emits - // normalization caching. - if (mixin.props || mixin.emits) { - context.deopt = true; - } } else { warn('Mixin has already been applied to target app' + @@ -5157,7 +5124,7 @@ function createHydrationFunctions(rendererInternals) { nextNode = nextSibling(node); } break; - case Comment: + case Comment$1: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } @@ -5599,7 +5566,7 @@ function baseCreateRenderer(options, createHydrationFns) { case Text: processText(n1, n2, container, anchor); break; - case Comment: + case Comment$1: processCommentNode(n1, n2, container, anchor); break; case Static: @@ -5894,15 +5861,18 @@ function baseCreateRenderer(options, createHydrationFns) { const newVNode = newChildren[i]; // Determine the container (parent element) for the patch. const container = - // - In the case of a Fragment, we need to provide the actual parent - // of the Fragment itself so it can move its children. - oldVNode.type === Fragment || - // - In the case of different nodes, there is going to be a replacement - // which also requires the correct parent container - !isSameVNodeType(oldVNode, newVNode) || - // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & 6 /* COMPONENT */ || - oldVNode.shapeFlag & 64 /* TELEPORT */ + // oldVNode may be an errored async setup() component inside Suspense + // which will not have a mounted element + oldVNode.el && + // - In the case of a Fragment, we need to provide the actual parent + // of the Fragment itself so it can move its children. + (oldVNode.type === Fragment || + // - In the case of different nodes, there is going to be a replacement + // which also requires the correct parent container + !isSameVNodeType(oldVNode, newVNode) || + // - In the case of a component, it could contain anything. + oldVNode.shapeFlag & 6 /* COMPONENT */ || + oldVNode.shapeFlag & 64 /* TELEPORT */) ? hostParentNode(oldVNode.el) : // In other cases, the parent container is not actually used so we // just pass the block element here to avoid a DOM parentNode call. @@ -6035,7 +6005,7 @@ function baseCreateRenderer(options, createHydrationFns) { // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { - const placeholder = (instance.subTree = createVNode(Comment)); + const placeholder = (instance.subTree = createVNode(Comment$1)); processCommentNode(null, placeholder, container, anchor); } return; @@ -6786,7 +6756,7 @@ function traverseStaticChildren(n1, n2, shallow = false) { } // also inherit for comment nodes, but not placeholders (e.g. v-if which // would have received .el during block patch) - if (c2.type === Comment && !c2.el) { + if (c2.type === Comment$1 && !c2.el) { c2.el = c1.el; } } @@ -7025,9 +6995,78 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope // Force-casted public typing for h and TSX props inference const Teleport = TeleportImpl; +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +/** + * @private + */ +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (shared.isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // explicit self name has highest priority + if (type === COMPONENTS) { + const selfName = getComponentName(Component); + if (selfName && + (selfName === name || + selfName === shared.camelize(name) || + selfName === shared.capitalize(shared.camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if (!res && maybeSelfReference) { + // fallback to implicit self-reference + return Component; + } + if (warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else { + warn(`resolve${shared.capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[shared.camelize(name)] || + registry[shared.capitalize(shared.camelize(name))])); +} + const Fragment = Symbol('Fragment' ); const Text = Symbol('Text' ); -const Comment = Symbol('Comment' ); +const Comment$1 = 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 @@ -7146,7 +7185,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami if (!type) { warn(`Invalid vnode type when creating vnode: ${type}.`); } - type = Comment; + type = Comment$1; } if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like @@ -7234,9 +7273,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami normalizeChildren(vnode, children); // normalize suspense children if (shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + type.normalize(vnode); } if (isBlockTreeEnabled > 0 && // avoid a block node from tracking itself @@ -7347,22 +7384,24 @@ function createCommentVNode(text = '', // block to ensure correct updates. asBlock = false) { return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); + ? (openBlock(), createBlock(Comment$1, null, text)) + : createVNode(Comment$1, null, text); } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder - return createVNode(Comment); + return createVNode(Comment$1); } else if (shared.isArray(child)) { // fragment - return createVNode(Fragment, null, child); + return createVNode(Fragment, null, + // #3666, avoid reference pollution when reusing vnode + child.slice()); } else if (typeof child === 'object') { // already vnode, this should be the most common since compiled templates // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + return cloneIfMounted(child); } else { // strings and numbers @@ -7561,7 +7600,7 @@ function ensureValidVNode(vnodes) { return vnodes.some(child => { if (!isVNode(child)) return true; - if (child.type === Comment) + if (child.type === Comment$1) return false; if (child.type === Fragment && !ensureValidVNode(child.children)) @@ -7875,6 +7914,8 @@ function createComponentInstance(vnode, parent, suspense) { emitted: null, // props default value propsDefaults: shared.EMPTY_OBJ, + // inheritAttrs + inheritAttrs: type.inheritAttrs, // state ctx: shared.EMPTY_OBJ, data: shared.EMPTY_OBJ, @@ -8100,7 +8141,7 @@ function finishComponentSetup(instance, isSSR, skipOptions) { { currentInstance = instance; pauseTracking(); - applyOptions(instance, Component); + applyOptions(instance); resetTracking(); currentInstance = null; } @@ -8462,7 +8503,7 @@ function initCustomFormatter() { } // Core API ------------------------------------------------------------------ -const version = "3.1.0-beta.5"; +const version = "3.1.0-beta.7"; const _ssrUtils = { createComponentInstance, setupComponent, @@ -8718,6 +8759,9 @@ prevChildren, parentComponent, parentSuspense, unmountChildren) { if (el.value !== newValue) { el.value = newValue; } + if (value == null) { + el.removeAttribute(key); + } return; } if (value === '' || value == null) { @@ -9029,6 +9073,29 @@ const DOMTransitionPropsValidators = { leaveToClass: String }; const TransitionPropsValidators = (Transition.props = /*#__PURE__*/ shared.extend({}, BaseTransition.props, DOMTransitionPropsValidators)); +/** + * #3227 Incoming hooks may be merged into arrays when wrapping Transition + * with custom HOCs. + */ +const callHook$1 = (hook, args = []) => { + if (shared.isArray(hook)) { + hook.forEach(h => h(...args)); + } + else if (hook) { + hook(...args); + } +}; +/** + * Check if a hook expects a callback (2nd arg), which means the user + * intends to explicitly control the end of the transition. + */ +const hasExplicitCallback = (hook) => { + return hook + ? shared.isArray(hook) + ? hook.some(h => h.length > 1) + : hook.length > 1 + : false; +}; function resolveTransitionProps(rawProps) { const baseProps = {}; for (const key in rawProps) { @@ -9058,11 +9125,11 @@ function resolveTransitionProps(rawProps) { return (el, done) => { const hook = isAppear ? onAppear : onEnter; const resolve = () => finishEnter(el, isAppear, done); - hook && hook(el, resolve); + callHook$1(hook, [el, resolve]); nextFrame(() => { removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass); addTransitionClass(el, isAppear ? appearToClass : enterToClass); - if (!(hook && hook.length > 1)) { + if (!hasExplicitCallback(hook)) { whenTransitionEnds(el, type, enterDuration, resolve); } }); @@ -9070,12 +9137,12 @@ function resolveTransitionProps(rawProps) { }; return shared.extend(baseProps, { onBeforeEnter(el) { - onBeforeEnter && onBeforeEnter(el); + callHook$1(onBeforeEnter, [el]); addTransitionClass(el, enterFromClass); addTransitionClass(el, enterActiveClass); }, onBeforeAppear(el) { - onBeforeAppear && onBeforeAppear(el); + callHook$1(onBeforeAppear, [el]); addTransitionClass(el, appearFromClass); addTransitionClass(el, appearActiveClass); }, @@ -9090,23 +9157,23 @@ function resolveTransitionProps(rawProps) { nextFrame(() => { removeTransitionClass(el, leaveFromClass); addTransitionClass(el, leaveToClass); - if (!(onLeave && onLeave.length > 1)) { + if (!hasExplicitCallback(onLeave)) { whenTransitionEnds(el, type, leaveDuration, resolve); } }); - onLeave && onLeave(el, resolve); + callHook$1(onLeave, [el, resolve]); }, onEnterCancelled(el) { finishEnter(el, false); - onEnterCancelled && onEnterCancelled(el); + callHook$1(onEnterCancelled, [el]); }, onAppearCancelled(el) { finishEnter(el, true); - onAppearCancelled && onAppearCancelled(el); + callHook$1(onAppearCancelled, [el]); }, onLeaveCancelled(el) { finishLeave(el); - onLeaveCancelled && onLeaveCancelled(el); + callHook$1(onLeaveCancelled, [el]); } }); } @@ -9571,12 +9638,13 @@ function setSelected(el, value) { } else { if (shared.looseEqual(getValue(option), value)) { - el.selectedIndex = i; + if (el.selectedIndex !== i) + el.selectedIndex = i; return; } } } - if (!isMultiple) { + if (!isMultiple && el.selectedIndex !== -1) { el.selectedIndex = -1; } } @@ -9889,7 +9957,7 @@ exports.capitalize = shared.capitalize; exports.toDisplayString = shared.toDisplayString; exports.toHandlerKey = shared.toHandlerKey; exports.BaseTransition = BaseTransition; -exports.Comment = Comment; +exports.Comment = Comment$1; exports.Fragment = Fragment; exports.KeepAlive = KeepAlive; exports.Static = Static; diff --git a/packages/uni-h5-vue/dist/vue.runtime.compat.cjs.js b/packages/uni-h5-vue/dist/vue.runtime.compat.cjs.js index 744d6d258..3db9dfe53 100644 --- a/packages/uni-h5-vue/dist/vue.runtime.compat.cjs.js +++ b/packages/uni-h5-vue/dist/vue.runtime.compat.cjs.js @@ -333,7 +333,7 @@ let uid = 0; function createReactiveEffect(fn, options) { const effect = function reactiveEffect() { if (!effect.active) { - return options.scheduler ? undefined : fn(); + return fn(); } if (!effectStack.includes(effect)) { cleanup(effect); @@ -1559,7 +1559,7 @@ function flushJobs(seen) { try { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex]; - if (job) { + if (job && job.active !== false) { if (true && checkRecursiveUpdates(seen, job)) { continue; } @@ -1742,7 +1742,7 @@ function devtoolsInitApp(app, version) { devtools.emit("app:init" /* APP_INIT */, app, version, { Fragment, Text, - Comment, + Comment: Comment$1, Static }); } @@ -2072,7 +2072,7 @@ function warnDeprecation(key, instance, ...args) { warnCount[dupKey] = 0; const { message, link } = deprecationData[key]; warn(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`); - if (!isCompatEnabled(key, instance)) { + if (!isCompatEnabled(key, instance, true)) { console.error(`^ The above deprecation's compat behavior is disabled and will likely ` + `lead to runtime errors.`); } @@ -2089,7 +2089,7 @@ function configureCompat(config) { const seenConfigObjects = /*#__PURE__*/ new WeakSet(); const warnedInvalidKeys = {}; // dev only -function validateCompatConfig(config) { +function validateCompatConfig(config, instance) { if (seenConfigObjects.has(config)) { return; } @@ -2113,6 +2113,9 @@ function validateCompatConfig(config) { warnedInvalidKeys[key] = true; } } + if (instance && config["OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */] != null) { + warn(`Deprecation config "${"OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */}" can only be configured globally.`); + } } function getCompatConfigForKey(key, instance) { const instanceConfig = instance && instance.type.compatConfig; @@ -2363,8 +2366,10 @@ function emit$1(instance, event, ...rawArgs) { } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__emits !== undefined) { - return comp.__emits; + const cache = appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== undefined) { + return cached; } const raw = comp.emits; let normalized = {}; @@ -2389,7 +2394,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__emits = null); + cache.set(comp, null); + return null; } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -2397,7 +2403,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (comp.__emits = normalized); + cache.set(comp, normalized); + return normalized; } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -2518,7 +2525,7 @@ function markAttrsAccessed() { accessedAttrs = true; } function renderComponentRoot(instance) { - const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx } = instance; + const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance; let result; const prev = setCurrentRenderingInstance(instance); { @@ -2567,7 +2574,7 @@ function renderComponentRoot(instance) { ; [root, setRoot] = getChildRoot(result); } - if (fallthroughAttrs && Component.inheritAttrs !== false) { + if (fallthroughAttrs && inheritAttrs !== false) { const keys = Object.keys(fallthroughAttrs); const { shapeFlag } = root; if (keys.length) { @@ -2582,7 +2589,7 @@ function renderComponentRoot(instance) { } root = cloneVNode(root, fallthroughAttrs); } - else if (true && !accessedAttrs && root.type !== Comment) { + else if (true && !accessedAttrs && root.type !== Comment$1) { const allAttrs = Object.keys(attrs); const eventAttrs = []; const extraAttrs = []; @@ -2624,7 +2631,7 @@ function renderComponentRoot(instance) { root.shapeFlag & 6 /* COMPONENT */)) { const { class: cls, style } = vnode.props || {}; if (cls || style) { - if (true && Component.inheritAttrs === false) { + if (true && inheritAttrs === false) { warnDeprecation("INSTANCE_ATTRS_CLASS_STYLE" /* INSTANCE_ATTRS_CLASS_STYLE */, instance, getComponentName(instance.type)); } root = cloneVNode(root, { @@ -2659,7 +2666,7 @@ function renderComponentRoot(instance) { catch (err) { blockStack.length = 0; handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment); + result = createVNode(Comment$1); } setCurrentRenderingInstance(prev); return result; @@ -2698,7 +2705,7 @@ function filterSingleRoot(children) { const child = children[i]; if (isVNode(child)) { // ignore user comment - if (child.type !== Comment || child.children === 'v-if') { + if (child.type !== Comment$1 || child.children === 'v-if') { if (singleRoot) { // has more than 1 non-comment child, return now return; @@ -2735,7 +2742,7 @@ const filterModelListeners = (attrs, props) => { const isElementRoot = (vnode) => { return (vnode.shapeFlag & 6 /* COMPONENT */ || vnode.shapeFlag & 1 /* ELEMENT */ || - vnode.type === Comment // potential v-if branch switch + vnode.type === Comment$1 // potential v-if branch switch ); }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { @@ -2841,7 +2848,8 @@ const SuspenseImpl = { } }, hydrate: hydrateSuspense, - create: createSuspenseBoundary + create: createSuspenseBoundary, + normalize: normalizeSuspenseChildren }; // Force-casted public typing for h and TSX props inference const Suspense = (SuspenseImpl @@ -3186,24 +3194,29 @@ function hydrateSuspense(node, vnode, parentComponent, parentSuspense, isSVG, sl } function normalizeSuspenseChildren(vnode) { const { shapeFlag, children } = vnode; - let content; - let fallback; - if (shapeFlag & 32 /* SLOTS_CHILDREN */) { - content = normalizeSuspenseSlot(children.default); - fallback = normalizeSuspenseSlot(children.fallback); - } - else { - content = normalizeSuspenseSlot(children); - fallback = normalizeVNode(null); - } - return { - content, - fallback - }; + const isSlotChildren = shapeFlag & 32 /* SLOTS_CHILDREN */; + vnode.ssContent = normalizeSuspenseSlot(isSlotChildren ? children.default : children); + vnode.ssFallback = isSlotChildren + ? normalizeSuspenseSlot(children.fallback) + : createVNode(Comment); } function normalizeSuspenseSlot(s) { + let block; if (isFunction(s)) { + const isCompiledSlot = s._c; + if (isCompiledSlot) { + // disableTracking: false + // allow block tracking for compiled slots + // (see ./componentRenderContext.ts) + s._d = false; + openBlock(); + } s = s(); + if (isCompiledSlot) { + s._d = true; + block = currentBlock; + closeBlock(); + } } if (isArray(s)) { const singleChild = filterSingleRoot(s); @@ -3212,7 +3225,11 @@ function normalizeSuspenseSlot(s) { } s = singleChild; } - return normalizeVNode(s); + s = normalizeVNode(s); + if (block) { + s.dynamicChildren = block.filter(c => c !== s); + } + return s; } function queueEffectWithSuspense(fn, suspense) { if (suspense && suspense.pendingBranch) { @@ -3447,7 +3464,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM job.allowRecurse = !!cb; let scheduler; if (flush === 'sync') { - scheduler = job; + scheduler = job; // the scheduler function gets called directly } else if (flush === 'post') { scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); @@ -3523,7 +3540,9 @@ function createPathGetter(ctx, path) { }; } function traverse(value, seen = new Set()) { - if (!isObject(value) || seen.has(value)) { + if (!isObject(value) || + seen.has(value) || + value["__v_skip" /* SKIP */]) { return value; } seen.add(value); @@ -3637,7 +3656,7 @@ const BaseTransitionImpl = { } // handle mode if (oldInnerChild && - oldInnerChild.type !== Comment && + oldInnerChild.type !== Comment$1 && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { const leavingHooks = resolveTransitionHooks(oldInnerChild, rawProps, state, instance); // update old tree's hooks in case of dynamic transition @@ -3652,7 +3671,7 @@ const BaseTransitionImpl = { }; return emptyPlaceholder(child); } - else if (mode === 'in-out' && innerChild.type !== Comment) { + else if (mode === 'in-out' && innerChild.type !== Comment$1) { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType(state, oldInnerChild); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; @@ -3847,7 +3866,7 @@ function getTransitionRawChildren(children, keepComment = false) { ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if - else if (keepComment || child.type !== Comment) { + else if (keepComment || child.type !== Comment$1) { ret.push(child); } } @@ -4423,106 +4442,19 @@ function onErrorCaptured(hook, target = currentInstance) { injectHook("ec" /* ERROR_CAPTURED */, hook, target); } -function deepMergeData(to, from, instance) { +function deepMergeData(to, from) { for (const key in from) { const toVal = to[key]; const fromVal = from[key]; if (key in to && isPlainObject(toVal) && isPlainObject(fromVal)) { - warnDeprecation("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, instance, key); - deepMergeData(toVal, fromVal, instance); + warnDeprecation("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, null, key); + deepMergeData(toVal, fromVal); } else { to[key] = fromVal; } } -} -function mergeDataOption(to, from) { - if (!from) { - return to; - } - if (!to) { - return from; - } - return function mergedDataFn() { - return deepMergeData(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from, this.$); - }; -} - -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -const FILTERS = 'filters'; -/** - * @private - */ -function resolveComponent(name, maybeSelfReference) { - return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; -} -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; - } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); - } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -/** - * v2 compat only - * @internal - */ -function resolveFilter(name) { - return resolveAsset(FILTERS, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // explicit self name has highest priority - if (type === COMPONENTS) { - const selfName = getComponentName(Component); - if (selfName && - (selfName === name || - selfName === camelize(name) || - selfName === capitalize(camelize(name)))) { - return Component; - } - } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if (!res && maybeSelfReference) { - // fallback to implicit self-reference - return Component; - } - if (warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); - } - return res; - } - else { - warn(`resolve${capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); - } -} -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[camelize(name)] || - registry[capitalize(camelize(name))])); + return to; } function createDuplicateChecker() { @@ -4537,47 +4469,32 @@ function createDuplicateChecker() { }; } let shouldCacheAccess = true; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { - if (isFunction(options)) { - options = options.options; - } - const { - // composition - mixins, extends: extendsOptions, - // state - data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, - // lifecycle - beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, - // public API - expose } = options; +function applyOptions(instance) { + const options = resolveMergedOptions(instance); const publicThis = instance.proxy; const ctx = instance.ctx; - const globalMixins = instance.appContext.mixins; - if (asMixin && render && instance.render === NOOP) { - instance.render = render; - } // fixed by xxxxxx const customApplyOptions = instance.appContext.config.globalProperties .$applyOptions; if (customApplyOptions) { customApplyOptions(options, instance, publicThis); } - // applyOptions is called non-as-mixin once per instance - if (!asMixin) { - shouldCacheAccess = false; - callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); - shouldCacheAccess = true; - // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); - } - // extending a base component... - if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); - } - // local mixins - if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); + // do not cache property access on public proxy during state initialization + shouldCacheAccess = false; + // call beforeCreate first before accessing other options since + // the hook may mutate resolved options (#2791) + if (options.beforeCreate) { + callHook(options.beforeCreate, instance, "bc" /* BEFORE_CREATE */); } + const { + // state + data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, + // lifecycle + created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, + // public API + expose, inheritAttrs, + // assets + components, directives, filters } = options; const checkDuplicateProperties = createDuplicateChecker() ; { const [propsOptions] = instance.propsOptions; @@ -4621,33 +4538,40 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } - if (!asMixin) { - if (deferredData.length) { - deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)); + if (dataOptions) { + if (!isFunction(dataOptions)) { + warn(`The data option must be a function. ` + + `Plain object usage is no longer supported.`); } - if (dataOptions) { - // @ts-ignore dataOptions is not fully type safe - resolveData(instance, dataOptions, publicThis); + const data = dataOptions.call(publicThis, publicThis); + if (isPromise(data)) { + warn(`data() returned a Promise - note data() cannot be async; If you ` + + `intend to perform data fetching before component renders, use ` + + `async setup() + .`); } - { - const rawData = toRaw(instance.data); - for (const key in rawData) { - checkDuplicateProperties("Data" /* DATA */, key); - // expose data on ctx during dev - if (key[0] !== '$' && key[0] !== '_') { - Object.defineProperty(ctx, key, { - configurable: true, - enumerable: true, - get: () => rawData[key], - set: NOOP - }); + if (!isObject(data)) { + warn(`data() should return an object.`); + } + else { + instance.data = reactive(data); + { + for (const key in data) { + checkDuplicateProperties("Data" /* DATA */, key); + // expose data on ctx during dev + if (key[0] !== '$' && key[0] !== '_') { + Object.defineProperty(ctx, key, { + configurable: true, + enumerable: true, + get: () => data[key], + set: NOOP + }); + } } } } } - else if (dataOptions) { - deferredData.push(dataOptions); - } + // state initialization complete at this point - start caching access + shouldCacheAccess = true; if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key]; @@ -4681,44 +4605,22 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (watchOptions) { - deferredWatch.push(watchOptions); - } - if (!asMixin && deferredWatch.length) { - deferredWatch.forEach(watchOptions => { - for (const key in watchOptions) { - createWatcher(watchOptions[key], ctx, publicThis, key); - } - }); + for (const key in watchOptions) { + createWatcher(watchOptions[key], ctx, publicThis, key); + } } if (provideOptions) { - deferredProvide.push(provideOptions); - } - if (!asMixin && deferredProvide.length) { - deferredProvide.forEach(provideOptions => { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - Reflect.ownKeys(provides).forEach(key => { - provide(key, provides[key]); - }); + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + Reflect.ownKeys(provides).forEach(key => { + provide(key, provides[key]); }); } - // asset options. - // To reduce memory usage, only components with mixins or extends will have - // resolved asset registry attached to instance. - if (asMixin) { - resolveInstanceAssets(instance, options, COMPONENTS); - resolveInstanceAssets(instance, options, DIRECTIVES); - if (isCompatEnabled("FILTERS" /* FILTERS */, instance)) { - resolveInstanceAssets(instance, options, FILTERS); - } - } - // lifecycle options - if (!asMixin) { - callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); + if (created) { + callHook(created, instance, "c" /* CREATED */); } function registerLifecycleHook(register, hook) { - // Array lifecycle hooks are only present in the compat build if (isArray(hook)) { hook.forEach(_hook => register(_hook.bind(publicThis))); } @@ -4749,110 +4651,61 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (isArray(expose)) { - if (!asMixin) { - if (expose.length) { - const exposed = instance.exposed || (instance.exposed = proxyRefs({})); - expose.forEach(key => { - exposed[key] = toRef(publicThis, key); - }); - } - else if (!instance.exposed) { - instance.exposed = EMPTY_OBJ; - } + if (expose.length) { + const exposed = instance.exposed || (instance.exposed = proxyRefs({})); + expose.forEach(key => { + exposed[key] = toRef(publicThis, key); + }); } - else { - warn(`The \`expose\` option is ignored when used in mixins.`); + else if (!instance.exposed) { + instance.exposed = EMPTY_OBJ; } } -} -function resolveInstanceAssets(instance, mixin, type) { - if (mixin[type]) { - extend(instance[type] || - (instance[type] = extend({}, instance.type[type])), mixin[type]); + // options that are handled when creating the instance but also need to be + // applied from mixins + if (render && instance.render === NOOP) { + instance.render = render; + } + if (inheritAttrs != null) { + instance.inheritAttrs = inheritAttrs; + } + // asset options. + if (components) + instance.components = components; + if (directives) + instance.directives = directives; + if (filters && + isCompatEnabled("FILTERS" /* FILTERS */, instance)) { + instance.filters = filters; } } function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) { if (isArray(injectOptions)) { - for (let i = 0; i < injectOptions.length; i++) { - const key = injectOptions[i]; - ctx[key] = inject(key); - { - checkDuplicateProperties("Inject" /* INJECT */, key); - } - } + injectOptions = normalizeInject(injectOptions); } - else { - for (const key in injectOptions) { - const opt = injectOptions[key]; - if (isObject(opt)) { + for (const key in injectOptions) { + const opt = injectOptions[key]; + if (isObject(opt)) { + if ('default' in opt) { ctx[key] = inject(opt.from || key, opt.default, true /* treat default function as factory */); } else { - ctx[key] = inject(opt); - } - { - checkDuplicateProperties("Inject" /* INJECT */, key); + ctx[key] = inject(opt.from || key); } } - } -} -function callSyncHook(name, type, options, instance, globalMixins) { - for (let i = 0; i < globalMixins.length; i++) { - callHookWithMixinAndExtends(name, type, globalMixins[i], instance); - } - callHookWithMixinAndExtends(name, type, options, instance); -} -function callHookWithMixinAndExtends(name, type, options, instance) { - const { extends: base, mixins } = options; - const selfHook = options[name]; - if (base) { - callHookWithMixinAndExtends(name, type, base, instance); - } - if (mixins) { - for (let i = 0; i < mixins.length; i++) { - callHookWithMixinAndExtends(name, type, mixins[i], instance); - } - } - if (selfHook) { - callWithAsyncErrorHandling(isArray(selfHook) - ? selfHook.map(h => h.bind(instance.proxy)) - : selfHook.bind(instance.proxy), instance, type); - } -} -function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { - for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); - } -} -function resolveData(instance, dataFn, publicThis) { - if (!isFunction(dataFn)) { - warn(`The data option must be a function. ` + - `Plain object usage is no longer supported.`); - } - shouldCacheAccess = false; - const data = dataFn.call(publicThis, publicThis); - shouldCacheAccess = true; - if (isPromise(data)) { - warn(`data() returned a Promise - note data() cannot be async; If you ` + - `intend to perform data fetching before component renders, use ` + - `async setup() + .`); - } - if (!isObject(data)) { - warn(`data() should return an object.`); - } - else if (instance.data === EMPTY_OBJ) { - instance.data = reactive(data); - } - else { - // existing data: this is a mixin or extends. - if (isCompatEnabled("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, instance)) { - deepMergeData(instance.data, data, instance); - } else { - extend(instance.data, data); + ctx[key] = inject(opt); + } + { + checkDuplicateProperties("Inject" /* INJECT */, key); } } } +function callHook(hook, instance, type) { + callWithAsyncErrorHandling(isArray(hook) + ? hook.map(h => h.bind(instance.proxy)) + : hook.bind(instance.proxy), instance, type); +} function createWatcher(raw, ctx, publicThis, key) { const getter = key.includes('.') ? createPathGetter(publicThis, key) @@ -4889,36 +4742,128 @@ function createWatcher(raw, ctx, publicThis, key) { warn(`Invalid watch option: "${key}"`, raw); } } +/** + * Resolve merged options and cache it on the component. + * This is done only once per-component since the merging does not involve + * instances. + */ function resolveMergedOptions(instance) { - const raw = instance.type; - const { __merged, mixins, extends: extendsOptions } = raw; - if (__merged) - return __merged; - const globalMixins = instance.appContext.mixins; - if (!globalMixins.length && !mixins && !extendsOptions) - return raw; - const options = {}; - globalMixins.forEach(m => mergeOptions(options, m, instance)); - mergeOptions(options, raw, instance); - return (raw.__merged = options); -} -function mergeOptions(to, from, instance, strats = instance && instance.appContext.config.optionMergeStrategies) { + const base = instance.type; + const { mixins, extends: extendsOptions } = base; + const { mixins: globalMixins, optionsCache: cache, config: { optionMergeStrategies } } = instance.appContext; + const cached = cache.get(base); + let resolved; + if (cached) { + resolved = cached; + } + else if (!globalMixins.length && !mixins && !extendsOptions) { + if (isCompatEnabled("PRIVATE_APIS" /* PRIVATE_APIS */, instance)) { + resolved = extend({}, base); + resolved.parent = instance.parent && instance.parent.proxy; + resolved.propsData = instance.vnode.props; + } + else { + resolved = base; + } + } + else { + resolved = {}; + if (globalMixins.length) { + globalMixins.forEach(m => mergeOptions(resolved, m, optionMergeStrategies, true)); + } + mergeOptions(resolved, base, optionMergeStrategies); + } + cache.set(base, resolved); + return resolved; +} +function mergeOptions(to, from, strats, asMixin = false) { if (isFunction(from)) { from = from.options; } const { mixins, extends: extendsOptions } = from; - extendsOptions && mergeOptions(to, extendsOptions, instance, strats); - mixins && - mixins.forEach((m) => mergeOptions(to, m, instance, strats)); + if (extendsOptions) { + mergeOptions(to, extendsOptions, strats, true); + } + if (mixins) { + mixins.forEach((m) => mergeOptions(to, m, strats, true)); + } for (const key in from) { - if (strats && hasOwn(strats, key)) { - to[key] = strats[key](to[key], from[key], instance && instance.proxy, key); + if (asMixin && key === 'expose') { + warn(`"expose" option is ignored when declared in mixins or extends. ` + + `It should only be declared in the base component itself.`); } else { - to[key] = from[key]; + const strat = internalOptionMergeStrats[key] || (strats && strats[key]); + to[key] = strat ? strat(to[key], from[key]) : from[key]; } } return to; +} +const internalOptionMergeStrats = { + data: mergeDataFn, + props: mergeObjectOptions, + emits: mergeObjectOptions, + // objects + methods: mergeObjectOptions, + computed: mergeObjectOptions, + // lifecycle + beforeCreate: mergeHook, + created: mergeHook, + beforeMount: mergeHook, + mounted: mergeHook, + beforeUpdate: mergeHook, + updated: mergeHook, + beforeDestroy: mergeHook, + destroyed: mergeHook, + activated: mergeHook, + deactivated: mergeHook, + errorCaptured: mergeHook, + serverPrefetch: mergeHook, + // assets + components: mergeObjectOptions, + directives: mergeObjectOptions, + // watch has special merge behavior in v2, but isn't actually needed in v3. + // since we are only exposing these for compat and nobody should be relying + // on the watch-specific behavior, just expose the object merge strat. + watch: mergeObjectOptions, + // provide / inject + provide: mergeDataFn, + inject: mergeInject +}; +{ + internalOptionMergeStrats.filters = mergeObjectOptions; +} +function mergeDataFn(to, from) { + if (!from) { + return to; + } + if (!to) { + return from; + } + return function mergedDataFn() { + return (isCompatEnabled("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, null) + ? deepMergeData + : extend)(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from); + }; +} +function mergeInject(to, from) { + return mergeObjectOptions(normalizeInject(to), normalizeInject(from)); +} +function normalizeInject(raw) { + if (isArray(raw)) { + const res = {}; + for (let i = 0; i < raw.length; i++) { + res[raw[i]] = raw[i]; + } + return res; + } + return raw; +} +function mergeHook(to, from) { + return to ? [...new Set([].concat(to, from))] : from; +} +function mergeObjectOptions(to, from) { + return to ? extend(extend(Object.create(null), to), from) : from; } function createPropsDefaultThis(instance, rawProps, propKey) { @@ -5198,8 +5143,10 @@ function resolvePropValue(options, props, key, value, instance, isAbsent) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__props) { - return comp.__props; + const cache = appContext.propsCache; + const cached = cache.get(comp); + if (cached) { + return cached; } const raw = comp.props; const normalized = {}; @@ -5228,7 +5175,8 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__props = EMPTY_ARR); + cache.set(comp, EMPTY_ARR); + return EMPTY_ARR; } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -5265,7 +5213,9 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (comp.__props = [normalized, needCastKeys]); + const res = [normalized, needCastKeys]; + cache.set(comp, res); + return res; } function validatePropName(key) { if (key[0] !== '$') { @@ -5630,12 +5580,16 @@ function invokeDirectiveHook(vnode, prevVNode, instance, name) { hook = mapCompatDirectiveHook(name, binding.dir, instance); } if (hook) { + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ vnode.el, binding, vnode, prevVNode ]); + resetTracking(); } } } @@ -5671,49 +5625,12 @@ function installLegacyOptionMergeStrats(config) { if (key in target) { return target[key]; } - if (key in legacyOptionMergeStrats && + if (key in internalOptionMergeStrats && softAssertCompatEnabled("CONFIG_OPTION_MERGE_STRATS" /* CONFIG_OPTION_MERGE_STRATS */, null)) { - return legacyOptionMergeStrats[key]; + return internalOptionMergeStrats[key]; } } }); -} -const legacyOptionMergeStrats = { - data: mergeDataOption, - beforeCreate: mergeHook, - created: mergeHook, - beforeMount: mergeHook, - mounted: mergeHook, - beforeUpdate: mergeHook, - updated: mergeHook, - beforeDestroy: mergeHook, - destroyed: mergeHook, - activated: mergeHook, - deactivated: mergeHook, - errorCaptured: mergeHook, - serverPrefetch: mergeHook, - // assets - components: mergeObjectOptions, - directives: mergeObjectOptions, - filters: mergeObjectOptions, - // objects - props: mergeObjectOptions, - methods: mergeObjectOptions, - inject: mergeObjectOptions, - computed: mergeObjectOptions, - // watch has special merge behavior in v2, but isn't actually needed in v3. - // since we are only exposing these for compat and nobody should be relying - // on the watch-specific behavior, just expose the object merge strat. - watch: mergeObjectOptions -}; -function toArray(target) { - return isArray(target) ? target : target ? [target] : []; -} -function mergeHook(to, from) { - return Array.from(new Set([...toArray(to), ...toArray(from)])); -} -function mergeObjectOptions(to, from) { - return to ? extend(extend(Object.create(null), to), from) : from; } let isCopyingConfig = false; @@ -5746,7 +5663,7 @@ function createCompatVue(createApp, createSingletonApp) { return vm; } } - Vue.version = "3.1.0-beta.5"; + Vue.version = "3.1.0-beta.7"; Vue.config = singletonApp.config; Vue.use = (p, ...options) => { if (p && isFunction(p.install)) { @@ -5798,7 +5715,7 @@ function createCompatVue(createApp, createSingletonApp) { return createCompatApp(SubVue.options, SubVue); } else { - return createCompatApp(mergeOptions(extend({}, SubVue.options), inlineOptions, null, legacyOptionMergeStrats), SubVue); + return createCompatApp(mergeOptions(extend({}, SubVue.options), inlineOptions, internalOptionMergeStrats), SubVue); } } SubVue.super = Super; @@ -5815,7 +5732,7 @@ function createCompatVue(createApp, createSingletonApp) { ? extend(Object.create(null), superValue) : superValue; } - SubVue.options = mergeOptions(mergeBase, extendOptions, null, legacyOptionMergeStrats); + SubVue.options = mergeOptions(mergeBase, extendOptions, internalOptionMergeStrats); SubVue.options._base = SubVue; SubVue.extend = extendCtor.bind(SubVue); SubVue.mixin = Super.mixin; @@ -5850,7 +5767,7 @@ function createCompatVue(createApp, createSingletonApp) { const util = { warn: warn , extend, - mergeOptions: (parent, child, vm) => mergeOptions(parent, child, vm && vm.$, vm ? undefined : legacyOptionMergeStrats), + mergeOptions: (parent, child, vm) => mergeOptions(parent, child, vm ? undefined : internalOptionMergeStrats), defineReactive }; Object.defineProperty(Vue, 'util', { @@ -5983,6 +5900,7 @@ function installCompatMount(app, context, render) { } setupComponent(instance); vnode.component = instance; + vnode.isCompatRoot = true; // $mount & $destroy // these are defined on ctx and picked up by the $mount/$destroy // public property getters on the instance proxy. @@ -6165,7 +6083,10 @@ function createAppContext() { mixins: [], components: {}, directives: {}, - provides: Object.create(null) + provides: Object.create(null), + optionsCache: new WeakMap(), + propsCache: new WeakMap(), + emitsCache: new WeakMap() }; } let uid$1 = 0; @@ -6215,11 +6136,6 @@ function createAppAPI(render, hydrate) { { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); - // global mixin with props/emits de-optimizes props/emits - // normalization caching. - if (mixin.props || mixin.emits) { - context.deopt = true; - } } else { warn('Mixin has already been applied to target app' + @@ -6365,7 +6281,7 @@ function createHydrationFunctions(rendererInternals) { nextNode = nextSibling(node); } break; - case Comment: + case Comment$1: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } @@ -6848,7 +6764,7 @@ function baseCreateRenderer(options, createHydrationFns) { case Text: processText(n1, n2, container, anchor); break; - case Comment: + case Comment$1: processCommentNode(n1, n2, container, anchor); break; case Static: @@ -7143,15 +7059,18 @@ function baseCreateRenderer(options, createHydrationFns) { const newVNode = newChildren[i]; // Determine the container (parent element) for the patch. const container = - // - In the case of a Fragment, we need to provide the actual parent - // of the Fragment itself so it can move its children. - oldVNode.type === Fragment || - // - In the case of different nodes, there is going to be a replacement - // which also requires the correct parent container - !isSameVNodeType(oldVNode, newVNode) || - // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & 6 /* COMPONENT */ || - oldVNode.shapeFlag & 64 /* TELEPORT */ + // oldVNode may be an errored async setup() component inside Suspense + // which will not have a mounted element + oldVNode.el && + // - In the case of a Fragment, we need to provide the actual parent + // of the Fragment itself so it can move its children. + (oldVNode.type === Fragment || + // - In the case of different nodes, there is going to be a replacement + // which also requires the correct parent container + !isSameVNodeType(oldVNode, newVNode) || + // - In the case of a component, it could contain anything. + oldVNode.shapeFlag & 6 /* COMPONENT */ || + oldVNode.shapeFlag & 64 /* TELEPORT */) ? hostParentNode(oldVNode.el) : // In other cases, the parent container is not actually used so we // just pass the block element here to avoid a DOM parentNode call. @@ -7257,7 +7176,7 @@ function baseCreateRenderer(options, createHydrationFns) { const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { // 2.x compat may pre-creaate the component instance before actually // mounting - const compatMountInstance = initialVNode.component; + const compatMountInstance = initialVNode.isCompatRoot && initialVNode.component; const instance = compatMountInstance || (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense)); if (instance.type.__hmrId) { @@ -7288,7 +7207,7 @@ function baseCreateRenderer(options, createHydrationFns) { // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { - const placeholder = (instance.subTree = createVNode(Comment)); + const placeholder = (instance.subTree = createVNode(Comment$1)); processCommentNode(null, placeholder, container, anchor); } return; @@ -8060,7 +7979,7 @@ function traverseStaticChildren(n1, n2, shallow = false) { } // also inherit for comment nodes, but not placeholders (e.g. v-if which // would have received .el during block patch) - if (c2.type === Comment && !c2.el) { + if (c2.type === Comment$1 && !c2.el) { c2.el = c1.el; } } @@ -8299,6 +8218,83 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope // Force-casted public typing for h and TSX props inference const Teleport = TeleportImpl; +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +const FILTERS = 'filters'; +/** + * @private + */ +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +/** + * v2 compat only + * @internal + */ +function resolveFilter(name) { + return resolveAsset(FILTERS, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // explicit self name has highest priority + if (type === COMPONENTS) { + const selfName = getComponentName(Component); + if (selfName && + (selfName === name || + selfName === camelize(name) || + selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if (!res && maybeSelfReference) { + // fallback to implicit self-reference + return Component; + } + if (warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else { + warn(`resolve${capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[camelize(name)] || + registry[capitalize(camelize(name))])); +} + const normalizedAsyncComponentMap = new Map(); function convertLegacyAsyncComponent(comp) { if (normalizedAsyncComponentMap.has(comp)) { @@ -8375,7 +8371,7 @@ function convertLegacyRenderFn(instance) { } function compatH(type, propsOrChildren, children) { if (!type) { - type = Comment; + type = Comment$1; } // to support v2 string component name look!up if (typeof type === 'string') { @@ -8627,7 +8623,7 @@ function convertLegacyComponent(comp, instance) { const Fragment = Symbol('Fragment' ); const Text = Symbol('Text' ); -const Comment = Symbol('Comment' ); +const Comment$1 = 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 @@ -8746,7 +8742,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami if (!type) { warn(`Invalid vnode type when creating vnode: ${type}.`); } - type = Comment; + type = Comment$1; } if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like @@ -8838,9 +8834,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami normalizeChildren(vnode, children); // normalize suspense children if (shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + type.normalize(vnode); } if (isBlockTreeEnabled > 0 && // avoid a block node from tracking itself @@ -8959,22 +8953,24 @@ function createCommentVNode(text = '', // block to ensure correct updates. asBlock = false) { return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); + ? (openBlock(), createBlock(Comment$1, null, text)) + : createVNode(Comment$1, null, text); } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder - return createVNode(Comment); + return createVNode(Comment$1); } else if (isArray(child)) { // fragment - return createVNode(Fragment, null, child); + return createVNode(Fragment, null, + // #3666, avoid reference pollution when reusing vnode + child.slice()); } else if (typeof child === 'object') { // already vnode, this should be the most common since compiled templates // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + return cloneIfMounted(child); } else { // strings and numbers @@ -9194,7 +9190,7 @@ function ensureValidVNode(vnodes) { return vnodes.some(child => { if (!isVNode(child)) return true; - if (child.type === Comment) + if (child.type === Comment$1) return false; if (child.type === Fragment && !ensureValidVNode(child.children)) @@ -9400,16 +9396,6 @@ function installCompatInstanceProperties(map) { extend(map, { // needed by many libs / render fns $vnode: i => i.vnode, - // inject addtional properties into $options for compat - // e.g. vuex needs this.$options.parent - $options: i => { - let res = resolveMergedOptions(i); - if (res === i.type) - res = i.type.__merged = extend({}, res); - res.parent = i.proxy.$parent; - res.propsData = i.vnode.props; - return res; - }, // some private properties that are likely accessed... _self: i => i.proxy, _uid: i => i.uid, @@ -9737,6 +9723,8 @@ function createComponentInstance(vnode, parent, suspense) { emitted: null, // props default value propsDefaults: EMPTY_OBJ, + // inheritAttrs + inheritAttrs: type.inheritAttrs, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, @@ -9977,7 +9965,7 @@ function finishComponentSetup(instance, isSSR, skipOptions) { if (!(skipOptions)) { currentInstance = instance; pauseTracking(); - applyOptions(instance, Component); + applyOptions(instance); resetTracking(); currentInstance = null; } @@ -10339,7 +10327,7 @@ function initCustomFormatter() { } // Core API ------------------------------------------------------------------ -const version = "3.1.0-beta.5"; +const version = "3.1.0-beta.7"; const _ssrUtils = { createComponentInstance, setupComponent, @@ -10630,6 +10618,9 @@ prevChildren, parentComponent, parentSuspense, unmountChildren) { if (el.value !== newValue) { el.value = newValue; } + if (value == null) { + el.removeAttribute(key); + } return; } if (value === '' || value == null) { @@ -10954,6 +10945,29 @@ const DOMTransitionPropsValidators = { leaveToClass: String }; const TransitionPropsValidators = (Transition.props = /*#__PURE__*/ extend({}, BaseTransition.props, DOMTransitionPropsValidators)); +/** + * #3227 Incoming hooks may be merged into arrays when wrapping Transition + * with custom HOCs. + */ +const callHook$1 = (hook, args = []) => { + if (isArray(hook)) { + hook.forEach(h => h(...args)); + } + else if (hook) { + hook(...args); + } +}; +/** + * Check if a hook expects a callback (2nd arg), which means the user + * intends to explicitly control the end of the transition. + */ +const hasExplicitCallback = (hook) => { + return hook + ? isArray(hook) + ? hook.some(h => h.length > 1) + : hook.length > 1 + : false; +}; function resolveTransitionProps(rawProps) { const baseProps = {}; for (const key in rawProps) { @@ -11000,14 +11014,14 @@ function resolveTransitionProps(rawProps) { return (el, done) => { const hook = isAppear ? onAppear : onEnter; const resolve = () => finishEnter(el, isAppear, done); - hook && hook(el, resolve); + callHook$1(hook, [el, resolve]); nextFrame(() => { removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass); if (legacyClassEnabled) { removeTransitionClass(el, isAppear ? legacyAppearFromClass : legacyEnterFromClass); } addTransitionClass(el, isAppear ? appearToClass : enterToClass); - if (!(hook && hook.length > 1)) { + if (!hasExplicitCallback(hook)) { whenTransitionEnds(el, type, enterDuration, resolve); } }); @@ -11015,7 +11029,7 @@ function resolveTransitionProps(rawProps) { }; return extend(baseProps, { onBeforeEnter(el) { - onBeforeEnter && onBeforeEnter(el); + callHook$1(onBeforeEnter, [el]); addTransitionClass(el, enterFromClass); if (legacyClassEnabled) { addTransitionClass(el, legacyEnterFromClass); @@ -11023,7 +11037,7 @@ function resolveTransitionProps(rawProps) { addTransitionClass(el, enterActiveClass); }, onBeforeAppear(el) { - onBeforeAppear && onBeforeAppear(el); + callHook$1(onBeforeAppear, [el]); addTransitionClass(el, appearFromClass); if (legacyClassEnabled) { addTransitionClass(el, legacyAppearFromClass); @@ -11047,23 +11061,23 @@ function resolveTransitionProps(rawProps) { removeTransitionClass(el, legacyLeaveFromClass); } addTransitionClass(el, leaveToClass); - if (!(onLeave && onLeave.length > 1)) { + if (!hasExplicitCallback(onLeave)) { whenTransitionEnds(el, type, leaveDuration, resolve); } }); - onLeave && onLeave(el, resolve); + callHook$1(onLeave, [el, resolve]); }, onEnterCancelled(el) { finishEnter(el, false); - onEnterCancelled && onEnterCancelled(el); + callHook$1(onEnterCancelled, [el]); }, onAppearCancelled(el) { finishEnter(el, true); - onAppearCancelled && onAppearCancelled(el); + callHook$1(onAppearCancelled, [el]); }, onLeaveCancelled(el) { finishLeave(el); - onLeaveCancelled && onLeaveCancelled(el); + callHook$1(onLeaveCancelled, [el]); } }); } @@ -11535,12 +11549,13 @@ function setSelected(el, value) { } else { if (looseEqual(getValue(option), value)) { - el.selectedIndex = i; + if (el.selectedIndex !== i) + el.selectedIndex = i; return; } } } - if (!isMultiple) { + if (!isMultiple && el.selectedIndex !== -1) { el.selectedIndex = -1; } } @@ -11953,7 +11968,7 @@ var runtimeDom = /*#__PURE__*/Object.freeze({ isVNode: isVNode, Fragment: Fragment, Text: Text, - Comment: Comment, + Comment: Comment$1, Static: Static, Teleport: Teleport, Suspense: Suspense, diff --git a/packages/uni-h5-vue/dist/vue.runtime.compat.esm.js b/packages/uni-h5-vue/dist/vue.runtime.compat.esm.js index e21abab03..1b9dd8273 100644 --- a/packages/uni-h5-vue/dist/vue.runtime.compat.esm.js +++ b/packages/uni-h5-vue/dist/vue.runtime.compat.esm.js @@ -332,7 +332,7 @@ let uid = 0; function createReactiveEffect(fn, options) { const effect = function reactiveEffect() { if (!effect.active) { - return options.scheduler ? undefined : fn(); + return fn(); } if (!effectStack.includes(effect)) { cleanup(effect); @@ -1566,7 +1566,7 @@ function flushJobs(seen) { try { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex]; - if (job) { + if (job && job.active !== false) { if ((process.env.NODE_ENV !== 'production') && checkRecursiveUpdates(seen, job)) { continue; } @@ -1749,7 +1749,7 @@ function devtoolsInitApp(app, version) { devtools.emit("app:init" /* APP_INIT */, app, version, { Fragment, Text, - Comment, + Comment: Comment$1, Static }); } @@ -2082,7 +2082,7 @@ function warnDeprecation(key, instance, ...args) { warnCount[dupKey] = 0; const { message, link } = deprecationData[key]; warn(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`); - if (!isCompatEnabled(key, instance)) { + if (!isCompatEnabled(key, instance, true)) { console.error(`^ The above deprecation's compat behavior is disabled and will likely ` + `lead to runtime errors.`); } @@ -2099,7 +2099,7 @@ function configureCompat(config) { const seenConfigObjects = /*#__PURE__*/ new WeakSet(); const warnedInvalidKeys = {}; // dev only -function validateCompatConfig(config) { +function validateCompatConfig(config, instance) { if (seenConfigObjects.has(config)) { return; } @@ -2123,6 +2123,9 @@ function validateCompatConfig(config) { warnedInvalidKeys[key] = true; } } + if (instance && config["OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */] != null) { + warn(`Deprecation config "${"OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */}" can only be configured globally.`); + } } function getCompatConfigForKey(key, instance) { const instanceConfig = instance && instance.type.compatConfig; @@ -2373,8 +2376,10 @@ function emit$1(instance, event, ...rawArgs) { } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__emits !== undefined) { - return comp.__emits; + const cache = appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== undefined) { + return cached; } const raw = comp.emits; let normalized = {}; @@ -2399,7 +2404,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__emits = null); + cache.set(comp, null); + return null; } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -2407,7 +2413,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (comp.__emits = normalized); + cache.set(comp, normalized); + return normalized; } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -2528,7 +2535,7 @@ function markAttrsAccessed() { accessedAttrs = true; } function renderComponentRoot(instance) { - const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx } = instance; + const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance; let result; const prev = setCurrentRenderingInstance(instance); if ((process.env.NODE_ENV !== 'production')) { @@ -2577,7 +2584,7 @@ function renderComponentRoot(instance) { ; [root, setRoot] = getChildRoot(result); } - if (fallthroughAttrs && Component.inheritAttrs !== false) { + if (fallthroughAttrs && inheritAttrs !== false) { const keys = Object.keys(fallthroughAttrs); const { shapeFlag } = root; if (keys.length) { @@ -2592,7 +2599,7 @@ function renderComponentRoot(instance) { } root = cloneVNode(root, fallthroughAttrs); } - else if ((process.env.NODE_ENV !== 'production') && !accessedAttrs && root.type !== Comment) { + else if ((process.env.NODE_ENV !== 'production') && !accessedAttrs && root.type !== Comment$1) { const allAttrs = Object.keys(attrs); const eventAttrs = []; const extraAttrs = []; @@ -2634,7 +2641,7 @@ function renderComponentRoot(instance) { root.shapeFlag & 6 /* COMPONENT */)) { const { class: cls, style } = vnode.props || {}; if (cls || style) { - if ((process.env.NODE_ENV !== 'production') && Component.inheritAttrs === false) { + if ((process.env.NODE_ENV !== 'production') && inheritAttrs === false) { warnDeprecation("INSTANCE_ATTRS_CLASS_STYLE" /* INSTANCE_ATTRS_CLASS_STYLE */, instance, getComponentName(instance.type)); } root = cloneVNode(root, { @@ -2669,7 +2676,7 @@ function renderComponentRoot(instance) { catch (err) { blockStack.length = 0; handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment); + result = createVNode(Comment$1); } setCurrentRenderingInstance(prev); return result; @@ -2708,7 +2715,7 @@ function filterSingleRoot(children) { const child = children[i]; if (isVNode(child)) { // ignore user comment - if (child.type !== Comment || child.children === 'v-if') { + if (child.type !== Comment$1 || child.children === 'v-if') { if (singleRoot) { // has more than 1 non-comment child, return now return; @@ -2745,7 +2752,7 @@ const filterModelListeners = (attrs, props) => { const isElementRoot = (vnode) => { return (vnode.shapeFlag & 6 /* COMPONENT */ || vnode.shapeFlag & 1 /* ELEMENT */ || - vnode.type === Comment // potential v-if branch switch + vnode.type === Comment$1 // potential v-if branch switch ); }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { @@ -2851,7 +2858,8 @@ const SuspenseImpl = { } }, hydrate: hydrateSuspense, - create: createSuspenseBoundary + create: createSuspenseBoundary, + normalize: normalizeSuspenseChildren }; // Force-casted public typing for h and TSX props inference const Suspense = (SuspenseImpl @@ -3196,24 +3204,29 @@ function hydrateSuspense(node, vnode, parentComponent, parentSuspense, isSVG, sl } function normalizeSuspenseChildren(vnode) { const { shapeFlag, children } = vnode; - let content; - let fallback; - if (shapeFlag & 32 /* SLOTS_CHILDREN */) { - content = normalizeSuspenseSlot(children.default); - fallback = normalizeSuspenseSlot(children.fallback); - } - else { - content = normalizeSuspenseSlot(children); - fallback = normalizeVNode(null); - } - return { - content, - fallback - }; + const isSlotChildren = shapeFlag & 32 /* SLOTS_CHILDREN */; + vnode.ssContent = normalizeSuspenseSlot(isSlotChildren ? children.default : children); + vnode.ssFallback = isSlotChildren + ? normalizeSuspenseSlot(children.fallback) + : createVNode(Comment); } function normalizeSuspenseSlot(s) { + let block; if (isFunction(s)) { + const isCompiledSlot = s._c; + if (isCompiledSlot) { + // disableTracking: false + // allow block tracking for compiled slots + // (see ./componentRenderContext.ts) + s._d = false; + openBlock(); + } s = s(); + if (isCompiledSlot) { + s._d = true; + block = currentBlock; + closeBlock(); + } } if (isArray(s)) { const singleChild = filterSingleRoot(s); @@ -3222,7 +3235,11 @@ function normalizeSuspenseSlot(s) { } s = singleChild; } - return normalizeVNode(s); + s = normalizeVNode(s); + if (block) { + s.dynamicChildren = block.filter(c => c !== s); + } + return s; } function queueEffectWithSuspense(fn, suspense) { if (suspense && suspense.pendingBranch) { @@ -3440,7 +3457,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM job.allowRecurse = !!cb; let scheduler; if (flush === 'sync') { - scheduler = job; + scheduler = job; // the scheduler function gets called directly } else if (flush === 'post') { scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); @@ -3516,7 +3533,9 @@ function createPathGetter(ctx, path) { }; } function traverse(value, seen = new Set()) { - if (!isObject(value) || seen.has(value)) { + if (!isObject(value) || + seen.has(value) || + value["__v_skip" /* SKIP */]) { return value; } seen.add(value); @@ -3630,7 +3649,7 @@ const BaseTransitionImpl = { } // handle mode if (oldInnerChild && - oldInnerChild.type !== Comment && + oldInnerChild.type !== Comment$1 && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { const leavingHooks = resolveTransitionHooks(oldInnerChild, rawProps, state, instance); // update old tree's hooks in case of dynamic transition @@ -3645,7 +3664,7 @@ const BaseTransitionImpl = { }; return emptyPlaceholder(child); } - else if (mode === 'in-out' && innerChild.type !== Comment) { + else if (mode === 'in-out' && innerChild.type !== Comment$1) { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType(state, oldInnerChild); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; @@ -3840,7 +3859,7 @@ function getTransitionRawChildren(children, keepComment = false) { ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if - else if (keepComment || child.type !== Comment) { + else if (keepComment || child.type !== Comment$1) { ret.push(child); } } @@ -4416,107 +4435,19 @@ function onErrorCaptured(hook, target = currentInstance) { injectHook("ec" /* ERROR_CAPTURED */, hook, target); } -function deepMergeData(to, from, instance) { +function deepMergeData(to, from) { for (const key in from) { const toVal = to[key]; const fromVal = from[key]; if (key in to && isPlainObject(toVal) && isPlainObject(fromVal)) { - (process.env.NODE_ENV !== 'production') && - warnDeprecation("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, instance, key); - deepMergeData(toVal, fromVal, instance); + (process.env.NODE_ENV !== 'production') && warnDeprecation("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, null, key); + deepMergeData(toVal, fromVal); } else { to[key] = fromVal; } } -} -function mergeDataOption(to, from) { - if (!from) { - return to; - } - if (!to) { - return from; - } - return function mergedDataFn() { - return deepMergeData(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from, this.$); - }; -} - -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -const FILTERS = 'filters'; -/** - * @private - */ -function resolveComponent(name, maybeSelfReference) { - return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; -} -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; - } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); - } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -/** - * v2 compat only - * @internal - */ -function resolveFilter(name) { - return resolveAsset(FILTERS, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // explicit self name has highest priority - if (type === COMPONENTS) { - const selfName = getComponentName(Component); - if (selfName && - (selfName === name || - selfName === camelize(name) || - selfName === capitalize(camelize(name)))) { - return Component; - } - } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if (!res && maybeSelfReference) { - // fallback to implicit self-reference - return Component; - } - if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); - } - return res; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`resolve${capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); - } -} -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[camelize(name)] || - registry[capitalize(camelize(name))])); + return to; } function createDuplicateChecker() { @@ -4531,47 +4462,32 @@ function createDuplicateChecker() { }; } let shouldCacheAccess = true; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { - if (isFunction(options)) { - options = options.options; - } - const { - // composition - mixins, extends: extendsOptions, - // state - data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, - // lifecycle - beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, - // public API - expose } = options; +function applyOptions(instance) { + const options = resolveMergedOptions(instance); const publicThis = instance.proxy; const ctx = instance.ctx; - const globalMixins = instance.appContext.mixins; - if (asMixin && render && instance.render === NOOP) { - instance.render = render; - } // fixed by xxxxxx const customApplyOptions = instance.appContext.config.globalProperties .$applyOptions; if (customApplyOptions) { customApplyOptions(options, instance, publicThis); } - // applyOptions is called non-as-mixin once per instance - if (!asMixin) { - shouldCacheAccess = false; - callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); - shouldCacheAccess = true; - // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); - } - // extending a base component... - if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); - } - // local mixins - if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); + // do not cache property access on public proxy during state initialization + shouldCacheAccess = false; + // call beforeCreate first before accessing other options since + // the hook may mutate resolved options (#2791) + if (options.beforeCreate) { + callHook(options.beforeCreate, instance, "bc" /* BEFORE_CREATE */); } + const { + // state + data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, + // lifecycle + created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, + // public API + expose, inheritAttrs, + // assets + components, directives, filters } = options; const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { const [propsOptions] = instance.propsOptions; @@ -4618,33 +4534,40 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } - if (!asMixin) { - if (deferredData.length) { - deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)); + if (dataOptions) { + if ((process.env.NODE_ENV !== 'production') && !isFunction(dataOptions)) { + warn(`The data option must be a function. ` + + `Plain object usage is no longer supported.`); } - if (dataOptions) { - // @ts-ignore dataOptions is not fully type safe - resolveData(instance, dataOptions, publicThis); + const data = dataOptions.call(publicThis, publicThis); + if ((process.env.NODE_ENV !== 'production') && isPromise(data)) { + warn(`data() returned a Promise - note data() cannot be async; If you ` + + `intend to perform data fetching before component renders, use ` + + `async setup() + .`); } - if ((process.env.NODE_ENV !== 'production')) { - const rawData = toRaw(instance.data); - for (const key in rawData) { - checkDuplicateProperties("Data" /* DATA */, key); - // expose data on ctx during dev - if (key[0] !== '$' && key[0] !== '_') { - Object.defineProperty(ctx, key, { - configurable: true, - enumerable: true, - get: () => rawData[key], - set: NOOP - }); + if (!isObject(data)) { + (process.env.NODE_ENV !== 'production') && warn(`data() should return an object.`); + } + else { + instance.data = reactive(data); + if ((process.env.NODE_ENV !== 'production')) { + for (const key in data) { + checkDuplicateProperties("Data" /* DATA */, key); + // expose data on ctx during dev + if (key[0] !== '$' && key[0] !== '_') { + Object.defineProperty(ctx, key, { + configurable: true, + enumerable: true, + get: () => data[key], + set: NOOP + }); + } } } } } - else if (dataOptions) { - deferredData.push(dataOptions); - } + // state initialization complete at this point - start caching access + shouldCacheAccess = true; if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key]; @@ -4679,44 +4602,22 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (watchOptions) { - deferredWatch.push(watchOptions); - } - if (!asMixin && deferredWatch.length) { - deferredWatch.forEach(watchOptions => { - for (const key in watchOptions) { - createWatcher(watchOptions[key], ctx, publicThis, key); - } - }); + for (const key in watchOptions) { + createWatcher(watchOptions[key], ctx, publicThis, key); + } } if (provideOptions) { - deferredProvide.push(provideOptions); - } - if (!asMixin && deferredProvide.length) { - deferredProvide.forEach(provideOptions => { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - Reflect.ownKeys(provides).forEach(key => { - provide(key, provides[key]); - }); + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + Reflect.ownKeys(provides).forEach(key => { + provide(key, provides[key]); }); } - // asset options. - // To reduce memory usage, only components with mixins or extends will have - // resolved asset registry attached to instance. - if (asMixin) { - resolveInstanceAssets(instance, options, COMPONENTS); - resolveInstanceAssets(instance, options, DIRECTIVES); - if (isCompatEnabled("FILTERS" /* FILTERS */, instance)) { - resolveInstanceAssets(instance, options, FILTERS); - } - } - // lifecycle options - if (!asMixin) { - callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); + if (created) { + callHook(created, instance, "c" /* CREATED */); } function registerLifecycleHook(register, hook) { - // Array lifecycle hooks are only present in the compat build if (isArray(hook)) { hook.forEach(_hook => register(_hook.bind(publicThis))); } @@ -4747,110 +4648,61 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (isArray(expose)) { - if (!asMixin) { - if (expose.length) { - const exposed = instance.exposed || (instance.exposed = proxyRefs({})); - expose.forEach(key => { - exposed[key] = toRef(publicThis, key); - }); - } - else if (!instance.exposed) { - instance.exposed = EMPTY_OBJ; - } + if (expose.length) { + const exposed = instance.exposed || (instance.exposed = proxyRefs({})); + expose.forEach(key => { + exposed[key] = toRef(publicThis, key); + }); } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`The \`expose\` option is ignored when used in mixins.`); + else if (!instance.exposed) { + instance.exposed = EMPTY_OBJ; } } -} -function resolveInstanceAssets(instance, mixin, type) { - if (mixin[type]) { - extend(instance[type] || - (instance[type] = extend({}, instance.type[type])), mixin[type]); + // options that are handled when creating the instance but also need to be + // applied from mixins + if (render && instance.render === NOOP) { + instance.render = render; + } + if (inheritAttrs != null) { + instance.inheritAttrs = inheritAttrs; + } + // asset options. + if (components) + instance.components = components; + if (directives) + instance.directives = directives; + if (filters && + isCompatEnabled("FILTERS" /* FILTERS */, instance)) { + instance.filters = filters; } } function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) { if (isArray(injectOptions)) { - for (let i = 0; i < injectOptions.length; i++) { - const key = injectOptions[i]; - ctx[key] = inject(key); - if ((process.env.NODE_ENV !== 'production')) { - checkDuplicateProperties("Inject" /* INJECT */, key); - } - } + injectOptions = normalizeInject(injectOptions); } - else { - for (const key in injectOptions) { - const opt = injectOptions[key]; - if (isObject(opt)) { + for (const key in injectOptions) { + const opt = injectOptions[key]; + if (isObject(opt)) { + if ('default' in opt) { ctx[key] = inject(opt.from || key, opt.default, true /* treat default function as factory */); } else { - ctx[key] = inject(opt); - } - if ((process.env.NODE_ENV !== 'production')) { - checkDuplicateProperties("Inject" /* INJECT */, key); + ctx[key] = inject(opt.from || key); } } - } -} -function callSyncHook(name, type, options, instance, globalMixins) { - for (let i = 0; i < globalMixins.length; i++) { - callHookWithMixinAndExtends(name, type, globalMixins[i], instance); - } - callHookWithMixinAndExtends(name, type, options, instance); -} -function callHookWithMixinAndExtends(name, type, options, instance) { - const { extends: base, mixins } = options; - const selfHook = options[name]; - if (base) { - callHookWithMixinAndExtends(name, type, base, instance); - } - if (mixins) { - for (let i = 0; i < mixins.length; i++) { - callHookWithMixinAndExtends(name, type, mixins[i], instance); - } - } - if (selfHook) { - callWithAsyncErrorHandling(isArray(selfHook) - ? selfHook.map(h => h.bind(instance.proxy)) - : selfHook.bind(instance.proxy), instance, type); - } -} -function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { - for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); - } -} -function resolveData(instance, dataFn, publicThis) { - if ((process.env.NODE_ENV !== 'production') && !isFunction(dataFn)) { - warn(`The data option must be a function. ` + - `Plain object usage is no longer supported.`); - } - shouldCacheAccess = false; - const data = dataFn.call(publicThis, publicThis); - shouldCacheAccess = true; - if ((process.env.NODE_ENV !== 'production') && isPromise(data)) { - warn(`data() returned a Promise - note data() cannot be async; If you ` + - `intend to perform data fetching before component renders, use ` + - `async setup() + .`); - } - if (!isObject(data)) { - (process.env.NODE_ENV !== 'production') && warn(`data() should return an object.`); - } - else if (instance.data === EMPTY_OBJ) { - instance.data = reactive(data); - } - else { - // existing data: this is a mixin or extends. - if (isCompatEnabled("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, instance)) { - deepMergeData(instance.data, data, instance); - } else { - extend(instance.data, data); + ctx[key] = inject(opt); + } + if ((process.env.NODE_ENV !== 'production')) { + checkDuplicateProperties("Inject" /* INJECT */, key); } } } +function callHook(hook, instance, type) { + callWithAsyncErrorHandling(isArray(hook) + ? hook.map(h => h.bind(instance.proxy)) + : hook.bind(instance.proxy), instance, type); +} function createWatcher(raw, ctx, publicThis, key) { const getter = key.includes('.') ? createPathGetter(publicThis, key) @@ -4887,36 +4739,129 @@ function createWatcher(raw, ctx, publicThis, key) { warn(`Invalid watch option: "${key}"`, raw); } } +/** + * Resolve merged options and cache it on the component. + * This is done only once per-component since the merging does not involve + * instances. + */ function resolveMergedOptions(instance) { - const raw = instance.type; - const { __merged, mixins, extends: extendsOptions } = raw; - if (__merged) - return __merged; - const globalMixins = instance.appContext.mixins; - if (!globalMixins.length && !mixins && !extendsOptions) - return raw; - const options = {}; - globalMixins.forEach(m => mergeOptions(options, m, instance)); - mergeOptions(options, raw, instance); - return (raw.__merged = options); -} -function mergeOptions(to, from, instance, strats = instance && instance.appContext.config.optionMergeStrategies) { + const base = instance.type; + const { mixins, extends: extendsOptions } = base; + const { mixins: globalMixins, optionsCache: cache, config: { optionMergeStrategies } } = instance.appContext; + const cached = cache.get(base); + let resolved; + if (cached) { + resolved = cached; + } + else if (!globalMixins.length && !mixins && !extendsOptions) { + if (isCompatEnabled("PRIVATE_APIS" /* PRIVATE_APIS */, instance)) { + resolved = extend({}, base); + resolved.parent = instance.parent && instance.parent.proxy; + resolved.propsData = instance.vnode.props; + } + else { + resolved = base; + } + } + else { + resolved = {}; + if (globalMixins.length) { + globalMixins.forEach(m => mergeOptions(resolved, m, optionMergeStrategies, true)); + } + mergeOptions(resolved, base, optionMergeStrategies); + } + cache.set(base, resolved); + return resolved; +} +function mergeOptions(to, from, strats, asMixin = false) { if (isFunction(from)) { from = from.options; } const { mixins, extends: extendsOptions } = from; - extendsOptions && mergeOptions(to, extendsOptions, instance, strats); - mixins && - mixins.forEach((m) => mergeOptions(to, m, instance, strats)); + if (extendsOptions) { + mergeOptions(to, extendsOptions, strats, true); + } + if (mixins) { + mixins.forEach((m) => mergeOptions(to, m, strats, true)); + } for (const key in from) { - if (strats && hasOwn(strats, key)) { - to[key] = strats[key](to[key], from[key], instance && instance.proxy, key); + if (asMixin && key === 'expose') { + (process.env.NODE_ENV !== 'production') && + warn(`"expose" option is ignored when declared in mixins or extends. ` + + `It should only be declared in the base component itself.`); } else { - to[key] = from[key]; + const strat = internalOptionMergeStrats[key] || (strats && strats[key]); + to[key] = strat ? strat(to[key], from[key]) : from[key]; } } return to; +} +const internalOptionMergeStrats = { + data: mergeDataFn, + props: mergeObjectOptions, + emits: mergeObjectOptions, + // objects + methods: mergeObjectOptions, + computed: mergeObjectOptions, + // lifecycle + beforeCreate: mergeHook, + created: mergeHook, + beforeMount: mergeHook, + mounted: mergeHook, + beforeUpdate: mergeHook, + updated: mergeHook, + beforeDestroy: mergeHook, + destroyed: mergeHook, + activated: mergeHook, + deactivated: mergeHook, + errorCaptured: mergeHook, + serverPrefetch: mergeHook, + // assets + components: mergeObjectOptions, + directives: mergeObjectOptions, + // watch has special merge behavior in v2, but isn't actually needed in v3. + // since we are only exposing these for compat and nobody should be relying + // on the watch-specific behavior, just expose the object merge strat. + watch: mergeObjectOptions, + // provide / inject + provide: mergeDataFn, + inject: mergeInject +}; +{ + internalOptionMergeStrats.filters = mergeObjectOptions; +} +function mergeDataFn(to, from) { + if (!from) { + return to; + } + if (!to) { + return from; + } + return function mergedDataFn() { + return (isCompatEnabled("OPTIONS_DATA_MERGE" /* OPTIONS_DATA_MERGE */, null) + ? deepMergeData + : extend)(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from); + }; +} +function mergeInject(to, from) { + return mergeObjectOptions(normalizeInject(to), normalizeInject(from)); +} +function normalizeInject(raw) { + if (isArray(raw)) { + const res = {}; + for (let i = 0; i < raw.length; i++) { + res[raw[i]] = raw[i]; + } + return res; + } + return raw; +} +function mergeHook(to, from) { + return to ? [...new Set([].concat(to, from))] : from; +} +function mergeObjectOptions(to, from) { + return to ? extend(extend(Object.create(null), to), from) : from; } function createPropsDefaultThis(instance, rawProps, propKey) { @@ -5198,8 +5143,10 @@ function resolvePropValue(options, props, key, value, instance, isAbsent) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__props) { - return comp.__props; + const cache = appContext.propsCache; + const cached = cache.get(comp); + if (cached) { + return cached; } const raw = comp.props; const normalized = {}; @@ -5228,7 +5175,8 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__props = EMPTY_ARR); + cache.set(comp, EMPTY_ARR); + return EMPTY_ARR; } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -5265,7 +5213,9 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (comp.__props = [normalized, needCastKeys]); + const res = [normalized, needCastKeys]; + cache.set(comp, res); + return res; } function validatePropName(key) { if (key[0] !== '$') { @@ -5632,12 +5582,16 @@ function invokeDirectiveHook(vnode, prevVNode, instance, name) { hook = mapCompatDirectiveHook(name, binding.dir, instance); } if (hook) { + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ vnode.el, binding, vnode, prevVNode ]); + resetTracking(); } } } @@ -5673,49 +5627,12 @@ function installLegacyOptionMergeStrats(config) { if (key in target) { return target[key]; } - if (key in legacyOptionMergeStrats && + if (key in internalOptionMergeStrats && softAssertCompatEnabled("CONFIG_OPTION_MERGE_STRATS" /* CONFIG_OPTION_MERGE_STRATS */, null)) { - return legacyOptionMergeStrats[key]; + return internalOptionMergeStrats[key]; } } }); -} -const legacyOptionMergeStrats = { - data: mergeDataOption, - beforeCreate: mergeHook, - created: mergeHook, - beforeMount: mergeHook, - mounted: mergeHook, - beforeUpdate: mergeHook, - updated: mergeHook, - beforeDestroy: mergeHook, - destroyed: mergeHook, - activated: mergeHook, - deactivated: mergeHook, - errorCaptured: mergeHook, - serverPrefetch: mergeHook, - // assets - components: mergeObjectOptions, - directives: mergeObjectOptions, - filters: mergeObjectOptions, - // objects - props: mergeObjectOptions, - methods: mergeObjectOptions, - inject: mergeObjectOptions, - computed: mergeObjectOptions, - // watch has special merge behavior in v2, but isn't actually needed in v3. - // since we are only exposing these for compat and nobody should be relying - // on the watch-specific behavior, just expose the object merge strat. - watch: mergeObjectOptions -}; -function toArray(target) { - return isArray(target) ? target : target ? [target] : []; -} -function mergeHook(to, from) { - return Array.from(new Set([...toArray(to), ...toArray(from)])); -} -function mergeObjectOptions(to, from) { - return to ? extend(extend(Object.create(null), to), from) : from; } let isCopyingConfig = false; @@ -5748,7 +5665,7 @@ function createCompatVue(createApp, createSingletonApp) { return vm; } } - Vue.version = "3.1.0-beta.5"; + Vue.version = "3.1.0-beta.7"; Vue.config = singletonApp.config; Vue.use = (p, ...options) => { if (p && isFunction(p.install)) { @@ -5800,7 +5717,7 @@ function createCompatVue(createApp, createSingletonApp) { return createCompatApp(SubVue.options, SubVue); } else { - return createCompatApp(mergeOptions(extend({}, SubVue.options), inlineOptions, null, legacyOptionMergeStrats), SubVue); + return createCompatApp(mergeOptions(extend({}, SubVue.options), inlineOptions, internalOptionMergeStrats), SubVue); } } SubVue.super = Super; @@ -5817,7 +5734,7 @@ function createCompatVue(createApp, createSingletonApp) { ? extend(Object.create(null), superValue) : superValue; } - SubVue.options = mergeOptions(mergeBase, extendOptions, null, legacyOptionMergeStrats); + SubVue.options = mergeOptions(mergeBase, extendOptions, internalOptionMergeStrats); SubVue.options._base = SubVue; SubVue.extend = extendCtor.bind(SubVue); SubVue.mixin = Super.mixin; @@ -5852,7 +5769,7 @@ function createCompatVue(createApp, createSingletonApp) { const util = { warn: (process.env.NODE_ENV !== 'production') ? warn : NOOP, extend, - mergeOptions: (parent, child, vm) => mergeOptions(parent, child, vm && vm.$, vm ? undefined : legacyOptionMergeStrats), + mergeOptions: (parent, child, vm) => mergeOptions(parent, child, vm ? undefined : internalOptionMergeStrats), defineReactive }; Object.defineProperty(Vue, 'util', { @@ -5986,6 +5903,7 @@ function installCompatMount(app, context, render) { } setupComponent(instance); vnode.component = instance; + vnode.isCompatRoot = true; // $mount & $destroy // these are defined on ctx and picked up by the $mount/$destroy // public property getters on the instance proxy. @@ -6169,7 +6087,10 @@ function createAppContext() { mixins: [], components: {}, directives: {}, - provides: Object.create(null) + provides: Object.create(null), + optionsCache: new WeakMap(), + propsCache: new WeakMap(), + emitsCache: new WeakMap() }; } let uid$1 = 0; @@ -6219,11 +6140,6 @@ function createAppAPI(render, hydrate) { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); - // global mixin with props/emits de-optimizes props/emits - // normalization caching. - if (mixin.props || mixin.emits) { - context.deopt = true; - } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -6373,7 +6289,7 @@ function createHydrationFunctions(rendererInternals) { nextNode = nextSibling(node); } break; - case Comment: + case Comment$1: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } @@ -6892,7 +6808,7 @@ function baseCreateRenderer(options, createHydrationFns) { case Text: processText(n1, n2, container, anchor); break; - case Comment: + case Comment$1: processCommentNode(n1, n2, container, anchor); break; case Static: @@ -7198,15 +7114,18 @@ function baseCreateRenderer(options, createHydrationFns) { const newVNode = newChildren[i]; // Determine the container (parent element) for the patch. const container = - // - In the case of a Fragment, we need to provide the actual parent - // of the Fragment itself so it can move its children. - oldVNode.type === Fragment || - // - In the case of different nodes, there is going to be a replacement - // which also requires the correct parent container - !isSameVNodeType(oldVNode, newVNode) || - // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & 6 /* COMPONENT */ || - oldVNode.shapeFlag & 64 /* TELEPORT */ + // oldVNode may be an errored async setup() component inside Suspense + // which will not have a mounted element + oldVNode.el && + // - In the case of a Fragment, we need to provide the actual parent + // of the Fragment itself so it can move its children. + (oldVNode.type === Fragment || + // - In the case of different nodes, there is going to be a replacement + // which also requires the correct parent container + !isSameVNodeType(oldVNode, newVNode) || + // - In the case of a component, it could contain anything. + oldVNode.shapeFlag & 6 /* COMPONENT */ || + oldVNode.shapeFlag & 64 /* TELEPORT */) ? hostParentNode(oldVNode.el) : // In other cases, the parent container is not actually used so we // just pass the block element here to avoid a DOM parentNode call. @@ -7312,7 +7231,7 @@ function baseCreateRenderer(options, createHydrationFns) { const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { // 2.x compat may pre-creaate the component instance before actually // mounting - const compatMountInstance = initialVNode.component; + const compatMountInstance = initialVNode.isCompatRoot && initialVNode.component; const instance = compatMountInstance || (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense)); if ((process.env.NODE_ENV !== 'production') && instance.type.__hmrId) { @@ -7343,7 +7262,7 @@ function baseCreateRenderer(options, createHydrationFns) { // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { - const placeholder = (instance.subTree = createVNode(Comment)); + const placeholder = (instance.subTree = createVNode(Comment$1)); processCommentNode(null, placeholder, container, anchor); } return; @@ -8115,7 +8034,7 @@ function traverseStaticChildren(n1, n2, shallow = false) { } // also inherit for comment nodes, but not placeholders (e.g. v-if which // would have received .el during block patch) - if ((process.env.NODE_ENV !== 'production') && c2.type === Comment && !c2.el) { + if ((process.env.NODE_ENV !== 'production') && c2.type === Comment$1 && !c2.el) { c2.el = c1.el; } } @@ -8358,6 +8277,83 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope // Force-casted public typing for h and TSX props inference const Teleport = TeleportImpl; +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +const FILTERS = 'filters'; +/** + * @private + */ +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +/** + * v2 compat only + * @internal + */ +function resolveFilter(name) { + return resolveAsset(FILTERS, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // explicit self name has highest priority + if (type === COMPONENTS) { + const selfName = getComponentName(Component); + if (selfName && + (selfName === name || + selfName === camelize(name) || + selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if (!res && maybeSelfReference) { + // fallback to implicit self-reference + return Component; + } + if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`resolve${capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[camelize(name)] || + registry[capitalize(camelize(name))])); +} + const normalizedAsyncComponentMap = new Map(); function convertLegacyAsyncComponent(comp) { if (normalizedAsyncComponentMap.has(comp)) { @@ -8434,7 +8430,7 @@ function convertLegacyRenderFn(instance) { } function compatH(type, propsOrChildren, children) { if (!type) { - type = Comment; + type = Comment$1; } // to support v2 string component name look!up if (typeof type === 'string') { @@ -8686,7 +8682,7 @@ function convertLegacyComponent(comp, instance) { const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); -const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); +const Comment$1 = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); // Since v-if and v-for are the two possible ways node structure can dynamically // change, once we consider v-if branches and each v-for fragment a block, we @@ -8807,7 +8803,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami if ((process.env.NODE_ENV !== 'production') && !type) { warn(`Invalid vnode type when creating vnode: ${type}.`); } - type = Comment; + type = Comment$1; } if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like @@ -8899,9 +8895,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami normalizeChildren(vnode, children); // normalize suspense children if (shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + type.normalize(vnode); } if (isBlockTreeEnabled > 0 && // avoid a block node from tracking itself @@ -9020,22 +9014,24 @@ function createCommentVNode(text = '', // block to ensure correct updates. asBlock = false) { return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); + ? (openBlock(), createBlock(Comment$1, null, text)) + : createVNode(Comment$1, null, text); } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder - return createVNode(Comment); + return createVNode(Comment$1); } else if (isArray(child)) { // fragment - return createVNode(Fragment, null, child); + return createVNode(Fragment, null, + // #3666, avoid reference pollution when reusing vnode + child.slice()); } else if (typeof child === 'object') { // already vnode, this should be the most common since compiled templates // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + return cloneIfMounted(child); } else { // strings and numbers @@ -9255,7 +9251,7 @@ function ensureValidVNode(vnodes) { return vnodes.some(child => { if (!isVNode(child)) return true; - if (child.type === Comment) + if (child.type === Comment$1) return false; if (child.type === Fragment && !ensureValidVNode(child.children)) @@ -9461,16 +9457,6 @@ function installCompatInstanceProperties(map) { extend(map, { // needed by many libs / render fns $vnode: i => i.vnode, - // inject addtional properties into $options for compat - // e.g. vuex needs this.$options.parent - $options: i => { - let res = resolveMergedOptions(i); - if (res === i.type) - res = i.type.__merged = extend({}, res); - res.parent = i.proxy.$parent; - res.propsData = i.vnode.props; - return res; - }, // some private properties that are likely accessed... _self: i => i.proxy, _uid: i => i.uid, @@ -9801,6 +9787,8 @@ function createComponentInstance(vnode, parent, suspense) { emitted: null, // props default value propsDefaults: EMPTY_OBJ, + // inheritAttrs + inheritAttrs: type.inheritAttrs, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, @@ -10029,7 +10017,7 @@ function finishComponentSetup(instance, isSSR, skipOptions) { if (__VUE_OPTIONS_API__ && !(skipOptions)) { currentInstance = instance; pauseTracking(); - applyOptions(instance, Component); + applyOptions(instance); resetTracking(); currentInstance = null; } @@ -10400,7 +10388,7 @@ function initCustomFormatter() { } // Core API ------------------------------------------------------------------ -const version = "3.1.0-beta.5"; +const version = "3.1.0-beta.7"; /** * SSR utils for \@vue/server-renderer. Only exposed in cjs builds. * @internal @@ -10683,6 +10671,9 @@ prevChildren, parentComponent, parentSuspense, unmountChildren) { if (el.value !== newValue) { el.value = newValue; } + if (value == null) { + el.removeAttribute(key); + } return; } if (value === '' || value == null) { @@ -11042,6 +11033,29 @@ const DOMTransitionPropsValidators = { leaveToClass: String }; const TransitionPropsValidators = (Transition.props = /*#__PURE__*/ extend({}, BaseTransition.props, DOMTransitionPropsValidators)); +/** + * #3227 Incoming hooks may be merged into arrays when wrapping Transition + * with custom HOCs. + */ +const callHook$1 = (hook, args = []) => { + if (isArray(hook)) { + hook.forEach(h => h(...args)); + } + else if (hook) { + hook(...args); + } +}; +/** + * Check if a hook expects a callback (2nd arg), which means the user + * intends to explicitly control the end of the transition. + */ +const hasExplicitCallback = (hook) => { + return hook + ? isArray(hook) + ? hook.some(h => h.length > 1) + : hook.length > 1 + : false; +}; function resolveTransitionProps(rawProps) { const baseProps = {}; for (const key in rawProps) { @@ -11088,14 +11102,14 @@ function resolveTransitionProps(rawProps) { return (el, done) => { const hook = isAppear ? onAppear : onEnter; const resolve = () => finishEnter(el, isAppear, done); - hook && hook(el, resolve); + callHook$1(hook, [el, resolve]); nextFrame(() => { removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass); if (legacyClassEnabled) { removeTransitionClass(el, isAppear ? legacyAppearFromClass : legacyEnterFromClass); } addTransitionClass(el, isAppear ? appearToClass : enterToClass); - if (!(hook && hook.length > 1)) { + if (!hasExplicitCallback(hook)) { whenTransitionEnds(el, type, enterDuration, resolve); } }); @@ -11103,7 +11117,7 @@ function resolveTransitionProps(rawProps) { }; return extend(baseProps, { onBeforeEnter(el) { - onBeforeEnter && onBeforeEnter(el); + callHook$1(onBeforeEnter, [el]); addTransitionClass(el, enterFromClass); if (legacyClassEnabled) { addTransitionClass(el, legacyEnterFromClass); @@ -11111,7 +11125,7 @@ function resolveTransitionProps(rawProps) { addTransitionClass(el, enterActiveClass); }, onBeforeAppear(el) { - onBeforeAppear && onBeforeAppear(el); + callHook$1(onBeforeAppear, [el]); addTransitionClass(el, appearFromClass); if (legacyClassEnabled) { addTransitionClass(el, legacyAppearFromClass); @@ -11135,23 +11149,23 @@ function resolveTransitionProps(rawProps) { removeTransitionClass(el, legacyLeaveFromClass); } addTransitionClass(el, leaveToClass); - if (!(onLeave && onLeave.length > 1)) { + if (!hasExplicitCallback(onLeave)) { whenTransitionEnds(el, type, leaveDuration, resolve); } }); - onLeave && onLeave(el, resolve); + callHook$1(onLeave, [el, resolve]); }, onEnterCancelled(el) { finishEnter(el, false); - onEnterCancelled && onEnterCancelled(el); + callHook$1(onEnterCancelled, [el]); }, onAppearCancelled(el) { finishEnter(el, true); - onAppearCancelled && onAppearCancelled(el); + callHook$1(onAppearCancelled, [el]); }, onLeaveCancelled(el) { finishLeave(el); - onLeaveCancelled && onLeaveCancelled(el); + callHook$1(onLeaveCancelled, [el]); } }); } @@ -11625,12 +11639,13 @@ function setSelected(el, value) { } else { if (looseEqual(getValue(option), value)) { - el.selectedIndex = i; + if (el.selectedIndex !== i) + el.selectedIndex = i; return; } } } - if (!isMultiple) { + if (!isMultiple && el.selectedIndex !== -1) { el.selectedIndex = -1; } } @@ -12013,7 +12028,7 @@ var runtimeDom = /*#__PURE__*/Object.freeze({ isVNode: isVNode, Fragment: Fragment, Text: Text, - Comment: Comment, + Comment: Comment$1, Static: Static, Teleport: Teleport, Suspense: Suspense, @@ -12114,4 +12129,4 @@ Vue.compile = (() => { const { configureCompat: configureCompat$1 } = Vue; export default Vue; -export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, camelize, capitalize, cloneVNode, compatUtils, computed$1 as computed, configureCompat$1 as configureCompat, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter$1 as resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toDisplayString, toHandlerKey, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; +export { BaseTransition, Comment$1 as Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, camelize, capitalize, cloneVNode, compatUtils, computed$1 as computed, configureCompat$1 as configureCompat, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter$1 as resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toDisplayString, toHandlerKey, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; diff --git a/packages/uni-h5-vue/dist/vue.runtime.esm.js b/packages/uni-h5-vue/dist/vue.runtime.esm.js index 3d9acb276..a9303b4ff 100644 --- a/packages/uni-h5-vue/dist/vue.runtime.esm.js +++ b/packages/uni-h5-vue/dist/vue.runtime.esm.js @@ -32,7 +32,7 @@ let uid = 0; function createReactiveEffect(fn, options) { const effect = function reactiveEffect() { if (!effect.active) { - return options.scheduler ? undefined : fn(); + return fn(); } if (!effectStack.includes(effect)) { cleanup(effect); @@ -1266,7 +1266,7 @@ function flushJobs(seen) { try { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { const job = queue[flushIndex]; - if (job) { + if (job && job.active !== false) { if ((process.env.NODE_ENV !== 'production') && checkRecursiveUpdates(seen, job)) { continue; } @@ -1449,7 +1449,7 @@ function devtoolsInitApp(app, version) { devtools.emit("app:init" /* APP_INIT */, app, version, { Fragment, Text, - Comment, + Comment: Comment$1, Static }); } @@ -1782,7 +1782,7 @@ function warnDeprecation(key, instance, ...args) { warnCount[dupKey] = 0; const { message, link } = deprecationData[key]; warn(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`); - if (!isCompatEnabled(key, instance)) { + if (!isCompatEnabled(key, instance, true)) { console.error(`^ The above deprecation's compat behavior is disabled and will likely ` + `lead to runtime errors.`); } @@ -1889,8 +1889,10 @@ function emit(instance, event, ...rawArgs) { } } function normalizeEmitsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__emits !== undefined) { - return comp.__emits; + const cache = appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== undefined) { + return cached; } const raw = comp.emits; let normalized = {}; @@ -1915,7 +1917,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__emits = null); + cache.set(comp, null); + return null; } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1923,7 +1926,8 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { else { extend(normalized, raw); } - return (comp.__emits = normalized); + cache.set(comp, normalized); + return normalized; } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are @@ -2033,7 +2037,7 @@ function markAttrsAccessed() { accessedAttrs = true; } function renderComponentRoot(instance) { - const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx } = instance; + const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance; let result; const prev = setCurrentRenderingInstance(instance); if ((process.env.NODE_ENV !== 'production')) { @@ -2082,7 +2086,7 @@ function renderComponentRoot(instance) { ; [root, setRoot] = getChildRoot(result); } - if (fallthroughAttrs && Component.inheritAttrs !== false) { + if (fallthroughAttrs && inheritAttrs !== false) { const keys = Object.keys(fallthroughAttrs); const { shapeFlag } = root; if (keys.length) { @@ -2097,7 +2101,7 @@ function renderComponentRoot(instance) { } root = cloneVNode(root, fallthroughAttrs); } - else if ((process.env.NODE_ENV !== 'production') && !accessedAttrs && root.type !== Comment) { + else if ((process.env.NODE_ENV !== 'production') && !accessedAttrs && root.type !== Comment$1) { const allAttrs = Object.keys(attrs); const eventAttrs = []; const extraAttrs = []; @@ -2163,7 +2167,7 @@ function renderComponentRoot(instance) { catch (err) { blockStack.length = 0; handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment); + result = createVNode(Comment$1); } setCurrentRenderingInstance(prev); return result; @@ -2202,7 +2206,7 @@ function filterSingleRoot(children) { const child = children[i]; if (isVNode(child)) { // ignore user comment - if (child.type !== Comment || child.children === 'v-if') { + if (child.type !== Comment$1 || child.children === 'v-if') { if (singleRoot) { // has more than 1 non-comment child, return now return; @@ -2239,7 +2243,7 @@ const filterModelListeners = (attrs, props) => { const isElementRoot = (vnode) => { return (vnode.shapeFlag & 6 /* COMPONENT */ || vnode.shapeFlag & 1 /* ELEMENT */ || - vnode.type === Comment // potential v-if branch switch + vnode.type === Comment$1 // potential v-if branch switch ); }; function shouldUpdateComponent(prevVNode, nextVNode, optimized) { @@ -2345,7 +2349,8 @@ const SuspenseImpl = { } }, hydrate: hydrateSuspense, - create: createSuspenseBoundary + create: createSuspenseBoundary, + normalize: normalizeSuspenseChildren }; // Force-casted public typing for h and TSX props inference const Suspense = (SuspenseImpl @@ -2690,24 +2695,29 @@ function hydrateSuspense(node, vnode, parentComponent, parentSuspense, isSVG, sl } function normalizeSuspenseChildren(vnode) { const { shapeFlag, children } = vnode; - let content; - let fallback; - if (shapeFlag & 32 /* SLOTS_CHILDREN */) { - content = normalizeSuspenseSlot(children.default); - fallback = normalizeSuspenseSlot(children.fallback); - } - else { - content = normalizeSuspenseSlot(children); - fallback = normalizeVNode(null); - } - return { - content, - fallback - }; + const isSlotChildren = shapeFlag & 32 /* SLOTS_CHILDREN */; + vnode.ssContent = normalizeSuspenseSlot(isSlotChildren ? children.default : children); + vnode.ssFallback = isSlotChildren + ? normalizeSuspenseSlot(children.fallback) + : createVNode(Comment); } function normalizeSuspenseSlot(s) { + let block; if (isFunction(s)) { + const isCompiledSlot = s._c; + if (isCompiledSlot) { + // disableTracking: false + // allow block tracking for compiled slots + // (see ./componentRenderContext.ts) + s._d = false; + openBlock(); + } s = s(); + if (isCompiledSlot) { + s._d = true; + block = currentBlock; + closeBlock(); + } } if (isArray(s)) { const singleChild = filterSingleRoot(s); @@ -2716,7 +2726,11 @@ function normalizeSuspenseSlot(s) { } s = singleChild; } - return normalizeVNode(s); + s = normalizeVNode(s); + if (block) { + s.dynamicChildren = block.filter(c => c !== s); + } + return s; } function queueEffectWithSuspense(fn, suspense) { if (suspense && suspense.pendingBranch) { @@ -2921,7 +2935,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM job.allowRecurse = !!cb; let scheduler; if (flush === 'sync') { - scheduler = job; + scheduler = job; // the scheduler function gets called directly } else if (flush === 'post') { scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); @@ -2997,7 +3011,9 @@ function createPathGetter(ctx, path) { }; } function traverse(value, seen = new Set()) { - if (!isObject(value) || seen.has(value)) { + if (!isObject(value) || + seen.has(value) || + value["__v_skip" /* SKIP */]) { return value; } seen.add(value); @@ -3111,7 +3127,7 @@ const BaseTransitionImpl = { } // handle mode if (oldInnerChild && - oldInnerChild.type !== Comment && + oldInnerChild.type !== Comment$1 && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { const leavingHooks = resolveTransitionHooks(oldInnerChild, rawProps, state, instance); // update old tree's hooks in case of dynamic transition @@ -3126,7 +3142,7 @@ const BaseTransitionImpl = { }; return emptyPlaceholder(child); } - else if (mode === 'in-out' && innerChild.type !== Comment) { + else if (mode === 'in-out' && innerChild.type !== Comment$1) { leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { const leavingVNodesCache = getLeavingNodesForType(state, oldInnerChild); leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; @@ -3318,7 +3334,7 @@ function getTransitionRawChildren(children, keepComment = false) { ret = ret.concat(getTransitionRawChildren(child.children, keepComment)); } // comment placeholders should be skipped, e.g. v-if - else if (keepComment || child.type !== Comment) { + else if (keepComment || child.type !== Comment$1) { ret.push(child); } } @@ -3891,75 +3907,6 @@ function onErrorCaptured(hook, target = currentInstance) { injectHook("ec" /* ERROR_CAPTURED */, hook, target); } -const COMPONENTS = 'components'; -const DIRECTIVES = 'directives'; -/** - * @private - */ -function resolveComponent(name, maybeSelfReference) { - return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; -} -const NULL_DYNAMIC_COMPONENT = Symbol(); -/** - * @private - */ -function resolveDynamicComponent(component) { - if (isString(component)) { - return resolveAsset(COMPONENTS, component, false) || component; - } - else { - // invalid types will fallthrough to createVNode and raise warning - return (component || NULL_DYNAMIC_COMPONENT); - } -} -/** - * @private - */ -function resolveDirective(name) { - return resolveAsset(DIRECTIVES, name); -} -// implementation -function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { - const instance = currentRenderingInstance || currentInstance; - if (instance) { - const Component = instance.type; - // explicit self name has highest priority - if (type === COMPONENTS) { - const selfName = getComponentName(Component); - if (selfName && - (selfName === name || - selfName === camelize(name) || - selfName === capitalize(camelize(name)))) { - return Component; - } - } - const res = - // local registration - // check instance[type] first for components with mixin or extends. - resolve(instance[type] || Component[type], name) || - // global registration - resolve(instance.appContext[type], name); - if (!res && maybeSelfReference) { - // fallback to implicit self-reference - return Component; - } - if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { - warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); - } - return res; - } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`resolve${capitalize(type.slice(0, -1))} ` + - `can only be used in render() or setup().`); - } -} -function resolve(registry, name) { - return (registry && - (registry[name] || - registry[camelize(name)] || - registry[capitalize(camelize(name))])); -} - function createDuplicateChecker() { const cache = Object.create(null); return (type, key) => { @@ -3972,44 +3919,32 @@ function createDuplicateChecker() { }; } let shouldCacheAccess = true; -function applyOptions(instance, options, deferredData = [], deferredWatch = [], deferredProvide = [], asMixin = false) { - const { - // composition - mixins, extends: extendsOptions, - // state - data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, - // lifecycle - beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, - // public API - expose } = options; +function applyOptions(instance) { + const options = resolveMergedOptions(instance); const publicThis = instance.proxy; const ctx = instance.ctx; - const globalMixins = instance.appContext.mixins; - if (asMixin && render && instance.render === NOOP) { - instance.render = render; - } // fixed by xxxxxx const customApplyOptions = instance.appContext.config.globalProperties .$applyOptions; if (customApplyOptions) { customApplyOptions(options, instance, publicThis); } - // applyOptions is called non-as-mixin once per instance - if (!asMixin) { - shouldCacheAccess = false; - callSyncHook('beforeCreate', "bc" /* BEFORE_CREATE */, options, instance, globalMixins); - shouldCacheAccess = true; - // global mixins are applied first - applyMixins(instance, globalMixins, deferredData, deferredWatch, deferredProvide); - } - // extending a base component... - if (extendsOptions) { - applyOptions(instance, extendsOptions, deferredData, deferredWatch, deferredProvide, true); - } - // local mixins - if (mixins) { - applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide); + // do not cache property access on public proxy during state initialization + shouldCacheAccess = false; + // call beforeCreate first before accessing other options since + // the hook may mutate resolved options (#2791) + if (options.beforeCreate) { + callHook(options.beforeCreate, instance, "bc" /* BEFORE_CREATE */); } + const { + // state + data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, + // lifecycle + created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured, serverPrefetch, + // public API + expose, inheritAttrs, + // assets + components, directives, filters } = options; const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { const [propsOptions] = instance.propsOptions; @@ -4056,33 +3991,40 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } - if (!asMixin) { - if (deferredData.length) { - deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)); + if (dataOptions) { + if ((process.env.NODE_ENV !== 'production') && !isFunction(dataOptions)) { + warn(`The data option must be a function. ` + + `Plain object usage is no longer supported.`); } - if (dataOptions) { - // @ts-ignore dataOptions is not fully type safe - resolveData(instance, dataOptions, publicThis); + const data = dataOptions.call(publicThis, publicThis); + if ((process.env.NODE_ENV !== 'production') && isPromise(data)) { + warn(`data() returned a Promise - note data() cannot be async; If you ` + + `intend to perform data fetching before component renders, use ` + + `async setup() + .`); } - if ((process.env.NODE_ENV !== 'production')) { - const rawData = toRaw(instance.data); - for (const key in rawData) { - checkDuplicateProperties("Data" /* DATA */, key); - // expose data on ctx during dev - if (key[0] !== '$' && key[0] !== '_') { - Object.defineProperty(ctx, key, { - configurable: true, - enumerable: true, - get: () => rawData[key], - set: NOOP - }); + if (!isObject(data)) { + (process.env.NODE_ENV !== 'production') && warn(`data() should return an object.`); + } + else { + instance.data = reactive(data); + if ((process.env.NODE_ENV !== 'production')) { + for (const key in data) { + checkDuplicateProperties("Data" /* DATA */, key); + // expose data on ctx during dev + if (key[0] !== '$' && key[0] !== '_') { + Object.defineProperty(ctx, key, { + configurable: true, + enumerable: true, + get: () => data[key], + set: NOOP + }); + } } } } } - else if (dataOptions) { - deferredData.push(dataOptions); - } + // state initialization complete at this point - start caching access + shouldCacheAccess = true; if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key]; @@ -4117,42 +4059,26 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } if (watchOptions) { - deferredWatch.push(watchOptions); - } - if (!asMixin && deferredWatch.length) { - deferredWatch.forEach(watchOptions => { - for (const key in watchOptions) { - createWatcher(watchOptions[key], ctx, publicThis, key); - } - }); + for (const key in watchOptions) { + createWatcher(watchOptions[key], ctx, publicThis, key); + } } if (provideOptions) { - deferredProvide.push(provideOptions); - } - if (!asMixin && deferredProvide.length) { - deferredProvide.forEach(provideOptions => { - const provides = isFunction(provideOptions) - ? provideOptions.call(publicThis) - : provideOptions; - Reflect.ownKeys(provides).forEach(key => { - provide(key, provides[key]); - }); + const provides = isFunction(provideOptions) + ? provideOptions.call(publicThis) + : provideOptions; + Reflect.ownKeys(provides).forEach(key => { + provide(key, provides[key]); }); } - // asset options. - // To reduce memory usage, only components with mixins or extends will have - // resolved asset registry attached to instance. - if (asMixin) { - resolveInstanceAssets(instance, options, COMPONENTS); - resolveInstanceAssets(instance, options, DIRECTIVES); - } - // lifecycle options - if (!asMixin) { - callSyncHook('created', "c" /* CREATED */, options, instance, globalMixins); + if (created) { + callHook(created, instance, "c" /* CREATED */); } function registerLifecycleHook(register, hook) { - // Array lifecycle hooks are only present in the compat build - if (hook) { + if (isArray(hook)) { + hook.forEach(_hook => register(_hook.bind(publicThis))); + } + else if (hook) { register(hook.bind(publicThis)); } } @@ -4169,105 +4095,57 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], registerLifecycleHook(onUnmounted, unmounted); registerLifecycleHook(onServerPrefetch, serverPrefetch); if (isArray(expose)) { - if (!asMixin) { - if (expose.length) { - const exposed = instance.exposed || (instance.exposed = proxyRefs({})); - expose.forEach(key => { - exposed[key] = toRef(publicThis, key); - }); - } - else if (!instance.exposed) { - instance.exposed = EMPTY_OBJ; - } + if (expose.length) { + const exposed = instance.exposed || (instance.exposed = proxyRefs({})); + expose.forEach(key => { + exposed[key] = toRef(publicThis, key); + }); } - else if ((process.env.NODE_ENV !== 'production')) { - warn(`The \`expose\` option is ignored when used in mixins.`); + else if (!instance.exposed) { + instance.exposed = EMPTY_OBJ; } } -} -function resolveInstanceAssets(instance, mixin, type) { - if (mixin[type]) { - extend(instance[type] || - (instance[type] = extend({}, instance.type[type])), mixin[type]); + // options that are handled when creating the instance but also need to be + // applied from mixins + if (render && instance.render === NOOP) { + instance.render = render; + } + if (inheritAttrs != null) { + instance.inheritAttrs = inheritAttrs; } + // asset options. + if (components) + instance.components = components; + if (directives) + instance.directives = directives; } function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) { if (isArray(injectOptions)) { - for (let i = 0; i < injectOptions.length; i++) { - const key = injectOptions[i]; - ctx[key] = inject(key); - if ((process.env.NODE_ENV !== 'production')) { - checkDuplicateProperties("Inject" /* INJECT */, key); - } - } + injectOptions = normalizeInject(injectOptions); } - else { - for (const key in injectOptions) { - const opt = injectOptions[key]; - if (isObject(opt)) { + for (const key in injectOptions) { + const opt = injectOptions[key]; + if (isObject(opt)) { + if ('default' in opt) { ctx[key] = inject(opt.from || key, opt.default, true /* treat default function as factory */); } else { - ctx[key] = inject(opt); - } - if ((process.env.NODE_ENV !== 'production')) { - checkDuplicateProperties("Inject" /* INJECT */, key); + ctx[key] = inject(opt.from || key); } } - } -} -function callSyncHook(name, type, options, instance, globalMixins) { - for (let i = 0; i < globalMixins.length; i++) { - callHookWithMixinAndExtends(name, type, globalMixins[i], instance); - } - callHookWithMixinAndExtends(name, type, options, instance); -} -function callHookWithMixinAndExtends(name, type, options, instance) { - const { extends: base, mixins } = options; - const selfHook = options[name]; - if (base) { - callHookWithMixinAndExtends(name, type, base, instance); - } - if (mixins) { - for (let i = 0; i < mixins.length; i++) { - callHookWithMixinAndExtends(name, type, mixins[i], instance); + else { + ctx[key] = inject(opt); } - } - if (selfHook) { - callWithAsyncErrorHandling(selfHook.bind(instance.proxy), instance, type); - } -} -function applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide) { - for (let i = 0; i < mixins.length; i++) { - applyOptions(instance, mixins[i], deferredData, deferredWatch, deferredProvide, true); - } -} -function resolveData(instance, dataFn, publicThis) { - if ((process.env.NODE_ENV !== 'production') && !isFunction(dataFn)) { - warn(`The data option must be a function. ` + - `Plain object usage is no longer supported.`); - } - shouldCacheAccess = false; - const data = dataFn.call(publicThis, publicThis); - shouldCacheAccess = true; - if ((process.env.NODE_ENV !== 'production') && isPromise(data)) { - warn(`data() returned a Promise - note data() cannot be async; If you ` + - `intend to perform data fetching before component renders, use ` + - `async setup() + .`); - } - if (!isObject(data)) { - (process.env.NODE_ENV !== 'production') && warn(`data() should return an object.`); - } - else if (instance.data === EMPTY_OBJ) { - instance.data = reactive(data); - } - else { - // existing data: this is a mixin or extends. - { - extend(instance.data, data); + if ((process.env.NODE_ENV !== 'production')) { + checkDuplicateProperties("Inject" /* INJECT */, key); } } } +function callHook(hook, instance, type) { + callWithAsyncErrorHandling(isArray(hook) + ? hook.map(h => h.bind(instance.proxy)) + : hook.bind(instance.proxy), instance, type); +} function createWatcher(raw, ctx, publicThis, key) { const getter = key.includes('.') ? createPathGetter(publicThis, key) @@ -4304,33 +4182,116 @@ function createWatcher(raw, ctx, publicThis, key) { warn(`Invalid watch option: "${key}"`, raw); } } +/** + * Resolve merged options and cache it on the component. + * This is done only once per-component since the merging does not involve + * instances. + */ function resolveMergedOptions(instance) { - const raw = instance.type; - const { __merged, mixins, extends: extendsOptions } = raw; - if (__merged) - return __merged; - const globalMixins = instance.appContext.mixins; - if (!globalMixins.length && !mixins && !extendsOptions) - return raw; - const options = {}; - globalMixins.forEach(m => mergeOptions(options, m, instance)); - mergeOptions(options, raw, instance); - return (raw.__merged = options); -} -function mergeOptions(to, from, instance, strats = instance && instance.appContext.config.optionMergeStrategies) { + const base = instance.type; + const { mixins, extends: extendsOptions } = base; + const { mixins: globalMixins, optionsCache: cache, config: { optionMergeStrategies } } = instance.appContext; + const cached = cache.get(base); + let resolved; + if (cached) { + resolved = cached; + } + else if (!globalMixins.length && !mixins && !extendsOptions) { + { + resolved = base; + } + } + else { + resolved = {}; + if (globalMixins.length) { + globalMixins.forEach(m => mergeOptions(resolved, m, optionMergeStrategies, true)); + } + mergeOptions(resolved, base, optionMergeStrategies); + } + cache.set(base, resolved); + return resolved; +} +function mergeOptions(to, from, strats, asMixin = false) { const { mixins, extends: extendsOptions } = from; - extendsOptions && mergeOptions(to, extendsOptions, instance, strats); - mixins && - mixins.forEach((m) => mergeOptions(to, m, instance, strats)); + if (extendsOptions) { + mergeOptions(to, extendsOptions, strats, true); + } + if (mixins) { + mixins.forEach((m) => mergeOptions(to, m, strats, true)); + } for (const key in from) { - if (strats && hasOwn(strats, key)) { - to[key] = strats[key](to[key], from[key], instance && instance.proxy, key); + if (asMixin && key === 'expose') { + (process.env.NODE_ENV !== 'production') && + warn(`"expose" option is ignored when declared in mixins or extends. ` + + `It should only be declared in the base component itself.`); } else { - to[key] = from[key]; + const strat = internalOptionMergeStrats[key] || (strats && strats[key]); + to[key] = strat ? strat(to[key], from[key]) : from[key]; } } return to; +} +const internalOptionMergeStrats = { + data: mergeDataFn, + props: mergeObjectOptions, + emits: mergeObjectOptions, + // objects + methods: mergeObjectOptions, + computed: mergeObjectOptions, + // lifecycle + beforeCreate: mergeHook, + created: mergeHook, + beforeMount: mergeHook, + mounted: mergeHook, + beforeUpdate: mergeHook, + updated: mergeHook, + beforeDestroy: mergeHook, + destroyed: mergeHook, + activated: mergeHook, + deactivated: mergeHook, + errorCaptured: mergeHook, + serverPrefetch: mergeHook, + // assets + components: mergeObjectOptions, + directives: mergeObjectOptions, + // watch has special merge behavior in v2, but isn't actually needed in v3. + // since we are only exposing these for compat and nobody should be relying + // on the watch-specific behavior, just expose the object merge strat. + watch: mergeObjectOptions, + // provide / inject + provide: mergeDataFn, + inject: mergeInject +}; +function mergeDataFn(to, from) { + if (!from) { + return to; + } + if (!to) { + return from; + } + return function mergedDataFn() { + return (extend)(isFunction(to) ? to.call(this, this) : to, isFunction(from) ? from.call(this, this) : from); + }; +} +function mergeInject(to, from) { + return mergeObjectOptions(normalizeInject(to), normalizeInject(from)); +} +function normalizeInject(raw) { + if (isArray(raw)) { + const res = {}; + for (let i = 0; i < raw.length; i++) { + res[raw[i]] = raw[i]; + } + return res; + } + return raw; +} +function mergeHook(to, from) { + return to ? [...new Set([].concat(to, from))] : from; +} +function mergeObjectOptions(to, from) { + return to ? extend(extend(Object.create(null), to), from) : from; } function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison @@ -4535,8 +4496,10 @@ function resolvePropValue(options, props, key, value, instance, isAbsent) { return value; } function normalizePropsOptions(comp, appContext, asMixin = false) { - if (!appContext.deopt && comp.__props) { - return comp.__props; + const cache = appContext.propsCache; + const cached = cache.get(comp); + if (cached) { + return cached; } const raw = comp.props; const normalized = {}; @@ -4562,7 +4525,8 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } if (!raw && !hasExtends) { - return (comp.__props = EMPTY_ARR); + cache.set(comp, EMPTY_ARR); + return EMPTY_ARR; } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -4599,7 +4563,9 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } } } - return (comp.__props = [normalized, needCastKeys]); + const res = [normalized, needCastKeys]; + cache.set(comp, res); + return res; } function validatePropName(key) { if (key[0] !== '$') { @@ -4934,12 +4900,16 @@ function invokeDirectiveHook(vnode, prevVNode, instance, name) { } let hook = binding.dir[name]; if (hook) { + // disable tracking inside all lifecycle hooks + // since they can potentially be called inside effects. + pauseTracking(); callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ vnode.el, binding, vnode, prevVNode ]); + resetTracking(); } } } @@ -4959,7 +4929,10 @@ function createAppContext() { mixins: [], components: {}, directives: {}, - provides: Object.create(null) + provides: Object.create(null), + optionsCache: new WeakMap(), + propsCache: new WeakMap(), + emitsCache: new WeakMap() }; } let uid$1 = 0; @@ -5009,11 +4982,6 @@ function createAppAPI(render, hydrate) { if (__VUE_OPTIONS_API__) { if (!context.mixins.includes(mixin)) { context.mixins.push(mixin); - // global mixin with props/emits de-optimizes props/emits - // normalization caching. - if (mixin.props || mixin.emits) { - context.deopt = true; - } } else if ((process.env.NODE_ENV !== 'production')) { warn('Mixin has already been applied to target app' + @@ -5160,7 +5128,7 @@ function createHydrationFunctions(rendererInternals) { nextNode = nextSibling(node); } break; - case Comment: + case Comment$1: if (domType !== 8 /* COMMENT */ || isFragmentStart) { nextNode = onMismatch(); } @@ -5638,7 +5606,7 @@ function baseCreateRenderer(options, createHydrationFns) { case Text: processText(n1, n2, container, anchor); break; - case Comment: + case Comment$1: processCommentNode(n1, n2, container, anchor); break; case Static: @@ -5944,15 +5912,18 @@ function baseCreateRenderer(options, createHydrationFns) { const newVNode = newChildren[i]; // Determine the container (parent element) for the patch. const container = - // - In the case of a Fragment, we need to provide the actual parent - // of the Fragment itself so it can move its children. - oldVNode.type === Fragment || - // - In the case of different nodes, there is going to be a replacement - // which also requires the correct parent container - !isSameVNodeType(oldVNode, newVNode) || - // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & 6 /* COMPONENT */ || - oldVNode.shapeFlag & 64 /* TELEPORT */ + // oldVNode may be an errored async setup() component inside Suspense + // which will not have a mounted element + oldVNode.el && + // - In the case of a Fragment, we need to provide the actual parent + // of the Fragment itself so it can move its children. + (oldVNode.type === Fragment || + // - In the case of different nodes, there is going to be a replacement + // which also requires the correct parent container + !isSameVNodeType(oldVNode, newVNode) || + // - In the case of a component, it could contain anything. + oldVNode.shapeFlag & 6 /* COMPONENT */ || + oldVNode.shapeFlag & 64 /* TELEPORT */) ? hostParentNode(oldVNode.el) : // In other cases, the parent container is not actually used so we // just pass the block element here to avoid a DOM parentNode call. @@ -6085,7 +6056,7 @@ function baseCreateRenderer(options, createHydrationFns) { // Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { - const placeholder = (instance.subTree = createVNode(Comment)); + const placeholder = (instance.subTree = createVNode(Comment$1)); processCommentNode(null, placeholder, container, anchor); } return; @@ -6836,7 +6807,7 @@ function traverseStaticChildren(n1, n2, shallow = false) { } // also inherit for comment nodes, but not placeholders (e.g. v-if which // would have received .el during block patch) - if ((process.env.NODE_ENV !== 'production') && c2.type === Comment && !c2.el) { + if ((process.env.NODE_ENV !== 'production') && c2.type === Comment$1 && !c2.el) { c2.el = c1.el; } } @@ -7079,9 +7050,78 @@ function hydrateTeleport(node, vnode, parentComponent, parentSuspense, slotScope // Force-casted public typing for h and TSX props inference const Teleport = TeleportImpl; +const COMPONENTS = 'components'; +const DIRECTIVES = 'directives'; +/** + * @private + */ +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol(); +/** + * @private + */ +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } + else { + // invalid types will fallthrough to createVNode and raise warning + return (component || NULL_DYNAMIC_COMPONENT); + } +} +/** + * @private + */ +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +// implementation +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + // explicit self name has highest priority + if (type === COMPONENTS) { + const selfName = getComponentName(Component); + if (selfName && + (selfName === name || + selfName === camelize(name) || + selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || + // global registration + resolve(instance.appContext[type], name); + if (!res && maybeSelfReference) { + // fallback to implicit self-reference + return Component; + } + if ((process.env.NODE_ENV !== 'production') && warnMissing && !res) { + warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`); + } + return res; + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`resolve${capitalize(type.slice(0, -1))} ` + + `can only be used in render() or setup().`); + } +} +function resolve(registry, name) { + return (registry && + (registry[name] || + registry[camelize(name)] || + registry[capitalize(camelize(name))])); +} + const Fragment = Symbol((process.env.NODE_ENV !== 'production') ? 'Fragment' : undefined); const Text = Symbol((process.env.NODE_ENV !== 'production') ? 'Text' : undefined); -const Comment = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); +const Comment$1 = Symbol((process.env.NODE_ENV !== 'production') ? 'Comment' : undefined); const Static = Symbol((process.env.NODE_ENV !== 'production') ? 'Static' : undefined); // Since v-if and v-for are the two possible ways node structure can dynamically // change, once we consider v-if branches and each v-for fragment a block, we @@ -7202,7 +7242,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami if ((process.env.NODE_ENV !== 'production') && !type) { warn(`Invalid vnode type when creating vnode: ${type}.`); } - type = Comment; + type = Comment$1; } if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like @@ -7290,9 +7330,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami normalizeChildren(vnode, children); // normalize suspense children if (shapeFlag & 128 /* SUSPENSE */) { - const { content, fallback } = normalizeSuspenseChildren(vnode); - vnode.ssContent = content; - vnode.ssFallback = fallback; + type.normalize(vnode); } if (isBlockTreeEnabled > 0 && // avoid a block node from tracking itself @@ -7403,22 +7441,24 @@ function createCommentVNode(text = '', // block to ensure correct updates. asBlock = false) { return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); + ? (openBlock(), createBlock(Comment$1, null, text)) + : createVNode(Comment$1, null, text); } function normalizeVNode(child) { if (child == null || typeof child === 'boolean') { // empty placeholder - return createVNode(Comment); + return createVNode(Comment$1); } else if (isArray(child)) { // fragment - return createVNode(Fragment, null, child); + return createVNode(Fragment, null, + // #3666, avoid reference pollution when reusing vnode + child.slice()); } else if (typeof child === 'object') { // already vnode, this should be the most common since compiled templates // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); + return cloneIfMounted(child); } else { // strings and numbers @@ -7617,7 +7657,7 @@ function ensureValidVNode(vnodes) { return vnodes.some(child => { if (!isVNode(child)) return true; - if (child.type === Comment) + if (child.type === Comment$1) return false; if (child.type === Fragment && !ensureValidVNode(child.children)) @@ -7934,6 +7974,8 @@ function createComponentInstance(vnode, parent, suspense) { emitted: null, // props default value propsDefaults: EMPTY_OBJ, + // inheritAttrs + inheritAttrs: type.inheritAttrs, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, @@ -8147,7 +8189,7 @@ function finishComponentSetup(instance, isSSR, skipOptions) { if (__VUE_OPTIONS_API__ && !(false )) { currentInstance = instance; pauseTracking(); - applyOptions(instance, Component); + applyOptions(instance); resetTracking(); currentInstance = null; } @@ -8518,7 +8560,7 @@ function initCustomFormatter() { } // Core API ------------------------------------------------------------------ -const version = "3.1.0-beta.5"; +const version = "3.1.0-beta.7"; /** * SSR utils for \@vue/server-renderer. Only exposed in cjs builds. * @internal @@ -8766,6 +8808,9 @@ prevChildren, parentComponent, parentSuspense, unmountChildren) { if (el.value !== newValue) { el.value = newValue; } + if (value == null) { + el.removeAttribute(key); + } return; } if (value === '' || value == null) { @@ -9111,6 +9156,29 @@ const DOMTransitionPropsValidators = { leaveToClass: String }; const TransitionPropsValidators = (Transition.props = /*#__PURE__*/ extend({}, BaseTransition.props, DOMTransitionPropsValidators)); +/** + * #3227 Incoming hooks may be merged into arrays when wrapping Transition + * with custom HOCs. + */ +const callHook$1 = (hook, args = []) => { + if (isArray(hook)) { + hook.forEach(h => h(...args)); + } + else if (hook) { + hook(...args); + } +}; +/** + * Check if a hook expects a callback (2nd arg), which means the user + * intends to explicitly control the end of the transition. + */ +const hasExplicitCallback = (hook) => { + return hook + ? isArray(hook) + ? hook.some(h => h.length > 1) + : hook.length > 1 + : false; +}; function resolveTransitionProps(rawProps) { const baseProps = {}; for (const key in rawProps) { @@ -9140,11 +9208,11 @@ function resolveTransitionProps(rawProps) { return (el, done) => { const hook = isAppear ? onAppear : onEnter; const resolve = () => finishEnter(el, isAppear, done); - hook && hook(el, resolve); + callHook$1(hook, [el, resolve]); nextFrame(() => { removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass); addTransitionClass(el, isAppear ? appearToClass : enterToClass); - if (!(hook && hook.length > 1)) { + if (!hasExplicitCallback(hook)) { whenTransitionEnds(el, type, enterDuration, resolve); } }); @@ -9152,12 +9220,12 @@ function resolveTransitionProps(rawProps) { }; return extend(baseProps, { onBeforeEnter(el) { - onBeforeEnter && onBeforeEnter(el); + callHook$1(onBeforeEnter, [el]); addTransitionClass(el, enterFromClass); addTransitionClass(el, enterActiveClass); }, onBeforeAppear(el) { - onBeforeAppear && onBeforeAppear(el); + callHook$1(onBeforeAppear, [el]); addTransitionClass(el, appearFromClass); addTransitionClass(el, appearActiveClass); }, @@ -9172,23 +9240,23 @@ function resolveTransitionProps(rawProps) { nextFrame(() => { removeTransitionClass(el, leaveFromClass); addTransitionClass(el, leaveToClass); - if (!(onLeave && onLeave.length > 1)) { + if (!hasExplicitCallback(onLeave)) { whenTransitionEnds(el, type, leaveDuration, resolve); } }); - onLeave && onLeave(el, resolve); + callHook$1(onLeave, [el, resolve]); }, onEnterCancelled(el) { finishEnter(el, false); - onEnterCancelled && onEnterCancelled(el); + callHook$1(onEnterCancelled, [el]); }, onAppearCancelled(el) { finishEnter(el, true); - onAppearCancelled && onAppearCancelled(el); + callHook$1(onAppearCancelled, [el]); }, onLeaveCancelled(el) { finishLeave(el); - onLeaveCancelled && onLeaveCancelled(el); + callHook$1(onLeaveCancelled, [el]); } }); } @@ -9655,12 +9723,13 @@ function setSelected(el, value) { } else { if (looseEqual(getValue(option), value)) { - el.selectedIndex = i; + if (el.selectedIndex !== i) + el.selectedIndex = i; return; } } } - if (!isMultiple) { + if (!isMultiple && el.selectedIndex !== -1) { el.selectedIndex = -1; } } @@ -9948,4 +10017,4 @@ const compile$1 = () => { } }; -export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compatUtils, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; +export { BaseTransition, Comment$1 as Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compatUtils, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId }; -- GitLab