feat(compiler-core): re-implement v-once to use cache mechanism
This commit is contained in:
@@ -4,12 +4,12 @@ import {
|
||||
TemplateChildNode,
|
||||
SimpleExpressionNode,
|
||||
ElementTypes,
|
||||
ElementCodegenNode,
|
||||
PlainElementNode,
|
||||
ComponentNode,
|
||||
TemplateNode,
|
||||
ElementNode,
|
||||
PlainElementCodegenNode
|
||||
PlainElementCodegenNode,
|
||||
CodegenNodeWithDirective
|
||||
} from '../ast'
|
||||
import { TransformContext } from '../transform'
|
||||
import { WITH_DIRECTIVES } from '../runtimeHelpers'
|
||||
@@ -57,17 +57,20 @@ function walk(
|
||||
} else {
|
||||
// node may contain dynamic children, but its props may be eligible for
|
||||
// hoisting.
|
||||
const flag = getPatchFlag(child)
|
||||
if (
|
||||
(!flag ||
|
||||
flag === PatchFlags.NEED_PATCH ||
|
||||
flag === PatchFlags.TEXT) &&
|
||||
!hasDynamicKeyOrRef(child) &&
|
||||
!hasCachedProps(child)
|
||||
) {
|
||||
const props = getNodeProps(child)
|
||||
if (props && props !== `null`) {
|
||||
getVNodeCall(child).arguments[1] = context.hoist(props)
|
||||
const codegenNode = child.codegenNode!
|
||||
if (codegenNode.type === NodeTypes.JS_CALL_EXPRESSION) {
|
||||
const flag = getPatchFlag(codegenNode)
|
||||
if (
|
||||
(!flag ||
|
||||
flag === PatchFlags.NEED_PATCH ||
|
||||
flag === PatchFlags.TEXT) &&
|
||||
!hasDynamicKeyOrRef(child) &&
|
||||
!hasCachedProps(child)
|
||||
) {
|
||||
const props = getNodeProps(child)
|
||||
if (props && props !== `null`) {
|
||||
getVNodeCall(codegenNode).arguments[1] = context.hoist(props)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +103,11 @@ export function isStaticNode(
|
||||
if (cached !== undefined) {
|
||||
return cached
|
||||
}
|
||||
const flag = getPatchFlag(node)
|
||||
const codegenNode = node.codegenNode!
|
||||
if (codegenNode.type !== NodeTypes.JS_CALL_EXPRESSION) {
|
||||
return false
|
||||
}
|
||||
const flag = getPatchFlag(codegenNode)
|
||||
if (!flag && !hasDynamicKeyOrRef(node) && !hasCachedProps(node)) {
|
||||
// element self is static. check its children.
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
@@ -165,26 +172,32 @@ function hasCachedProps(node: PlainElementNode): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
function getVNodeCall(node: PlainElementNode) {
|
||||
let codegenNode = node.codegenNode as ElementCodegenNode
|
||||
if (codegenNode.callee === WITH_DIRECTIVES) {
|
||||
codegenNode = codegenNode.arguments[0]
|
||||
function getNodeProps(node: PlainElementNode) {
|
||||
const codegenNode = node.codegenNode!
|
||||
if (codegenNode.type === NodeTypes.JS_CALL_EXPRESSION) {
|
||||
return getVNodeArgAt(
|
||||
codegenNode,
|
||||
1
|
||||
) as PlainElementCodegenNode['arguments'][1]
|
||||
}
|
||||
return codegenNode
|
||||
}
|
||||
|
||||
type NonCachedCodegenNode =
|
||||
| PlainElementCodegenNode
|
||||
| CodegenNodeWithDirective<PlainElementCodegenNode>
|
||||
|
||||
function getVNodeArgAt(
|
||||
node: PlainElementNode,
|
||||
node: NonCachedCodegenNode,
|
||||
index: number
|
||||
): PlainElementCodegenNode['arguments'][number] {
|
||||
return getVNodeCall(node).arguments[index]
|
||||
}
|
||||
|
||||
function getPatchFlag(node: PlainElementNode): number | undefined {
|
||||
function getVNodeCall(node: NonCachedCodegenNode) {
|
||||
return node.callee === WITH_DIRECTIVES ? node.arguments[0] : node
|
||||
}
|
||||
|
||||
function getPatchFlag(node: NonCachedCodegenNode): number | undefined {
|
||||
const flag = getVNodeArgAt(node, 3) as string
|
||||
return flag ? parseInt(flag, 10) : undefined
|
||||
}
|
||||
|
||||
function getNodeProps(node: PlainElementNode) {
|
||||
return getVNodeArgAt(node, 1) as PlainElementCodegenNode['arguments'][1]
|
||||
}
|
||||
|
||||
@@ -280,6 +280,11 @@ export function buildProps(
|
||||
continue
|
||||
}
|
||||
|
||||
// skip v-once - it is handled by its dedicated transform.
|
||||
if (name === 'once') {
|
||||
continue
|
||||
}
|
||||
|
||||
// special case for v-bind and v-on with no argument
|
||||
const isBind = name === 'bind'
|
||||
const isOn = name === 'on'
|
||||
|
||||
@@ -15,7 +15,8 @@ import {
|
||||
createObjectExpression,
|
||||
createObjectProperty,
|
||||
ForCodegenNode,
|
||||
ElementCodegenNode
|
||||
ElementCodegenNode,
|
||||
SlotOutletCodegenNode
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import {
|
||||
@@ -130,7 +131,7 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
: null
|
||||
if (slotOutlet) {
|
||||
// <slot v-for="..."> or <template v-for="..."><slot/></template>
|
||||
childBlock = slotOutlet.codegenNode!
|
||||
childBlock = slotOutlet.codegenNode as SlotOutletCodegenNode
|
||||
if (isTemplate && keyProperty) {
|
||||
// <template v-for="..." :key="..."><slot/></template>
|
||||
// we need to inject the key to the renderSlot() call.
|
||||
|
||||
@@ -69,6 +69,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||
if (
|
||||
!__BROWSER__ &&
|
||||
context.prefixIdentifiers &&
|
||||
context.cacheHandlers &&
|
||||
!hasScopeRef(exp, context.identifiers)
|
||||
) {
|
||||
props[1].value = context.cache(props[1].value)
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import {
|
||||
DirectiveTransform,
|
||||
createObjectProperty,
|
||||
createSimpleExpression
|
||||
} from '@vue/compiler-core'
|
||||
import { NodeTransform } from '../transform'
|
||||
import { findDir } from '../utils'
|
||||
import { NodeTypes } from '../ast'
|
||||
import { SET_BLOCK_TRACKING } from '../runtimeHelpers'
|
||||
|
||||
export const transformOnce: DirectiveTransform = dir => {
|
||||
return {
|
||||
props: [
|
||||
createObjectProperty(
|
||||
createSimpleExpression(`$once`, true, dir.loc),
|
||||
createSimpleExpression('true', false)
|
||||
)
|
||||
],
|
||||
needRuntime: false
|
||||
export const transformOnce: NodeTransform = (node, context) => {
|
||||
if (node.type === NodeTypes.ELEMENT && findDir(node, 'once', true)) {
|
||||
context.helper(SET_BLOCK_TRACKING)
|
||||
return () => {
|
||||
if (node.codegenNode) {
|
||||
node.codegenNode = context.cache(node.codegenNode, true /* isVNode */)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user