From: Evan You Date: Tue, 1 Oct 2019 01:17:12 +0000 (-0400) Subject: feat(compiler): generate patchFlags for runtime X-Git-Tag: v3.0.0-alpha.0~661 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d67418002fbbff358e8761b07607f71e5df06c24;p=thirdparty%2Fvuejs%2Fcore.git feat(compiler): generate patchFlags for runtime --- diff --git a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap index f73f3dd7a1..047d00ad3d 100644 --- a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap @@ -11,14 +11,14 @@ return function render() { }, [ _toString(world.burn()), ok - ? _createVNode(\\"div\\", 0, \\"yes\\") + ? _createVNode(\\"div\\", null, \\"yes\\") : \\"no\\", _renderList(list, (value, index) => { - return _createVNode(\\"div\\", 0, [ - _createVNode(\\"span\\", 0, _toString(value + index)) + return _createVNode(\\"div\\", null, [ + _createVNode(\\"span\\", null, _toString(value + index)) ]) }) - ]) + ], 2) } }" `; @@ -34,14 +34,14 @@ return function render() { }, [ toString(_ctx.world.burn()), (_ctx.ok) - ? createVNode(\\"div\\", 0, \\"yes\\") + ? createVNode(\\"div\\", null, \\"yes\\") : \\"no\\", renderList(_ctx.list, (value, index) => { - return createVNode(\\"div\\", 0, [ - createVNode(\\"span\\", 0, toString(value + index)) + return createVNode(\\"div\\", null, [ + createVNode(\\"span\\", null, toString(value + index)) ]) }) - ]) + ], 2) }" `; @@ -56,13 +56,13 @@ export default function render() { }, [ _toString(_ctx.world.burn()), (_ctx.ok) - ? createVNode(\\"div\\", 0, \\"yes\\") + ? createVNode(\\"div\\", null, \\"yes\\") : \\"no\\", _renderList(_ctx.list, (value, index) => { - return createVNode(\\"div\\", 0, [ - createVNode(\\"span\\", 0, _toString(value + index)) + return createVNode(\\"div\\", null, [ + createVNode(\\"span\\", null, _toString(value + index)) ]) }) - ]) + ], 2) }" `; diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap index 1ef19853b4..1bc471f328 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap @@ -7,7 +7,7 @@ return function render() { const _ctx = this const _component_Comp = resolveComponent(\\"Comp\\") - return createVNode(_component_Comp, 0, { + return createVNode(_component_Comp, null, { [_ctx.one]: ({ foo }) => [ toString(foo), toString(_ctx.bar) @@ -16,7 +16,7 @@ return function render() { toString(_ctx.foo), toString(bar) ] - }) + }, 256) }" `; @@ -27,7 +27,7 @@ return function render() { const _ctx = this const _component_Comp = resolveComponent(\\"Comp\\") - return createVNode(_component_Comp, 0, { + return createVNode(_component_Comp, null, { default: ({ foo }) => [ toString(foo), toString(_ctx.bar) @@ -43,7 +43,7 @@ return function render() { const _ctx = this const _component_Comp = resolveComponent(\\"Comp\\") - return createVNode(_component_Comp, 0, { + return createVNode(_component_Comp, null, { default: () => [ createVNode(\\"div\\") ] @@ -58,7 +58,7 @@ return function render() { const _ctx = this const _component_Comp = resolveComponent(\\"Comp\\") - return createVNode(_component_Comp, 0, { + return createVNode(_component_Comp, null, { one: ({ foo }) => [ toString(foo), toString(_ctx.bar) @@ -79,9 +79,9 @@ return function render() { const _component_Comp = resolveComponent(\\"Comp\\") const _component_Inner = resolveComponent(\\"Inner\\") - return createVNode(_component_Comp, 0, { + return createVNode(_component_Comp, null, { default: ({ foo }) => [ - createVNode(_component_Inner, 0, { + createVNode(_component_Inner, null, { default: ({ bar }) => [ toString(foo), toString(bar), diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index f35092e515..2af63cb8b6 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -24,6 +24,7 @@ import { transformElement } from '../../src/transforms/transformElement' import { transformOn } from '../../src/transforms/vOn' import { transformStyle } from '../../src/transforms/transformStyle' import { transformBind } from '../../src/transforms/vBind' +import { PatchFlags } from '@vue/shared' function parseWithElementTransform( template: string, @@ -127,7 +128,7 @@ describe('compiler: element transform', () => { expect(node.callee).toBe(`_${CREATE_VNODE}`) expect(node.arguments).toMatchObject([ `"div"`, - `0`, + `null`, [ { type: NodeTypes.ELEMENT, @@ -351,7 +352,9 @@ describe('compiler: element transform', () => { value: _dir!.exp } ] - } + }, + `null`, + String(PatchFlags.NEED_PATCH) // should generate appropriate flag ] }, { @@ -546,5 +549,121 @@ describe('compiler: element transform', () => { }) }) - test.todo('slot outlets') + test(`props merging: class`, () => { + const { node } = parseWithElementTransform( + `
`, + { + directiveTransforms: { + bind: transformBind + } + } + ) + expect(node.arguments[1]).toMatchObject({ + type: NodeTypes.JS_OBJECT_EXPRESSION, + properties: [ + { + type: NodeTypes.JS_PROPERTY, + key: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `class`, + isStatic: true + }, + value: { + type: NodeTypes.JS_ARRAY_EXPRESSION, + elements: [ + { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `foo`, + isStatic: true + }, + { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `{ bar: isBar }`, + isStatic: false + } + ] + } + } + ] + }) + }) + + describe('patchFlag analysis', () => { + function parseWithBind(template: string) { + return parseWithElementTransform(template, { + directiveTransforms: { + bind: transformBind + } + }) + } + + test('CLASS', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.CLASS)) + }) + + test('STYLE', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.STYLE)) + }) + + test('PROPS', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(5) + expect(node.arguments[3]).toBe(String(PatchFlags.PROPS)) + expect(node.arguments[4]).toBe(`["foo", "baz"]`) + }) + + test('CLASS + STYLE + PROPS', () => { + const { node } = parseWithBind( + `
` + ) + expect(node.arguments.length).toBe(5) + expect(node.arguments[3]).toBe( + String(PatchFlags.PROPS | PatchFlags.CLASS | PatchFlags.STYLE) + ) + expect(node.arguments[4]).toBe(`["foo", "baz"]`) + }) + + test('FULL_PROPS (v-bind)', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) + }) + + test('FULL_PROPS (dynamic key)', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) + }) + + test('FULL_PROPS (w/ others)', () => { + const { node } = parseWithBind( + `
` + ) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) + }) + + test('NEED_PATCH (static ref)', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) + }) + + test('NEED_PATCH (dynamic ref)', () => { + const { node } = parseWithBind(`
`) + expect(node.arguments.length).toBe(4) + expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) + }) + + test('NEED_PATCH (custom directives)', () => { + const { node } = parseWithBind(`
`) + const vnodeCall = node.arguments[0] as CallExpression + expect(vnodeCall.arguments.length).toBe(4) + expect(vnodeCall.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) + }) + }) }) diff --git a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts index 748ba3496f..bfd4a68ae8 100644 --- a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts @@ -260,7 +260,7 @@ describe('compiler: transform component slots', () => { type: NodeTypes.JS_CALL_EXPRESSION, arguments: [ `_component_Inner`, - `0`, + `null`, createSlotMatcher({ default: { type: NodeTypes.JS_SLOT_FUNCTION, diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index 30a3d6c07f..eb7ad37914 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -169,7 +169,7 @@ export type JSChildNode = export interface CallExpression extends Node { type: NodeTypes.JS_CALL_EXPRESSION - callee: string | ExpressionNode + callee: string arguments: (string | JSChildNode | ChildNode[])[] } @@ -268,7 +268,7 @@ export function createCompoundExpression( } export function createCallExpression( - callee: string | ExpressionNode, + callee: string, args: CallExpression['arguments'], loc: SourceLocation ): CallExpression { diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index ee0d5d2b6b..1b3f53c821 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -544,12 +544,7 @@ function genCallExpression( context: CodegenContext, multilines = node.arguments.length > 2 ) { - if (isString(node.callee)) { - context.push(node.callee + `(`, node, true) - } else { - genNode(node.callee, context) - context.push(`(`) - } + context.push(node.callee + `(`, node, true) multilines && context.indent() genNodeList(node.arguments, context, multilines) multilines && context.deindent() diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 263c77dd75..ad0c512740 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -8,7 +8,8 @@ import { Property, ExpressionNode, createSimpleExpression, - JSChildNode + JSChildNode, + SimpleExpressionNode } from './ast' import { isString, isArray } from '@vue/shared' import { CompilerError, defaultOnError } from './errors' @@ -65,7 +66,7 @@ export interface TransformContext extends Required { onNodeRemoved: () => void addIdentifiers(exp: ExpressionNode): void removeIdentifiers(exp: ExpressionNode): void - hoist(exp: JSChildNode): ExpressionNode + hoist(exp: JSChildNode): SimpleExpressionNode } function createTransformContext( diff --git a/packages/compiler-core/src/transforms/optimizeBlocks.ts b/packages/compiler-core/src/transforms/optimizeBlocks.ts deleted file mode 100644 index 70b786d12e..0000000000 --- a/packages/compiler-core/src/transforms/optimizeBlocks.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO diff --git a/packages/compiler-core/src/transforms/optimizePatchFlags.ts b/packages/compiler-core/src/transforms/optimizePatchFlags.ts deleted file mode 100644 index 70b786d12e..0000000000 --- a/packages/compiler-core/src/transforms/optimizePatchFlags.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 0f36d9fad6..469f4e09d1 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -16,7 +16,7 @@ import { Property, SourceLocation } from '../ast' -import { isArray } from '@vue/shared' +import { isArray, PatchFlags } from '@vue/shared' import { createCompilerError, ErrorCodes } from '../errors' import { CREATE_VNODE, @@ -41,7 +41,9 @@ export const transformElement: NodeTransform = (node, context) => { const isComponent = node.tagType === ElementTypes.COMPONENT let hasProps = node.props.length > 0 const hasChildren = node.children.length > 0 + let patchFlag: number = 0 let runtimeDirectives: DirectiveNode[] | undefined + let dynamicPropNames: string[] | undefined let componentIdentifier: string | undefined if (isComponent) { @@ -58,26 +60,51 @@ export const transformElement: NodeTransform = (node, context) => { ] // props if (hasProps) { - const { props, directives } = buildProps( + const propsBuildResult = buildProps( node.props, node.loc, context, isComponent ) - runtimeDirectives = directives - if (!props) { + patchFlag = propsBuildResult.patchFlag + dynamicPropNames = propsBuildResult.dynamicPropNames + runtimeDirectives = propsBuildResult.directives + if (!propsBuildResult.props) { hasProps = false } else { - args.push(props) + args.push(propsBuildResult.props) } } // children if (hasChildren) { if (!hasProps) { - // placeholder for null props, but use `0` for more condense code - args.push(`0`) + args.push(`null`) + } + if (isComponent) { + const { slots, hasDynamicSlotName } = buildSlots(node, context) + args.push(slots) + if (hasDynamicSlotName) { + patchFlag |= PatchFlags.DYNAMIC_SLOTS + } + } else { + // only v-for fragments will have keyed/unkeyed flags + args.push(node.children) + } + } + // patchFlag & dynamicPropNames + if (patchFlag !== 0) { + if (!hasChildren) { + if (!hasProps) { + args.push(`null`) + } + args.push(`null`) + } + args.push(String(patchFlag)) + if (dynamicPropNames && dynamicPropNames.length) { + args.push( + `[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]` + ) } - args.push(isComponent ? buildSlots(node, context) : node.children) } const { loc } = node @@ -118,17 +145,30 @@ export function buildProps( ): { props: PropsExpression | undefined directives: DirectiveNode[] + patchFlag: number + dynamicPropNames: string[] } { let isStatic = true let properties: ObjectExpression['properties'] = [] const mergeArgs: PropsExpression[] = [] const runtimeDirectives: DirectiveNode[] = [] + // patchFlag analysis + let patchFlag = 0 + const dynamicPropNames: string[] = [] + let hasDynammicKeys = false + let hasClassBinding = false + let hasStyleBinding = false + let hasRef = false + for (let i = 0; i < props.length; i++) { // static attribute const prop = props[i] if (prop.type === NodeTypes.ATTRIBUTE) { const { loc, name, value } = prop + if (name === 'ref') { + hasRef = true + } properties.push( createObjectProperty( createSimpleExpression( @@ -162,6 +202,7 @@ export function buildProps( // special case for v-bind and v-on with no argument const isBind = name === 'bind' if (!arg && (isBind || name === 'on')) { + hasDynammicKeys = true if (exp) { if (properties.length) { mergeArgs.push( @@ -193,6 +234,24 @@ export function buildProps( continue } + // patchFlag analysis + if (isBind && arg) { + if (arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic) { + const name = arg.content + if (name === 'ref') { + hasRef = true + } else if (name === 'class') { + hasClassBinding = true + } else if (name === 'style') { + hasStyleBinding = true + } else { + dynamicPropNames.push(name) + } + } else { + hasDynammicKeys = true + } + } + const directiveTransform = context.directiveTransforms[name] if (directiveTransform) { // has built-in directive transform. @@ -243,9 +302,29 @@ export function buildProps( propsExpression = context.hoist(propsExpression) } + // determine the flags to add + if (hasDynammicKeys) { + patchFlag |= PatchFlags.FULL_PROPS + } else { + if (hasClassBinding) { + patchFlag |= PatchFlags.CLASS + } + if (hasStyleBinding) { + patchFlag |= PatchFlags.STYLE + } + if (dynamicPropNames.length) { + patchFlag |= PatchFlags.PROPS + } + } + if (patchFlag === 0 && (hasRef || runtimeDirectives.length > 0)) { + patchFlag |= PatchFlags.NEED_PATCH + } + return { props: propsExpression, - directives: runtimeDirectives + directives: runtimeDirectives, + patchFlag, + dynamicPropNames } } diff --git a/packages/compiler-core/src/transforms/vSlot.ts b/packages/compiler-core/src/transforms/vSlot.ts index 44cadf23e0..eb9fd12bb6 100644 --- a/packages/compiler-core/src/transforms/vSlot.ts +++ b/packages/compiler-core/src/transforms/vSlot.ts @@ -44,8 +44,12 @@ export const trackSlotScopes: NodeTransform = (node, context) => { export function buildSlots( { props, children, loc }: ElementNode, context: TransformContext -): ObjectExpression { +): { + slots: ObjectExpression + hasDynamicSlotName: boolean +} { const slots: Property[] = [] + let hasDynamicSlotName = false // 1. Check for default slot with slotProps on component itself. // @@ -83,11 +87,11 @@ export function buildSlots( ) break } else { - // check duplicate slot names if ( !slotName || (slotName.type === NodeTypes.SIMPLE_EXPRESSION && slotName.isStatic) ) { + // check duplicate slot names const name = slotName ? slotName.content : `default` if (seenSlotNames.has(name)) { context.onError( @@ -96,6 +100,8 @@ export function buildSlots( continue } seenSlotNames.add(name) + } else { + hasDynamicSlotName = true } slots.push( buildSlot(slotName || `default`, slotProps, children, nodeLoc) @@ -120,7 +126,10 @@ export function buildSlots( slots.push(buildSlot(`default`, undefined, children, loc)) } - return createObjectExpression(slots, loc) + return { + slots: createObjectExpression(slots, loc), + hasDynamicSlotName + } } function buildSlot( diff --git a/packages/runtime-core/__tests__/rendererFragment.spec.ts b/packages/runtime-core/__tests__/rendererFragment.spec.ts index 0be57da325..a550de7207 100644 --- a/packages/runtime-core/__tests__/rendererFragment.spec.ts +++ b/packages/runtime-core/__tests__/rendererFragment.spec.ts @@ -107,7 +107,7 @@ describe('renderer: fragment', () => { it('patch fragment children (compiler generated, unkeyed)', () => { const root = nodeOps.createElement('div') render( - createVNode(Fragment, 0, [h('div', 'one'), 'two'], PatchFlags.UNKEYED), + createVNode(Fragment, null, [h('div', 'one'), 'two'], PatchFlags.UNKEYED), root ) expect(serializeInner(root)).toBe(`
one
two`) @@ -115,7 +115,7 @@ describe('renderer: fragment', () => { render( createVNode( Fragment, - 0, + null, [h('div', 'foo'), 'bar', 'baz'], PatchFlags.UNKEYED ), @@ -130,7 +130,7 @@ describe('renderer: fragment', () => { render( createVNode( Fragment, - 0, + null, [h('div', { key: 1 }, 'one'), h('div', { key: 2 }, 'two')], PatchFlags.KEYED ), @@ -144,7 +144,7 @@ describe('renderer: fragment', () => { render( createVNode( Fragment, - 0, + null, [h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')], PatchFlags.KEYED ), diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 2ed15514f1..fad4d78b7e 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -10,11 +10,11 @@ import { isObject, isReservedProp, hasOwn, - toTypeString + toTypeString, + PatchFlags } from '@vue/shared' import { warn } from './warning' import { Data, ComponentInternalInstance } from './component' -import { PatchFlags } from './patchFlags' export type ComponentPropsOptions

= { [K in keyof P]: Prop | null diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index 0a617effcf..0f9caab641 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -6,7 +6,7 @@ import { import { VNode, normalizeVNode, createVNode, Comment } from './vnode' import { ShapeFlags } from './shapeFlags' import { handleError, ErrorCodes } from './errorHandling' -import { PatchFlags } from './patchFlags' +import { PatchFlags } from '@vue/shared' // mark the current rendering instance for asset resolution (e.g. // resolveComponent, resolveDirective) during render diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index 90fb8524c9..a7dc9be6a6 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -25,7 +25,8 @@ import { EMPTY_ARR, isReservedProp, isFunction, - isArray + isArray, + PatchFlags } from '@vue/shared' import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler' import { @@ -38,7 +39,6 @@ import { } from '@vue/reactivity' import { resolveProps } from './componentProps' import { resolveSlots } from './componentSlots' -import { PatchFlags } from './patchFlags' import { ShapeFlags } from './shapeFlags' import { pushWarningContext, popWarningContext, warn } from './warning' import { invokeDirectiveHook } from './directives' diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 6dbbbb85d2..9a7198d249 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -21,8 +21,8 @@ export { // VNode type symbols export { Text, Comment, Fragment, Portal, Suspense } from './vnode' // VNode flags -export { PublicPatchFlags as PatchFlags } from './patchFlags' export { PublicShapeFlags as ShapeFlags } from './shapeFlags' +export { PublicPatchFlags as PatchFlags } from '@vue/shared' // For advanced plugins export { getCurrentInstance } from './component' diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index b5b686d81a..f0090ffb87 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -4,11 +4,11 @@ import { isString, isObject, EMPTY_ARR, - extend + extend, + PatchFlags } from '@vue/shared' import { ComponentInternalInstance, Data, SetupProxySymbol } from './component' import { RawSlots } from './componentSlots' -import { PatchFlags } from './patchFlags' import { ShapeFlags } from './shapeFlags' import { isReactive } from '@vue/reactivity' import { AppContext } from './apiApp' @@ -131,14 +131,11 @@ export function isVNode(value: any): boolean { export function createVNode( type: VNodeTypes, - props: { [key: string]: any } | null | 0 = null, - children: any = null, + props: { [key: string]: any } | null = null, + children: unknown = null, patchFlag: number = 0, dynamicProps: string[] | null = null ): VNode { - // Allow passing 0 for props, this can save bytes on generated code. - props = props || null - // class & style normalization. if (props !== null) { // for reactive or proxy objects, we need to clone it to enable mutation. diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 211c72d3d0..93781a8d22 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,5 @@ +export * from './patchFlags' + export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__ ? Object.freeze({}) : {} diff --git a/packages/runtime-core/src/patchFlags.ts b/packages/shared/src/patchFlags.ts similarity index 90% rename from packages/runtime-core/src/patchFlags.ts rename to packages/shared/src/patchFlags.ts index 9061107c7d..13336c2210 100644 --- a/packages/runtime-core/src/patchFlags.ts +++ b/packages/shared/src/patchFlags.ts @@ -17,12 +17,7 @@ export const enum PatchFlags { // Indicates an element with dynamic textContent (children fast path) TEXT = 1, - // Indicates an element with dynamic class. - // The compiler also pre-normalizes the :class binding: - // - b -> normalize(b) - // - ['foo', b] -> 'foo' + normalize(b) - // - { a, b: c } -> (a ? a : '') + (b ? c : '') - // - ['a', b, { c }] -> 'a' + normalize(b) + (c ? c : '') + // Indicates an element with dynamic class binding. CLASS = 1 << 1, // Indicates an element with dynamic style @@ -48,6 +43,8 @@ export const enum PatchFlags { // Indicates an element that only needs non-props patching, e.g. ref or // directives (vnodeXXX hooks). It simply marks the vnode as "need patch", // since every pathced vnode checks for refs and vnodeXXX hooks. + // This flag is never directly matched against, it simply serves as a non-zero + // value. NEED_PATCH = 1 << 5, // Indicates a fragment or element with keyed or partially-keyed v-for