feat(compiler): annotate patchFlags in generated code

This commit is contained in:
Evan You 2019-10-01 17:53:57 -04:00
parent 4021307f4c
commit 4fc963bc5a
7 changed files with 70 additions and 30 deletions

View File

@ -20,7 +20,7 @@ return function render() {
_createVNode(\\"span\\", null, _toString(value + index)) _createVNode(\\"span\\", null, _toString(value + index))
]) ])
}))) })))
], 2) ], 2 /* CLASS */)
} }
}" }"
`; `;
@ -43,7 +43,7 @@ return function render() {
createVNode(\\"span\\", null, toString(value + index)) createVNode(\\"span\\", null, toString(value + index))
]) ])
}))) })))
], 2) ], 2 /* CLASS */)
}" }"
`; `;
@ -65,6 +65,6 @@ export default function render() {
createVNode(\\"span\\", null, _toString(value + index)) createVNode(\\"span\\", null, _toString(value + index))
]) ])
}))) })))
], 2) ], 2 /* CLASS */)
}" }"
`; `;

View File

@ -16,7 +16,7 @@ return function render() {
toString(_ctx.foo), toString(_ctx.foo),
toString(bar) toString(bar)
] ]
}, 256) }, 256 /* DYNAMIC_SLOTS */)
}" }"
`; `;

View File

