From: daiwei Date: Thu, 23 Jan 2025 03:14:18 +0000 (+0800) Subject: refactor: add new node type for v-skip node X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6529c3d03ba4ac56bb15da1db8e0901c136387f3;p=thirdparty%2Fvuejs%2Fcore.git refactor: add new node type for v-skip node --- diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index 2956a4b3dc..b3a9d326f6 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -41,6 +41,7 @@ export enum NodeTypes { IF_BRANCH, FOR, TEXT_CALL, + SKIP, // codegen VNODE_CALL, JS_CALL_EXPRESSION, @@ -100,6 +101,7 @@ export type TemplateChildNode = | IfBranchNode | ForNode | TextCallNode + | SkipNode export interface RootNode extends Node { type: NodeTypes.ROOT @@ -406,6 +408,15 @@ export interface FunctionExpression extends Node { isNonScopedSlot?: boolean } +export interface SkipNode extends Node { + type: NodeTypes.SKIP + test: ExpressionNode + consequent: IfBranchNode + alternate: IfBranchNode + newline: boolean + codegenNode?: ConditionalExpression +} + export interface ConditionalExpression extends Node { type: NodeTypes.JS_CONDITIONAL_EXPRESSION test: JSChildNode diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 70116cfb61..83fd61ee24 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -656,10 +656,11 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) { case NodeTypes.ELEMENT: case NodeTypes.IF: case NodeTypes.FOR: + case NodeTypes.SKIP: __DEV__ && assert( node.codegenNode != null, - `Codegen node is missing for element/if/for node. ` + + `Codegen node is missing for element/if/for/skip node. ` + `Apply appropriate transforms first.`, ) genNode(node.codegenNode!, context) diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index aeb96cc2b4..ca395b55fc 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -466,6 +466,10 @@ export function traverseNode( traverseNode(node.branches[i], context) } break + case NodeTypes.SKIP: + traverseNode(node.consequent, context) + traverseNode(node.alternate, context) + break case NodeTypes.IF_BRANCH: case NodeTypes.FOR: case NodeTypes.ELEMENT: diff --git a/packages/compiler-core/src/transforms/cacheStatic.ts b/packages/compiler-core/src/transforms/cacheStatic.ts index 8d5961643c..d0edd07537 100644 --- a/packages/compiler-core/src/transforms/cacheStatic.ts +++ b/packages/compiler-core/src/transforms/cacheStatic.ts @@ -341,6 +341,7 @@ export function getConstantType( case NodeTypes.IF: case NodeTypes.FOR: case NodeTypes.IF_BRANCH: + case NodeTypes.SKIP: return ConstantTypes.NOT_CONSTANT case NodeTypes.INTERPOLATION: case NodeTypes.TEXT_CALL: diff --git a/packages/compiler-core/src/transforms/vSkip.ts b/packages/compiler-core/src/transforms/vSkip.ts index 91a44480f7..3e0951f8dd 100644 --- a/packages/compiler-core/src/transforms/vSkip.ts +++ b/packages/compiler-core/src/transforms/vSkip.ts @@ -5,8 +5,8 @@ import { type IfBranchNode, NodeTypes, type SimpleExpressionNode, + type SkipNode, type SlotsExpression, - type SourceLocation, type TemplateChildNode, createConditionalExpression, createSimpleExpression, @@ -18,6 +18,7 @@ import { } from '../transform' import { ErrorCodes, + buildSlots, createCompilerError, findDir, findProp, @@ -27,61 +28,17 @@ import { } from '@vue/compiler-core' import { createCodegenNodeForBranch } from './vIf' import { validateBrowserExpression } from '../validateExpression' +import { cloneLoc } from '../parser' export const transformSkip: NodeTransform = createStructuralDirectiveTransform( 'skip', (node, dir, context) => { - return processSkip(node, dir, context, loc => { + return processSkip(node, dir, context, skipNode => { return () => { - let children: TemplateChildNode[] = [] - // for components, extract default slot without props - // if not found, throw an error - if (node.tagType === ElementTypes.COMPONENT) { - const codegenNode = node.codegenNode! - if (codegenNode.type === NodeTypes.VNODE_CALL) { - const genChildren = codegenNode.children! as SlotsExpression - if (genChildren.type === NodeTypes.JS_OBJECT_EXPRESSION) { - const prop = genChildren.properties.find( - p => - p.type === NodeTypes.JS_PROPERTY && - p.key.type === NodeTypes.SIMPLE_EXPRESSION && - p.key.content === 'default' && - p.value.params === undefined, - ) - if (prop) { - children = prop.value.returns as TemplateChildNode[] - } else { - context.onError( - createCompilerError(ErrorCodes.X_V_SKIP_UNEXPECTED_SLOT, loc), - ) - } - } - } - } - // for plain elements, take all children - else { - children = node.children - } - const consequent: IfBranchNode = { - type: NodeTypes.IF_BRANCH, - loc: node.loc, - condition: undefined, - children, - userKey: findProp(node, `key`), - } - - const alternate: IfBranchNode = { - type: NodeTypes.IF_BRANCH, - loc: node.loc, - condition: undefined, - children: [node], - userKey: findProp(node, `key`), - } - - node.codegenNode = createConditionalExpression( + skipNode.codegenNode = createConditionalExpression( dir.exp!, - createCodegenNodeForBranch(consequent, 0, context), - createCodegenNodeForBranch(alternate, 1, context), + createCodegenNodeForBranch(skipNode.consequent, 0, context), + createCodegenNodeForBranch(skipNode.alternate, 1, context), ) } }) @@ -92,7 +49,7 @@ export function processSkip( node: ElementNode, dir: DirectiveNode, context: TransformContext, - processCodegen?: (loc: SourceLocation) => () => void, + processCodegen?: (skipNode: SkipNode) => () => void, ): (() => void) | undefined { const loc = dir.exp ? dir.exp.loc : node.loc if (isTemplateNode(node) || isSlotOutlet(node)) { @@ -117,5 +74,58 @@ export function processSkip( validateBrowserExpression(dir.exp as SimpleExpressionNode, context) } - if (processCodegen) return processCodegen(loc) + let children: TemplateChildNode[] = [] + // for components, extract default slot without props + // if not found, throw an error + if (node.tagType === ElementTypes.COMPONENT) { + const { slots } = buildSlots(node, context) + const genChildren = slots as SlotsExpression + if (genChildren.type === NodeTypes.JS_OBJECT_EXPRESSION) { + const prop = genChildren.properties.find( + p => + p.type === NodeTypes.JS_PROPERTY && + p.key.type === NodeTypes.SIMPLE_EXPRESSION && + p.key.content === 'default' && + p.value.params === undefined, + ) + if (prop) { + children = prop.value.returns as TemplateChildNode[] + } else { + context.onError( + createCompilerError(ErrorCodes.X_V_SKIP_UNEXPECTED_SLOT, loc), + ) + } + } + } + // for plain elements, take all children + else { + children = node.children + } + + const consequent: IfBranchNode = { + type: NodeTypes.IF_BRANCH, + loc: node.loc, + condition: undefined, + children, + userKey: findProp(node, `key`), + } + + const alternate: IfBranchNode = { + type: NodeTypes.IF_BRANCH, + loc: node.loc, + condition: undefined, + children: [node], + userKey: findProp(node, `key`), + } + + const skipNode: SkipNode = { + type: NodeTypes.SKIP, + loc: cloneLoc(node.loc), + test: dir.exp, + consequent, + alternate, + newline: true, + } + context.replaceNode(skipNode) + if (processCodegen) return processCodegen(skipNode) } diff --git a/packages/compiler-core/src/utils.ts b/packages/compiler-core/src/utils.ts index 29939683eb..b350298ca1 100644 --- a/packages/compiler-core/src/utils.ts +++ b/packages/compiler-core/src/utils.ts @@ -528,6 +528,12 @@ export function hasScopeRef( return node.children.some(c => hasScopeRef(c, ids)) case NodeTypes.IF: return node.branches.some(b => hasScopeRef(b, ids)) + case NodeTypes.SKIP: + return ( + hasScopeRef(node.test, ids) || + node.consequent.children.some(c => hasScopeRef(c, ids)) || + node.alternate.children.some(c => hasScopeRef(c, ids)) + ) case NodeTypes.IF_BRANCH: if (hasScopeRef(node.condition, ids)) { return true diff --git a/packages/compiler-ssr/src/ssrCodegenTransform.ts b/packages/compiler-ssr/src/ssrCodegenTransform.ts index 536cbb5c1e..d8e3b0b00a 100644 --- a/packages/compiler-ssr/src/ssrCodegenTransform.ts +++ b/packages/compiler-ssr/src/ssrCodegenTransform.ts @@ -28,6 +28,7 @@ import { ssrProcessSlotOutlet } from './transforms/ssrTransformSlotOutlet' import { ssrProcessComponent } from './transforms/ssrTransformComponent' import { ssrProcessElement } from './transforms/ssrTransformElement' import { SSRErrorCodes, createSSRCompilerError } from './errors' +import { ssrProcessSkip } from './transforms/ssrVSkip' // Because SSR codegen output is completely different from client-side output // (e.g. multiple elements can be concatenated into a single template literal @@ -217,6 +218,9 @@ export function processChildren( case NodeTypes.IF_BRANCH: // no-op - handled by ssrProcessIf break + case NodeTypes.SKIP: + ssrProcessSkip(child, context) + break case NodeTypes.TEXT_CALL: case NodeTypes.COMPOUND_EXPRESSION: // no-op - these two types can never appear as template child node since diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts index 6e00788e6b..cad1ee8102 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts @@ -34,7 +34,6 @@ import { createRoot, createSimpleExpression, createTransformContext, - findDir, getBaseTransformPreset, locStub, resolveComponentType, @@ -62,7 +61,6 @@ import { ssrProcessTransition, ssrTransformTransition, } from './ssrTransformTransition' -import { ssrProcessSkip } from './ssrVSkip' // We need to construct the slot functions in the 1st pass to ensure proper // scope tracking, but the children of each slot cannot be processed until @@ -208,12 +206,6 @@ export function ssrProcessComponent( context: SSRTransformContext, parent: { children: TemplateChildNode[] }, ): void { - const skipDir = findDir(node, 'skip') - if (skipDir) { - ssrProcessSkip(node, skipDir, context) - return - } - const component = componentTypeMap.get(node)! if (!node.ssrCodegenNode) { // this is a built-in component that fell-through. diff --git a/packages/compiler-ssr/src/transforms/ssrTransformElement.ts b/packages/compiler-ssr/src/transforms/ssrTransformElement.ts index 5ff8659364..4a12b0f7ba 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformElement.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformElement.ts @@ -57,7 +57,6 @@ import { type SSRTransformContext, processChildren, } from '../ssrCodegenTransform' -import { ssrProcessSkip } from './ssrVSkip' // for directives with children overwrite (e.g. v-html & v-text), we need to // store the raw children so that they can be added in the 2nd pass. @@ -443,12 +442,6 @@ export function ssrProcessElement( node: PlainElementNode, context: SSRTransformContext, ): void { - const skipDir = findDir(node, 'skip') - if (skipDir) { - ssrProcessSkip(node, skipDir, context) - return - } - const isVoidTag = context.options.isVoidTag || NO const elementsToAdd = node.ssrCodegenNode!.elements for (let j = 0; j < elementsToAdd.length; j++) { diff --git a/packages/compiler-ssr/src/transforms/ssrVSkip.ts b/packages/compiler-ssr/src/transforms/ssrVSkip.ts index a28e517caf..751d3336f0 100644 --- a/packages/compiler-ssr/src/transforms/ssrVSkip.ts +++ b/packages/compiler-ssr/src/transforms/ssrVSkip.ts @@ -1,10 +1,6 @@ import { - type ComponentNode, - type DirectiveNode, - type IfBranchNode, type NodeTransform, - NodeTypes, - type PlainElementNode, + type SkipNode, createIfStatement, createStructuralDirectiveTransform, processSkip, @@ -16,30 +12,13 @@ export const ssrTransformSkip: NodeTransform = createStructuralDirectiveTransform('skip', processSkip) export function ssrProcessSkip( - node: PlainElementNode | ComponentNode, - dir: DirectiveNode, + node: SkipNode, context: SSRTransformContext, ): void { - node.props = node.props.filter(x => x.name !== 'skip') - const consequent: IfBranchNode = { - type: NodeTypes.IF_BRANCH, - loc: node.loc, - condition: undefined, - children: node.children, - } - - const alternate: IfBranchNode = { - type: NodeTypes.IF_BRANCH, - loc: node.loc, - condition: undefined, - children: [node], - } - - const ifNode = createIfStatement( - dir.exp!, - processIfBranch(consequent, context), - processIfBranch(alternate, context), + const ifStatement = createIfStatement( + node.test, + processIfBranch(node.consequent, context), + processIfBranch(node.alternate, context), ) - - context.pushStatement(ifNode) + context.pushStatement(ifStatement) }