mirror of https://github.com/vuejs/core.git
refactor(compiler-vapor): dynamicFlag
This commit is contained in:
parent
63a127b612
commit
79636ddc5b
|
|
@ -21,14 +21,15 @@ export function render(_ctx) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: v-if > comment between branches 1`] = `
|
exports[`compiler: v-if > comment between branches 1`] = `
|
||||||
"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
|
"import { template as _template, children as _children, createIf as _createIf, prepend as _prepend, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const t0 = _template("<div></div>")
|
const t0 = _template("<div></div>")
|
||||||
const t1 = _template("<!--foo--><p></p>")
|
const t1 = _template("<!--foo--><p></p>")
|
||||||
const t2 = _template("<!--bar-->fine")
|
const t2 = _template("<!--bar-->fine")
|
||||||
const t3 = _fragment()
|
const t3 = _template("<input>")
|
||||||
const n0 = t3()
|
const n0 = t3()
|
||||||
|
const { 0: [n5],} = _children(n0)
|
||||||
const n1 = _createIf(() => (_ctx.ok), () => {
|
const n1 = _createIf(() => (_ctx.ok), () => {
|
||||||
const n2 = t0()
|
const n2 = t0()
|
||||||
return n2
|
return n2
|
||||||
|
|
@ -40,6 +41,9 @@ export function render(_ctx) {
|
||||||
return n4
|
return n4
|
||||||
}))
|
}))
|
||||||
_prepend(n0, n1)
|
_prepend(n0, n1)
|
||||||
|
_renderEffect(() => {
|
||||||
|
_setText(n5, _ctx.text)
|
||||||
|
})
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
|
import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
|
||||||
import { IRNodeTypes, transformElement, transformVBind } from '../../src'
|
import {
|
||||||
|
DynamicFlag,
|
||||||
|
IRNodeTypes,
|
||||||
|
transformElement,
|
||||||
|
transformVBind,
|
||||||
|
} from '../../src'
|
||||||
import { makeCompile } from './_utils'
|
import { makeCompile } from './_utils'
|
||||||
|
|
||||||
const compileWithVBind = makeCompile({
|
const compileWithVBind = makeCompile({
|
||||||
|
|
@ -15,7 +20,7 @@ describe('compiler v-bind', () => {
|
||||||
|
|
||||||
expect(ir.dynamic.children[0]).toMatchObject({
|
expect(ir.dynamic.children[0]).toMatchObject({
|
||||||
id: 1,
|
id: 1,
|
||||||
referenced: true,
|
dynamicFlags: DynamicFlag.REFERENCED,
|
||||||
})
|
})
|
||||||
expect(ir.template[0]).toMatchObject({
|
expect(ir.template[0]).toMatchObject({
|
||||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,7 @@ describe('compiler: v-if', () => {
|
||||||
<p v-else-if="orNot"/>
|
<p v-else-if="orNot"/>
|
||||||
<!--bar-->
|
<!--bar-->
|
||||||
<template v-else>fine</template>
|
<template v-else>fine</template>
|
||||||
|
<input v-text="text" />
|
||||||
`)
|
`)
|
||||||
expect(code).matchSnapshot()
|
expect(code).matchSnapshot()
|
||||||
expect(ir.template).lengthOf(4)
|
expect(ir.template).lengthOf(4)
|
||||||
|
|
@ -292,7 +293,10 @@ describe('compiler: v-if', () => {
|
||||||
template: '<!--bar-->fine',
|
template: '<!--bar-->fine',
|
||||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||||
},
|
},
|
||||||
{ type: IRNodeTypes.FRAGMENT_FACTORY },
|
{
|
||||||
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||||
|
template: '<input>',
|
||||||
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import {
|
import {
|
||||||
type BlockFunctionIRNode,
|
type BlockFunctionIRNode,
|
||||||
|
DynamicFlag,
|
||||||
type IRDynamicChildren,
|
type IRDynamicChildren,
|
||||||
IRNodeTypes,
|
IRNodeTypes,
|
||||||
type OperationNode,
|
type OperationNode,
|
||||||
|
|
@ -317,21 +318,28 @@ function genChildren(children: IRDynamicChildren) {
|
||||||
let offset = 0
|
let offset = 0
|
||||||
for (const [index, child] of Object.entries(children)) {
|
for (const [index, child] of Object.entries(children)) {
|
||||||
const childrenLength = Object.keys(child.children).length
|
const childrenLength = Object.keys(child.children).length
|
||||||
if (child.ghost && child.placeholder === null && childrenLength === 0) {
|
if (
|
||||||
|
child.dynamicFlags & DynamicFlag.NON_TEMPLATE ||
|
||||||
|
(child.dynamicFlags & DynamicFlag.INSERT &&
|
||||||
|
child.placeholder === null &&
|
||||||
|
childrenLength === 0)
|
||||||
|
) {
|
||||||
offset--
|
offset--
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
code += ` ${Number(index) + offset}: [`
|
const idx = Number(index) + offset
|
||||||
|
const id =
|
||||||
const id = child.ghost ? child.placeholder : child.id
|
child.dynamicFlags & DynamicFlag.INSERT ? child.placeholder : child.id
|
||||||
if (id !== null) code += `n${id}`
|
|
||||||
|
|
||||||
const childrenString = childrenLength && genChildren(child.children)
|
const childrenString = childrenLength && genChildren(child.children)
|
||||||
if (childrenString) code += `, ${childrenString}`
|
|
||||||
|
|
||||||
|
if (id !== null || childrenString) {
|
||||||
|
code += ` ${idx}: [`
|
||||||
|
if (id !== null) code += `n${id}`
|
||||||
|
if (childrenString) code += `, ${childrenString}`
|
||||||
code += '],'
|
code += '],'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!code) return ''
|
if (!code) return ''
|
||||||
return `{${code}}`
|
return `{${code}}`
|
||||||
|
|
|
||||||
|
|
@ -180,11 +180,25 @@ export type OperationNode =
|
||||||
|
|
||||||
export type BlockIRNode = RootIRNode | BlockFunctionIRNode
|
export type BlockIRNode = RootIRNode | BlockFunctionIRNode
|
||||||
|
|
||||||
|
export enum DynamicFlag {
|
||||||
|
NONE = 0,
|
||||||
|
/**
|
||||||
|
* This node is referenced and needs to be saved as a variable.
|
||||||
|
*/
|
||||||
|
REFERENCED = 1,
|
||||||
|
/**
|
||||||
|
* This node is not generated from template, but is generated dynamically.
|
||||||
|
*/
|
||||||
|
NON_TEMPLATE = 1 << 1,
|
||||||
|
/**
|
||||||
|
* This node needs to be inserted back into the template.
|
||||||
|
*/
|
||||||
|
INSERT = 1 << 2,
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRDynamicInfo {
|
export interface IRDynamicInfo {
|
||||||
id: number | null
|
id: number | null
|
||||||
referenced: boolean
|
dynamicFlags: DynamicFlag
|
||||||
/** created by DOM API */
|
|
||||||
ghost: boolean
|
|
||||||
placeholder: number | null
|
placeholder: number | null
|
||||||
children: IRDynamicChildren
|
children: IRDynamicChildren
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,17 @@ import {
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
|
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
|
type BlockIRNode,
|
||||||
|
DynamicFlag,
|
||||||
|
type FragmentFactoryIRNode,
|
||||||
|
type HackOptions,
|
||||||
type IRDynamicInfo,
|
type IRDynamicInfo,
|
||||||
type IRExpression,
|
type IRExpression,
|
||||||
IRNodeTypes,
|
IRNodeTypes,
|
||||||
type OperationNode,
|
type OperationNode,
|
||||||
type RootIRNode,
|
type RootIRNode,
|
||||||
} from './ir'
|
type TemplateFactoryIRNode,
|
||||||
import type {
|
type VaporDirectiveNode,
|
||||||
BlockIRNode,
|
|
||||||
FragmentFactoryIRNode,
|
|
||||||
HackOptions,
|
|
||||||
TemplateFactoryIRNode,
|
|
||||||
VaporDirectiveNode,
|
|
||||||
} from './ir'
|
} from './ir'
|
||||||
|
|
||||||
export type NodeTransform = (
|
export type NodeTransform = (
|
||||||
|
|
@ -100,6 +99,13 @@ const defaultOptions = {
|
||||||
onWarn: defaultOnWarn,
|
onWarn: defaultOnWarn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const genDefaultDynamic = (): IRDynamicInfo => ({
|
||||||
|
id: null,
|
||||||
|
dynamicFlags: 0,
|
||||||
|
placeholder: null,
|
||||||
|
children: {},
|
||||||
|
})
|
||||||
|
|
||||||
// TODO use class for better perf
|
// TODO use class for better perf
|
||||||
function createRootContext(
|
function createRootContext(
|
||||||
root: RootIRNode,
|
root: RootIRNode,
|
||||||
|
|
@ -135,7 +141,7 @@ function createRootContext(
|
||||||
increaseId: () => globalId++,
|
increaseId: () => globalId++,
|
||||||
reference() {
|
reference() {
|
||||||
if (this.dynamic.id !== null) return this.dynamic.id
|
if (this.dynamic.id !== null) return this.dynamic.id
|
||||||
this.dynamic.referenced = true
|
this.dynamic.dynamicFlags |= DynamicFlag.REFERENCED
|
||||||
return (this.dynamic.id = this.increaseId())
|
return (this.dynamic.id = this.increaseId())
|
||||||
},
|
},
|
||||||
registerEffect(expressions, operations) {
|
registerEffect(expressions, operations) {
|
||||||
|
|
@ -220,14 +226,8 @@ function createContext<T extends TemplateChildNode>(
|
||||||
|
|
||||||
template: '',
|
template: '',
|
||||||
childrenTemplate: [],
|
childrenTemplate: [],
|
||||||
dynamic: {
|
dynamic: genDefaultDynamic(),
|
||||||
id: null,
|
} satisfies Partial<TransformContext<T>>)
|
||||||
referenced: false,
|
|
||||||
ghost: false,
|
|
||||||
placeholder: null,
|
|
||||||
children: {},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,13 +243,9 @@ export function transform(
|
||||||
loc: root.loc,
|
loc: root.loc,
|
||||||
template: [],
|
template: [],
|
||||||
templateIndex: -1,
|
templateIndex: -1,
|
||||||
dynamic: {
|
dynamic: extend(genDefaultDynamic(), {
|
||||||
id: null,
|
dynamicFlags: DynamicFlag.REFERENCED | DynamicFlag.INSERT,
|
||||||
referenced: true,
|
} satisfies Partial<IRDynamicInfo>),
|
||||||
ghost: true,
|
|
||||||
placeholder: null,
|
|
||||||
children: {},
|
|
||||||
},
|
|
||||||
effect: [],
|
effect: [],
|
||||||
operation: [],
|
operation: [],
|
||||||
}
|
}
|
||||||
|
|
@ -287,6 +283,7 @@ function transformNode(
|
||||||
node = context.node
|
node = context.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case NodeTypes.ROOT:
|
case NodeTypes.ROOT:
|
||||||
case NodeTypes.ELEMENT: {
|
case NodeTypes.ELEMENT: {
|
||||||
|
|
@ -322,15 +319,8 @@ function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
|
||||||
const childContext = createContext(child, ctx, i)
|
const childContext = createContext(child, ctx, i)
|
||||||
transformNode(childContext)
|
transformNode(childContext)
|
||||||
ctx.childrenTemplate.push(childContext.template)
|
ctx.childrenTemplate.push(childContext.template)
|
||||||
if (
|
|
||||||
childContext.dynamic.ghost ||
|
|
||||||
childContext.dynamic.referenced ||
|
|
||||||
childContext.dynamic.placeholder ||
|
|
||||||
Object.keys(childContext.dynamic.children).length
|
|
||||||
) {
|
|
||||||
ctx.dynamic.children[i] = childContext.dynamic
|
ctx.dynamic.children[i] = childContext.dynamic
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
processDynamicChildren(ctx)
|
processDynamicChildren(ctx)
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +334,7 @@ function processDynamicChildren(ctx: TransformContext<RootNode | ElementNode>) {
|
||||||
for (let index = 0; index < node.children.length; index++) {
|
for (let index = 0; index < node.children.length; index++) {
|
||||||
const child = ctx.dynamic.children[index]
|
const child = ctx.dynamic.children[index]
|
||||||
|
|
||||||
if (!child || !child.ghost) {
|
if (!child || !(child.dynamicFlags & DynamicFlag.INSERT)) {
|
||||||
if (prevChildren.length) {
|
if (prevChildren.length) {
|
||||||
if (hasStatic) {
|
if (hasStatic) {
|
||||||
ctx.childrenTemplate[index - prevChildren.length] = `<!>`
|
ctx.childrenTemplate[index - prevChildren.length] = `<!>`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { NodeTypes, type SimpleExpressionNode } from '@vue/compiler-dom'
|
import { NodeTypes, type SimpleExpressionNode } from '@vue/compiler-dom'
|
||||||
import type { NodeTransform } from '../transform'
|
import type { NodeTransform } from '../transform'
|
||||||
import { IRNodeTypes } from '../ir'
|
import { DynamicFlag, IRNodeTypes } from '../ir'
|
||||||
|
|
||||||
export const transformInterpolation: NodeTransform = (node, ctx) => {
|
export const transformInterpolation: NodeTransform = (node, ctx) => {
|
||||||
if (node.type !== NodeTypes.INTERPOLATION) return
|
if (node.type !== NodeTypes.INTERPOLATION) return
|
||||||
|
|
@ -27,7 +27,7 @@ export const transformInterpolation: NodeTransform = (node, ctx) => {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
const id = ctx.reference()
|
const id = ctx.reference()
|
||||||
ctx.dynamic.ghost = true
|
ctx.dynamic.dynamicFlags |= DynamicFlag.INSERT
|
||||||
ctx.registerOperation({
|
ctx.registerOperation({
|
||||||
type: IRNodeTypes.CREATE_TEXT_NODE,
|
type: IRNodeTypes.CREATE_TEXT_NODE,
|
||||||
loc: node.loc,
|
loc: node.loc,
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,12 @@ import {
|
||||||
import {
|
import {
|
||||||
type TransformContext,
|
type TransformContext,
|
||||||
createStructuralDirectiveTransform,
|
createStructuralDirectiveTransform,
|
||||||
|
genDefaultDynamic,
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import {
|
import {
|
||||||
type BlockFunctionIRNode,
|
type BlockFunctionIRNode,
|
||||||
|
DynamicFlag,
|
||||||
|
type IRDynamicInfo,
|
||||||
IRNodeTypes,
|
IRNodeTypes,
|
||||||
type OperationNode,
|
type OperationNode,
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
|
|
@ -41,7 +44,7 @@ export function processIf(
|
||||||
|
|
||||||
if (dir.name === 'if') {
|
if (dir.name === 'if') {
|
||||||
const id = context.reference()
|
const id = context.reference()
|
||||||
context.dynamic.ghost = true
|
context.dynamic.dynamicFlags |= DynamicFlag.INSERT
|
||||||
const [branch, onExit] = createIfBranch(node, context)
|
const [branch, onExit] = createIfBranch(node, context)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -55,10 +58,13 @@ export function processIf(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
context.dynamic.dynamicFlags |= DynamicFlag.NON_TEMPLATE
|
||||||
|
|
||||||
// check the adjacent v-if
|
// check the adjacent v-if
|
||||||
const parent = context.parent!
|
const parent = context.parent!
|
||||||
const siblings = parent.node.children
|
const siblings = parent.node.children
|
||||||
const templates = parent.childrenTemplate
|
const templates = parent.childrenTemplate
|
||||||
|
const siblingsDynamic = parent.dynamic.children
|
||||||
|
|
||||||
const comments = []
|
const comments = []
|
||||||
let sibling: TemplateChildNode | undefined
|
let sibling: TemplateChildNode | undefined
|
||||||
|
|
@ -66,21 +72,19 @@ export function processIf(
|
||||||
while (i-- >= -1) {
|
while (i-- >= -1) {
|
||||||
sibling = siblings[i]
|
sibling = siblings[i]
|
||||||
|
|
||||||
if (sibling) {
|
if (
|
||||||
if (sibling.type === NodeTypes.COMMENT) {
|
sibling &&
|
||||||
__DEV__ && comments.unshift(sibling)
|
(sibling.type === NodeTypes.COMMENT ||
|
||||||
templates[i] = null
|
(sibling.type === NodeTypes.TEXT && !sibling.content.trim().length))
|
||||||
continue
|
|
||||||
} else if (
|
|
||||||
sibling.type === NodeTypes.TEXT &&
|
|
||||||
!sibling.content.trim().length
|
|
||||||
) {
|
) {
|
||||||
|
if (__DEV__ && sibling.type === NodeTypes.COMMENT)
|
||||||
|
comments.unshift(sibling)
|
||||||
|
siblingsDynamic[i].dynamicFlags |= DynamicFlag.NON_TEMPLATE
|
||||||
templates[i] = null
|
templates[i] = null
|
||||||
continue
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { operation } = context.block
|
const { operation } = context.block
|
||||||
let lastIfNode: OperationNode
|
let lastIfNode: OperationNode
|
||||||
|
|
@ -150,13 +154,9 @@ export function createIfBranch(
|
||||||
loc: node.loc,
|
loc: node.loc,
|
||||||
node,
|
node,
|
||||||
templateIndex: -1,
|
templateIndex: -1,
|
||||||
dynamic: {
|
dynamic: extend(genDefaultDynamic(), {
|
||||||
id: null,
|
dynamicFlags: DynamicFlag.REFERENCED | DynamicFlag.INSERT,
|
||||||
referenced: true,
|
} satisfies Partial<IRDynamicInfo>),
|
||||||
ghost: true,
|
|
||||||
placeholder: null,
|
|
||||||
children: {},
|
|
||||||
},
|
|
||||||
effect: [],
|
effect: [],
|
||||||
operation: [],
|
operation: [],
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +164,7 @@ export function createIfBranch(
|
||||||
const exitBlock = context.enterBlock(branch)
|
const exitBlock = context.enterBlock(branch)
|
||||||
context.reference()
|
context.reference()
|
||||||
const onExit = () => {
|
const onExit = () => {
|
||||||
context.template += context.childrenTemplate.join('')
|
context.template += context.childrenTemplate.filter(Boolean).join('')
|
||||||
context.registerTemplate()
|
context.registerTemplate()
|
||||||
exitBlock()
|
exitBlock()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue