diff --git a/packages/compiler-core/src/index.ts b/packages/compiler-core/src/index.ts index 29e5f681300..0ad4f070ebb 100644 --- a/packages/compiler-core/src/index.ts +++ b/packages/compiler-core/src/index.ts @@ -48,6 +48,7 @@ export { transformBind } from './transforms/vBind' export { noopDirectiveTransform } from './transforms/noopDirectiveTransform' export { processIf } from './transforms/vIf' export { processFor, createForLoopParams } from './transforms/vFor' +export { processSkip } from './transforms/vSkip' export { transformExpression, processExpression, diff --git a/packages/compiler-core/src/transforms/vSkip.ts b/packages/compiler-core/src/transforms/vSkip.ts index 2e5d7a42f0d..91a44480f78 100644 --- a/packages/compiler-core/src/transforms/vSkip.ts +++ b/packages/compiler-core/src/transforms/vSkip.ts @@ -1,15 +1,19 @@ import { + type DirectiveNode, + type ElementNode, ElementTypes, type IfBranchNode, NodeTypes, type SimpleExpressionNode, type SlotsExpression, + type SourceLocation, type TemplateChildNode, createConditionalExpression, createSimpleExpression, } from '../ast' import { type NodeTransform, + type TransformContext, createStructuralDirectiveTransform, } from '../transform' import { @@ -27,82 +31,91 @@ import { validateBrowserExpression } from '../validateExpression' export const transformSkip: NodeTransform = createStructuralDirectiveTransform( 'skip', (node, dir, context) => { - const loc = dir.exp ? dir.exp.loc : node.loc - if (isTemplateNode(node) || isSlotOutlet(node)) { - context.onError(createCompilerError(ErrorCodes.X_V_SKIP_ON_TEMPLATE, loc)) - return - } - - if (findDir(node, 'for')) { - context.onWarn(createCompilerError(ErrorCodes.X_V_SKIP_WITH_V_FOR, loc)) - } - - if (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim()) { - context.onError( - createCompilerError(ErrorCodes.X_V_SKIP_NO_EXPRESSION, loc), - ) - dir.exp = createSimpleExpression(`true`, false, loc) - } - - if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) { - dir.exp = processExpression(dir.exp as SimpleExpressionNode, context) - } - - if (__DEV__ && __BROWSER__ && dir.exp) { - validateBrowserExpression(dir.exp as SimpleExpressionNode, context) - } - - 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), + return processSkip(node, dir, context, loc => { + 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`), - } + // 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 alternate: IfBranchNode = { + type: NodeTypes.IF_BRANCH, + loc: node.loc, + condition: undefined, + children: [node], + userKey: findProp(node, `key`), + } - node.codegenNode = createConditionalExpression( - dir.exp!, - createCodegenNodeForBranch(consequent, 0, context), - createCodegenNodeForBranch(alternate, 1, context), - ) - } + node.codegenNode = createConditionalExpression( + dir.exp!, + createCodegenNodeForBranch(consequent, 0, context), + createCodegenNodeForBranch(alternate, 1, context), + ) + } + }) }, ) + +export function processSkip( + node: ElementNode, + dir: DirectiveNode, + context: TransformContext, + processCodegen?: (loc: SourceLocation) => () => void, +): (() => void) | undefined { + const loc = dir.exp ? dir.exp.loc : node.loc + if (isTemplateNode(node) || isSlotOutlet(node)) { + context.onError(createCompilerError(ErrorCodes.X_V_SKIP_ON_TEMPLATE, loc)) + return + } + + if (findDir(node, 'for')) { + context.onError(createCompilerError(ErrorCodes.X_V_SKIP_WITH_V_FOR, loc)) + } + + if (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim()) { + context.onError(createCompilerError(ErrorCodes.X_V_SKIP_NO_EXPRESSION, loc)) + dir.exp = createSimpleExpression(`true`, false, loc) + } + + if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) { + dir.exp = processExpression(dir.exp as SimpleExpressionNode, context) + } + + if (__DEV__ && __BROWSER__ && dir.exp) { + validateBrowserExpression(dir.exp as SimpleExpressionNode, context) + } + + if (processCodegen) return processCodegen(loc) +} diff --git a/packages/compiler-ssr/src/index.ts b/packages/compiler-ssr/src/index.ts index f8a686555e8..03bc0bb231e 100644 --- a/packages/compiler-ssr/src/index.ts +++ b/packages/compiler-ssr/src/index.ts @@ -27,6 +27,7 @@ import { ssrTransformModel } from './transforms/ssrVModel' import { ssrTransformShow } from './transforms/ssrVShow' import { ssrInjectFallthroughAttrs } from './transforms/ssrInjectFallthroughAttrs' import { ssrInjectCssVars } from './transforms/ssrInjectCssVars' +import { ssrTransformSkip } from './transforms/ssrVSkip' export function compile( source: string | RootNode, @@ -56,6 +57,7 @@ export function compile( hoistStatic: false, nodeTransforms: [ ssrTransformIf, + ssrTransformSkip, ssrTransformFor, trackVForSlotScopes, transformExpression, diff --git a/packages/compiler-ssr/src/transforms/ssrVSkip.ts b/packages/compiler-ssr/src/transforms/ssrVSkip.ts index 1780a189d10..a28e517caf4 100644 --- a/packages/compiler-ssr/src/transforms/ssrVSkip.ts +++ b/packages/compiler-ssr/src/transforms/ssrVSkip.ts @@ -1,29 +1,25 @@ import { type ComponentNode, type DirectiveNode, - ErrorCodes, type IfBranchNode, + type NodeTransform, NodeTypes, type PlainElementNode, - type SimpleExpressionNode, - createCompilerError, createIfStatement, - createSimpleExpression, + createStructuralDirectiveTransform, + processSkip, } from '@vue/compiler-core' import { processIfBranch } from './ssrVIf' import type { SSRTransformContext } from '../ssrCodegenTransform' +export const ssrTransformSkip: NodeTransform = + createStructuralDirectiveTransform('skip', processSkip) + export function ssrProcessSkip( node: PlainElementNode | ComponentNode, dir: DirectiveNode, context: SSRTransformContext, ): void { - if (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim()) { - const loc = dir.exp ? dir.exp.loc : node.loc - context.onError(createCompilerError(ErrorCodes.X_V_SKIP_NO_EXPRESSION, loc)) - dir.exp = createSimpleExpression(`true`, false, loc) - } - node.props = node.props.filter(x => x.name !== 'skip') const consequent: IfBranchNode = { type: NodeTypes.IF_BRANCH,