feat(compiler): generate patchFlags for runtime
This commit is contained in:
parent
da0d785d84
commit
d67418002f
@ -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)
|
||||
}"
|
||||
`;
|
||||
|
@ -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),
|
||||
|
@ -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(
|
||||
`<div class="foo" :class="{ bar: isBar }" />`,
|
||||
{
|
||||
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(`<div :class="foo" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.CLASS))
|
||||
})
|
||||
|
||||
test('STYLE', () => {
|
||||
const { node } = parseWithBind(`<div :style="foo" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.STYLE))
|
||||
})
|
||||
|
||||
test('PROPS', () => {
|
||||
const { node } = parseWithBind(`<div id="foo" :foo="bar" :baz="qux" />`)
|
||||
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(
|
||||
`<div id="foo" :class="cls" :style="styl" :foo="bar" :baz="qux"/>`
|
||||
)
|
||||
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(`<div v-bind="foo" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS))
|
||||
})
|
||||
|
||||
test('FULL_PROPS (dynamic key)', () => {
|
||||
const { node } = parseWithBind(`<div :[foo]="bar" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS))
|
||||
})
|
||||
|
||||
test('FULL_PROPS (w/ others)', () => {
|
||||
const { node } = parseWithBind(
|
||||
`<div id="foo" v-bind="bar" :class="cls" />`
|
||||
)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.FULL_PROPS))
|
||||
})
|
||||
|
||||
test('NEED_PATCH (static ref)', () => {
|
||||
const { node } = parseWithBind(`<div ref="foo" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH))
|
||||
})
|
||||
|
||||
test('NEED_PATCH (dynamic ref)', () => {
|
||||
const { node } = parseWithBind(`<div :ref="foo" />`)
|
||||
expect(node.arguments.length).toBe(4)
|
||||
expect(node.arguments[3]).toBe(String(PatchFlags.NEED_PATCH))
|
||||
})
|
||||
|
||||
test('NEED_PATCH (custom directives)', () => {
|
||||
const { node } = parseWithBind(`<div v-foo />`)
|
||||
const vnodeCall = node.arguments[0] as CallExpression
|
||||
expect(vnodeCall.arguments.length).toBe(4)
|
||||
expect(vnodeCall.arguments[3]).toBe(String(PatchFlags.NEED_PATCH))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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<TransformOptions> {
|
||||
onNodeRemoved: () => void
|
||||
addIdentifiers(exp: ExpressionNode): void
|
||||
removeIdentifiers(exp: ExpressionNode): void
|
||||
hoist(exp: JSChildNode): ExpressionNode
|
||||
hoist(exp: JSChildNode): SimpleExpressionNode
|
||||
}
|
||||
|
||||
function createTransformContext(
|
||||
|
@ -1 +0,0 @@
|
||||
// TODO
|
@ -1 +0,0 @@
|
||||
// TODO
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
// <Comp v-slot="{ prop }"/>
|
||||
@ -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(
|
||||
|
@ -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(`<!----><div>one</div>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
|
||||
),
|
||||
|
@ -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<P = Data> = {
|
||||
[K in keyof P]: Prop<P[K]> | null
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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.
|
||||
|
@ -1,3 +1,5 @@
|
||||
export * from './patchFlags'
|
||||
|
||||
export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
|
||||
? Object.freeze({})
|
||||
: {}
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user