@ -319,7 +319,7 @@ describe('compiler: element transform', () => {
] ]
}, },
`null`, `null`,
String(PatchFlags.NEED_PATCH) // should generate appropriate flag `${PatchFlags.NEED_PATCH} /* NEED_PATCH */` // should generate appropriate flag
] ]
}, },
{ {
@ -565,19 +565,19 @@ describe('compiler: element transform', () => {
test('CLASS', () => { test('CLASS', () => {
const { node } = parseWithBind(`<div :class="foo" />`) const { node } = parseWithBind(`<div :class="foo" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.CLASS)) expect(node.arguments[3]).toBe(`${PatchFlags.CLASS} /* CLASS */`)
}) })
test('STYLE', () => { test('STYLE', () => {
const { node } = parseWithBind(`<div :style="foo" />`) const { node } = parseWithBind(`<div :style="foo" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.STYLE)) expect(node.arguments[3]).toBe(`${PatchFlags.STYLE} /* STYLE */`)
}) })
test('PROPS', () => { test('PROPS', () => {
const { node } = parseWithBind(`<div id="foo" :foo="bar" :baz="qux" />`) const { node } = parseWithBind(`<div id="foo" :foo="bar" :baz="qux" />`)
expect(node.arguments.length).toBe(5) expect(node.arguments.length).toBe(5)
expect(node.arguments[3]).toBe(String(PatchFlags.PROPS)) expect(node.arguments[3]).toBe(`${PatchFlags.PROPS} /* PROPS */`)
expect(node.arguments[4]).toBe(`["foo", "baz"]`) expect(node.arguments[4]).toBe(`["foo", "baz"]`)
}) })
@ -587,7 +587,9 @@ describe('compiler: element transform', () => {
) )
expect(node.arguments.length).toBe(5) expect(node.arguments.length).toBe(5)
expect(node.arguments[3]).toBe( expect(node.arguments[3]).toBe(
String(PatchFlags.PROPS | PatchFlags.CLASS | PatchFlags.STYLE) `${PatchFlags.PROPS |
PatchFlags.CLASS |
PatchFlags.STYLE} /* CLASS, STYLE, PROPS */`
) )
expect(node.arguments[4]).toBe(`["foo", "baz"]`) expect(node.arguments[4]).toBe(`["foo", "baz"]`)
}) })
@ -595,13 +597,17 @@ describe('compiler: element transform', () => {
test('FULL_PROPS (v-bind)', () => { test('FULL_PROPS (v-bind)', () => {
const { node } = parseWithBind(`<div v-bind="foo" />`) const { node } = parseWithBind(`<div v-bind="foo" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) expect(node.arguments[3]).toBe(
`${PatchFlags.FULL_PROPS} /* FULL_PROPS */`
)
}) })
test('FULL_PROPS (dynamic key)', () => { test('FULL_PROPS (dynamic key)', () => {
const { node } = parseWithBind(`<div :[foo]="bar" />`) const { node } = parseWithBind(`<div :[foo]="bar" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) expect(node.arguments[3]).toBe(
`${PatchFlags.FULL_PROPS} /* FULL_PROPS */`
)
}) })
test('FULL_PROPS (w/ others)', () => { test('FULL_PROPS (w/ others)', () => {
@ -609,26 +615,34 @@ describe('compiler: element transform', () => {
`<div id="foo" v-bind="bar" :class="cls" />` `<div id="foo" v-bind="bar" :class="cls" />`
) )
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS)) expect(node.arguments[3]).toBe(
`${PatchFlags.FULL_PROPS} /* FULL_PROPS */`
)
}) })
test('NEED_PATCH (static ref)', () => { test('NEED_PATCH (static ref)', () => {
const { node } = parseWithBind(`<div ref="foo" />`) const { node } = parseWithBind(`<div ref="foo" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) expect(node.arguments[3]).toBe(
`${PatchFlags.NEED_PATCH} /* NEED_PATCH */`
)
}) })
test('NEED_PATCH (dynamic ref)', () => { test('NEED_PATCH (dynamic ref)', () => {
const { node } = parseWithBind(`<div :ref="foo" />`) const { node } = parseWithBind(`<div :ref="foo" />`)
expect(node.arguments.length).toBe(4) expect(node.arguments.length).toBe(4)
expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) expect(node.arguments[3]).toBe(
`${PatchFlags.NEED_PATCH} /* NEED_PATCH */`
)
}) })
test('NEED_PATCH (custom directives)', () => { test('NEED_PATCH (custom directives)', () => {
const { node } = parseWithBind(`<div v-foo />`) const { node } = parseWithBind(`<div v-foo />`)
const vnodeCall = node.arguments[0] as CallExpression const vnodeCall = node.arguments[0] as CallExpression
expect(vnodeCall.arguments.length).toBe(4) expect(vnodeCall.arguments.length).toBe(4)
expect(vnodeCall.arguments[3]).toBe(String(PatchFlags.NEED_PATCH)) expect(vnodeCall.arguments[3]).toBe(
`${PatchFlags.NEED_PATCH} /* NEED_PATCH */`
)
}) })
}) })
}) })

View File

@ -16,7 +16,7 @@ import {
Property, Property,
SourceLocation SourceLocation
} from '../ast' } from '../ast'
import { isArray, PatchFlags } from '@vue/shared' import { isArray, PatchFlags, PatchFlagNames } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors' import { createCompilerError, ErrorCodes } from '../errors'
import { import {
CREATE_VNODE, CREATE_VNODE,
@ -99,7 +99,15 @@ export const transformElement: NodeTransform = (node, context) => {
} }
args.push(`null`) args.push(`null`)
} }
args.push(String(patchFlag)) if (__DEV__) {
const flagNames = Object.keys(PatchFlagNames)
.filter(n => patchFlag & Number(n))
.map(n => PatchFlagNames[n as any])
.join(`, `)
args.push(patchFlag + ` /* ${flagNames} */`)
} else {
args.push(patchFlag + '')
}
if (dynamicPropNames && dynamicPropNames.length) { if (dynamicPropNames && dynamicPropNames.length) {
args.push( args.push(
`[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]` `[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`

View File

@ -107,7 +107,12 @@ describe('renderer: fragment', () => {
it('patch fragment children (compiler generated, unkeyed)', () => { it('patch fragment children (compiler generated, unkeyed)', () => {
const root = nodeOps.createElement('div') const root = nodeOps.createElement('div')
render( render(
createVNode(Fragment, null, [h('div', 'one'), 'two'], PatchFlags.UNKEYED), createVNode(
Fragment,
null,
[h('div', 'one'), 'two'],
PatchFlags.UNKEYED_V_FOR
),
root root
) )
expect(serializeInner(root)).toBe(`<!----><div>one</div>two<!---->`) expect(serializeInner(root)).toBe(`<!----><div>one</div>two<!---->`)
@ -117,7 +122,7 @@ describe('renderer: fragment', () => {
Fragment, Fragment,
null, null,
[h('div', 'foo'), 'bar', 'baz'], [h('div', 'foo'), 'bar', 'baz'],
PatchFlags.UNKEYED PatchFlags.UNKEYED_V_FOR
), ),
root root
) )
@ -132,7 +137,7 @@ describe('renderer: fragment', () => {
Fragment, Fragment,
null, null,
[h('div', { key: 1 }, 'one'), h('div', { key: 2 }, 'two')], [h('div', { key: 1 }, 'one'), h('div', { key: 2 }, 'two')],
PatchFlags.KEYED PatchFlags.KEYED_V_FOR
), ),
root root
) )
@ -146,7 +151,7 @@ describe('renderer: fragment', () => {
Fragment, Fragment,
null, null,
[h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')], [h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')],
PatchFlags.KEYED PatchFlags.KEYED_V_FOR
), ),
root root
) )

View File

@ -1230,7 +1230,7 @@ export function createRenderer<
// fast path // fast path
const { patchFlag, shapeFlag } = n2 const { patchFlag, shapeFlag } = n2
if (patchFlag) { if (patchFlag) {
if (patchFlag & PatchFlags.KEYED) { if (patchFlag & PatchFlags.KEYED_V_FOR) {
// this could be either fully-keyed or mixed (some keyed some not) // this could be either fully-keyed or mixed (some keyed some not)
// presence of patchFlag means children are guaranteed to be arrays // presence of patchFlag means children are guaranteed to be arrays
patchKeyedChildren( patchKeyedChildren(
@ -1244,7 +1244,7 @@ export function createRenderer<
optimized optimized
) )
return return
} else if (patchFlag & PatchFlags.UNKEYED) { } else if (patchFlag & PatchFlags.UNKEYED_V_FOR) {
// unkeyed // unkeyed
patchUnkeyedChildren( patchUnkeyedChildren(
c1 as HostVNode[], c1 as HostVNode[],

View File

@ -47,12 +47,11 @@ export const enum PatchFlags {
// value. // value.
NEED_PATCH = 1 << 5, NEED_PATCH = 1 << 5,
// Indicates a fragment or element with keyed or partially-keyed v-for // Indicates a v-for fragment with keyed or partially keyed children
// children KEYED_V_FOR = 1 << 6,
KEYED = 1 << 6,
// Indicates a fragment or element that contains unkeyed v-for children // Indicates a v-for fragment with unkeyed children.
UNKEYED = 1 << 7, UNKEYED_V_FOR = 1 << 7,
// Indicates a component with dynamic slots (e.g. slot that references a v-for // Indicates a component with dynamic slots (e.g. slot that references a v-for
// iterated value, or dynamic slot names). // iterated value, or dynamic slot names).
@ -68,6 +67,20 @@ export const PublicPatchFlags = {
PROPS: PatchFlags.PROPS, PROPS: PatchFlags.PROPS,
NEED_PATCH: PatchFlags.NEED_PATCH, NEED_PATCH: PatchFlags.NEED_PATCH,
FULL_PROPS: PatchFlags.FULL_PROPS, FULL_PROPS: PatchFlags.FULL_PROPS,
KEYED: PatchFlags.KEYED, KEYED_V_FOR: PatchFlags.KEYED_V_FOR,
UNKEYED: PatchFlags.UNKEYED UNKEYED_V_FOR: PatchFlags.UNKEYED_V_FOR,
DYNAMIC_SLOTS: PatchFlags.DYNAMIC_SLOTS
}
// dev only flag -> name mapping
export const PatchFlagNames = {
[PatchFlags.TEXT]: `TEXT`,
[PatchFlags.CLASS]: `CLASS`,
[PatchFlags.STYLE]: `STYLE`,
[PatchFlags.PROPS]: `PROPS`,
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
[PatchFlags.FULL_PROPS]: `FULL_PROPS`,
[PatchFlags.KEYED_V_FOR]: `KEYED_V_FOR`,
[PatchFlags.UNKEYED_V_FOR]: `UNKEYED_V_FOR`,
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`
} }