]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: add new node type for v-skip node
authordaiwei <daiwei521@126.com>
Thu, 23 Jan 2025 03:14:18 +0000 (11:14 +0800)
committerdaiwei <daiwei521@126.com>
Thu, 23 Jan 2025 03:14:18 +0000 (11:14 +0800)
packages/compiler-core/src/ast.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/cacheStatic.ts
packages/compiler-core/src/transforms/vSkip.ts
packages/compiler-core/src/utils.ts
packages/compiler-ssr/src/ssrCodegenTransform.ts
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
packages/compiler-ssr/src/transforms/ssrTransformElement.ts
packages/compiler-ssr/src/transforms/ssrVSkip.ts

index 2956a4b3dc337aaad11e08f1303d8fd53948f3be..b3a9d326f61112ef144cb74a9e709e214af12732 100644 (file)
@@ -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
index 70116cfb61a9f7d6e662b64c3df79f08c7f50b23..83fd61ee24ef498dc7949d9913bbc4070528e485 100644 (file)
@@ -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)
index aeb96cc2b4adc1cb0b07a85f6caed251fd4daa2c..ca395b55fcd6e9719cc7f5ee8909d0628ceb4791 100644 (file)
@@ -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:
index 8d5961643c1c36b05f86c5ab834e33383455aa66..d0edd0753787dfce1cc0663a2a317c5d3e56fbc5 100644 (file)
@@ -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:
index 91a44480f78919616c10012931e7fb16ee1fec35..3e0951f8dd66aa35e431eda20100bb40086249f3 100644 (file)
@@ -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)
 }
index 29939683eb840ab6bc4e1d010f204a9e857accf2..b350298ca107a14f822f7e8e765851e8eef4bc28 100644 (file)
@@ -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
index 536cbb5c1e97342f7d2aa2d04ddae688e1339736..d8e3b0b00aacef0fd0c11006ede88899e65f641e 100644 (file)
@@ -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
index 6e00788e6b0e465029c45b3a11b05499eae105a9..cad1ee8102897beab4c8990b99b43366c5d42655 100644 (file)
@@ -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.
index 5ff86593642105f143f78a04490052c0511ec0d1..4a12b0f7ba78c790eea4316e7d7e4a9e3fc988d5 100644 (file)
@@ -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++) {
index a28e517caf4f93cf9b22544327d25ad1d60c6c47..751d3336f0304336639dc0c42adb5c01778e44f4 100644 (file)
@@ -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)
 }