diff --git a/packages/runtime-core/src/patchFlags.ts b/packages/runtime-core/src/patchFlags.ts index f28ffd15..0a26e80e 100644 --- a/packages/runtime-core/src/patchFlags.ts +++ b/packages/runtime-core/src/patchFlags.ts @@ -1,7 +1,37 @@ +// Patch flags are optimization hints generated by the compiler. +// when a block with dynamicChildren is encountered during diff, the algorithm +// enters "optimized mode". In this mode, we know that the vdom is produced by +// a render function generated by the compiler, so the algorithm only needs to +// handle updates explicitly marked by these patch flags. + +// Patch flags can be combined using the | bitwise operator and can be checked +// using the & operator, e.g. +// +// const flag = TEXT | CLASS +// if (flag & TEXT) { ... } + +// Indicates an element with dynamic textContent (children fast path) export const TEXT = 1 + +// Indicates an element with dynamic class export const CLASS = 1 << 1 + +// Indicates an element with dynamic style export const STYLE = 1 << 2 + +// Indicates an element that has non-class/style dynamic props. +// Can also be on a component that has any dynamic props (includes class/style). +// when this flag is present, the vnode also has a dynamicProps array that +// contains the keys of the props that may change so the runtime can diff +// them faster (without having to worry about removed props) export const PROPS = 1 << 3 + +// Indicates a fragment or element with keyed or partially-keyed v-for children export const KEYED = 1 << 4 + +// Indicates a fragment or element that contains unkeyed v-for children export const UNKEYED = 1 << 5 -export const SLOTS = 1 << 6 // component only + +// Indicates a component with dynamic slot (e.g. slot that references a v-for +// iterated value). Components with this flag are always force updated. +export const SLOTS = 1 << 6 diff --git a/packages/runtime-core/src/reactivity.ts b/packages/runtime-core/src/reactivity.ts index 493ae81c..fa102b2f 100644 --- a/packages/runtime-core/src/reactivity.ts +++ b/packages/runtime-core/src/reactivity.ts @@ -16,7 +16,7 @@ export { OperationTypes, Value, ComputedValue, - UnwrapValues + UnwrapValue } from '@vue/observer' import { diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 8dca305a..6ac85823 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -37,16 +37,30 @@ export interface VNode { dynamicChildren: VNode[] | null } +// Since v-if and v-for are the two possible ways node structure can dynamically +// change, once we consider v-if branches and each v-for fragment a block, we +// can divide a template into nested blocks, and within each block the node +// structure would be stable. This allows us to skip most children diffing +// and only worry about the dynamic nodes (indicated by patch flags). const blockStack: (VNode[] | null)[] = [] -// open block +// Open a block. +// This must be called before `createBlock`. It cannot be part of `createBlock` +// because the children of the block are evaluated before `createBlock` itself +// is called. The generated code typically looks like this: +// +// function render() { +// return (openBlock(),createBlock('div', null, [...])) +// } export function openBlock(disableTrackng?: boolean) { blockStack.push(disableTrackng ? null : []) } let shouldTrack = true -// block +// Create a block root vnode. Takes the same exact arguments as `createVNode`. +// A block root keeps track of dynamic nodes within the block in the +// `dynamicChildren` array. export function createBlock( type: VNodeTypes, props?: { [key: string]: any } | null, @@ -66,7 +80,6 @@ export function createBlock( return vnode } -// element export function createVNode( type: VNodeTypes, props: { [key: string]: any } | null = null, @@ -87,6 +100,7 @@ export function createVNode( dynamicProps, dynamicChildren: null } + // presence of a patch flag indicates this node is dynamic if (shouldTrack && patchFlag != null) { trackDynamicNode(vnode) }