diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index 0f9caab6..f2973adb 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -58,7 +58,7 @@ export function shouldUpdateComponent( ): boolean { const { props: prevProps, children: prevChildren } = prevVNode const { props: nextProps, children: nextChildren, patchFlag } = nextVNode - if (patchFlag) { + if (patchFlag > 0) { if (patchFlag & PatchFlags.DYNAMIC_SLOTS) { // slot content that references values that might have changed, // e.g. in a v-for diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index 4fc55aed..8829b738 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -409,7 +409,7 @@ export function createRenderer< invokeDirectiveHook(newProps.vnodeBeforeUpdate, parentComponent, n2, n1) } - if (patchFlag) { + if (patchFlag > 0) { // the presence of a patchFlag means this element's render code was // generated by the compiler and can take the fast path. // in this path old node and new node are guaranteed to have the same shape @@ -1227,9 +1227,12 @@ export function createRenderer< const prevShapeFlag = n1 ? n1.shapeFlag : 0 const c2 = n2.children - // fast path const { patchFlag, shapeFlag } = n2 - if (patchFlag) { + if (patchFlag === PatchFlags.BAIL) { + optimized = false + } + // fast path + if (patchFlag > 0) { if (patchFlag & PatchFlags.KEYED_FRAGMENT) { // this could be either fully-keyed or mixed (some keyed some not) // presence of patchFlag means children are guaranteed to be arrays diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index c5a84aad..de633b22 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -6,22 +6,24 @@ import { Fragment, VNode } from '../vnode' +import { PatchFlags } from '@vue/shared' export function renderSlot( slots: Record, - key: string, + name: string, props: any = {}, // this is not a user-facing function, so the fallback is always generated by // the compiler and gurunteed to be an array fallback?: VNodeChildren ): VNode { - const slot = slots[key] + const slot = slots[name] return ( openBlock(), createBlock( Fragment, { key: props.key }, - slot ? slot(props) : fallback || [] + slot ? slot(props) : fallback || [], + slots._compiled ? 0 : PatchFlags.BAIL ) ) } diff --git a/packages/shared/src/patchFlags.ts b/packages/shared/src/patchFlags.ts index 74c8bf86..698aac08 100644 --- a/packages/shared/src/patchFlags.ts +++ b/packages/shared/src/patchFlags.ts @@ -56,7 +56,13 @@ export const enum PatchFlags { // Indicates a component with dynamic slots (e.g. slot that references a v-for // iterated value, or dynamic slot names). // Components with this flag are always force updated. - DYNAMIC_SLOTS = 1 << 8 + DYNAMIC_SLOTS = 1 << 8, + + // A special flag that indicates that the diffing algorithm should bail out + // of optimized mode. This is only on block fragments created by renderSlot() + // when encountering non-compiler generated slots (i.e. manually written + // render functions, which should always be fully diffed) + BAIL = -1 } // runtime object for public consumption @@ -69,7 +75,8 @@ export const PublicPatchFlags = { FULL_PROPS: PatchFlags.FULL_PROPS, KEYED_FRAGMENT: PatchFlags.KEYED_FRAGMENT, UNKEYED_FRAGMENT: PatchFlags.UNKEYED_FRAGMENT, - DYNAMIC_SLOTS: PatchFlags.DYNAMIC_SLOTS + DYNAMIC_SLOTS: PatchFlags.DYNAMIC_SLOTS, + BAIL: PatchFlags.BAIL } // dev only flag -> name mapping @@ -82,5 +89,6 @@ export const PatchFlagNames = { [PatchFlags.FULL_PROPS]: `FULL_PROPS`, [PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`, [PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`, - [PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS` + [PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`, + [PatchFlags.BAIL]: `BAIL` }