From: daiwei Date: Fri, 24 Jan 2025 14:15:52 +0000 (+0800) Subject: wip: save X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3fc7035136a2cb3c3591f94b95fbe608683b4e0;p=thirdparty%2Fvuejs%2Fcore.git wip: save --- diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vSkip.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vSkip.spec.ts.snap index 8904400a65..a975095208 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vSkip.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vSkip.spec.ts.snap @@ -36,6 +36,37 @@ return function render(_ctx, _cache) { }" `; +exports[`compiler: v-skip > transform > on component 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { resolveComponent: _resolveComponent, resolveSkipComponent: _resolveSkipComponent, openBlock: _openBlock, createBlock: _createBlock } = _Vue + + const _component_Comp = _resolveComponent("Comp") + + return (_openBlock(), _createBlock(_resolveSkipComponent(_ctx.ok, _component_Comp))) + } +}" +`; + +exports[`compiler: v-skip > transform > on dynamic component 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderSlot: _renderSlot, resolveDynamicComponent: _resolveDynamicComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock, resolveSkipComponent: _resolveSkipComponent } = _Vue + + return (_openBlock(), _createBlock(_resolveSkipComponent(_ctx.ok, _resolveDynamicComponent(_ctx.Comp)), null, { + default: _withCtx(() => [ + _renderSlot(_ctx.$slots, "default") + ]), + _: 3 /* FORWARDED */ + })) + } +}" +`; + exports[`compiler: v-skip > transform > v-else + v-skip 1`] = ` "const _Vue = Vue diff --git a/packages/compiler-core/__tests__/transforms/vSkip.spec.ts b/packages/compiler-core/__tests__/transforms/vSkip.spec.ts index 2d7a74b7c4..c9002fb87f 100644 --- a/packages/compiler-core/__tests__/transforms/vSkip.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vSkip.spec.ts @@ -1,14 +1,18 @@ import { + type CallExpression, type CompilerOptions, + type ComponentNode, type ElementNode, ElementTypes, ErrorCodes, type IfBranchNode, type IfNode, NodeTypes, + RESOLVE_SKIP_COMPONENT, type RootNode, type SimpleExpressionNode, type SkipNode, + type VNodeCall, generate, baseParse as parse, transform, @@ -25,7 +29,7 @@ export function parseWithSkipTransform( options: CompilerOptions = { prefixIdentifiers: true }, ): { root: RootNode - node: SkipNode + node: SkipNode | ComponentNode } { const ast = parse(template, options) transform(ast, { @@ -41,14 +45,17 @@ export function parseWithSkipTransform( }) return { root: ast, - node: ast.children[0] as SkipNode, + node: ast.children[0] as SkipNode | ComponentNode, } } describe('compiler: v-skip', () => { describe('transform', () => { test('basic', () => { - const { root, node } = parseWithSkipTransform(`
`) + const { root, node } = parseWithSkipTransform(`
`) as { + root: RootNode + node: SkipNode + } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect(node.consequent.type === NodeTypes.JS_CALL_EXPRESSION).toBe(true) @@ -61,7 +68,7 @@ describe('compiler: v-skip', () => { test('with text children', () => { const { root, node } = parseWithSkipTransform( `
foo
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect((node.consequent as IfBranchNode).children.length).toBe(1) @@ -80,7 +87,7 @@ describe('compiler: v-skip', () => { test('with element children', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect((node.consequent as IfBranchNode).children.length).toBe(1) @@ -99,7 +106,7 @@ describe('compiler: v-skip', () => { test('with component children', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect((node.consequent as IfBranchNode).children.length).toBe(1) @@ -118,7 +125,7 @@ describe('compiler: v-skip', () => { test('with multiple children', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect((node.consequent as IfBranchNode).children.length).toBe(2) @@ -143,7 +150,7 @@ describe('compiler: v-skip', () => { test('nested v-skip', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) expect((node.consequent as IfBranchNode).children.length).toBe(1) @@ -194,7 +201,7 @@ describe('compiler: v-skip', () => { test('v-skip with key', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.SKIP) expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.nested`) expect(node.consequent.type === NodeTypes.JS_CALL_EXPRESSION).toBe(true) @@ -216,7 +223,7 @@ describe('compiler: v-skip', () => { test('v-else + v-skip', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.IF) const elseNode = node as unknown as IfNode const branch = elseNode.branches[1] @@ -232,7 +239,7 @@ describe('compiler: v-skip', () => { test('v-else-if + v-skip', () => { const { root, node } = parseWithSkipTransform( `
`, - ) + ) as { root: RootNode; node: SkipNode } expect(node.type).toBe(NodeTypes.IF) const elseIfNode = node as unknown as IfNode const branch = elseIfNode.branches[1] @@ -249,19 +256,24 @@ describe('compiler: v-skip', () => { }) test('on component', () => { - const { root, node } = parseWithSkipTransform(``) - expect(node.type).toBe(NodeTypes.SKIP) - expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) - expect(node.consequent.type === NodeTypes.JS_CALL_EXPRESSION).toBe(true) - expect(node.alternate.children.length).toBe(1) - expect((node.alternate.children[0] as ElementNode).tagType).toBe( - ElementTypes.COMPONENT, + const { root, node } = parseWithSkipTransform(``) as { + root: RootNode + node: ComponentNode + } + expect(node.type).toBe(NodeTypes.ELEMENT) + expect(node.tagType).toBe(ElementTypes.COMPONENT) + const codegenNode = node.codegenNode! as VNodeCall + expect(codegenNode.type).toBe(NodeTypes.VNODE_CALL) + const vnodeTag = codegenNode.tag as CallExpression + expect(vnodeTag.type).toBe(NodeTypes.JS_CALL_EXPRESSION) + expect(vnodeTag.callee).toBe(RESOLVE_SKIP_COMPONENT) + expect((vnodeTag.arguments[0] as SimpleExpressionNode).content).toBe( + `_ctx.ok`, ) - expect((node.alternate.children[0] as ElementNode).tag).toBe(`Comp`) expect(generate(root).code).toMatchSnapshot() }) - test('on component with default slot', () => { + test.todo('on component with default slot', () => { const { root, node } = parseWithSkipTransform( `foo`, ) @@ -282,7 +294,7 @@ describe('compiler: v-skip', () => { expect(generate(root).code).toMatchSnapshot() }) - test('on component with multiple named slot', () => { + test.todo('on component with multiple named slot', () => { const { root, node } = parseWithSkipTransform( ` @@ -306,7 +318,7 @@ describe('compiler: v-skip', () => { expect(generate(root).code).toMatchSnapshot() }) - test('on component with multiple implicit slot', () => { + test.todo('on component with multiple implicit slot', () => { const { root, node } = parseWithSkipTransform( ` @@ -389,23 +401,23 @@ describe('compiler: v-skip', () => { ` `, + ) as { root: RootNode; node: ComponentNode } + expect(node.type).toBe(NodeTypes.ELEMENT) + expect(node.tagType).toBe(ElementTypes.COMPONENT) + const codegenNode = node.codegenNode! as VNodeCall + expect(codegenNode.type).toBe(NodeTypes.VNODE_CALL) + const vnodeTag = codegenNode.tag as CallExpression + expect(vnodeTag.type).toBe(NodeTypes.JS_CALL_EXPRESSION) + expect(vnodeTag.callee).toBe(RESOLVE_SKIP_COMPONENT) + expect((vnodeTag.arguments[0] as SimpleExpressionNode).content).toBe( + `_ctx.ok`, ) - expect(node.type).toBe(NodeTypes.SKIP) - expect((node.test as SimpleExpressionNode).content).toBe(`_ctx.ok`) - expect((node.consequent as IfBranchNode).children.length).toBe(1) - expect((node.consequent as IfBranchNode).children[0].type).toBe( - NodeTypes.ELEMENT, - ) - expect( - ((node.consequent as IfBranchNode).children[0] as ElementNode).tag, - ).toBe(`slot`) - expect(node.alternate.children.length).toBe(1) - expect((node.alternate.children[0] as ElementNode).tagType).toBe( - ElementTypes.COMPONENT, - ) - expect((node.alternate.children[0] as ElementNode).tag).toBe(`component`) expect(generate(root).code).toMatchSnapshot() }) + + test.todo('on Teleport', () => {}) + + test.todo('built-in components', () => {}) }) describe('errors', () => { @@ -440,51 +452,6 @@ describe('compiler: v-skip', () => { ]) }) - test('on component without default slot', () => { - const onError = vi.fn() - parseWithSkipTransform( - ` - - `, - { onError }, - ) - expect(onError.mock.calls[0]).toMatchObject([ - { - code: ErrorCodes.X_V_SKIP_UNEXPECTED_SLOT, - }, - ]) - }) - - test('on component with default slot and slot props', () => { - const onError = vi.fn() - parseWithSkipTransform( - ` - - `, - { onError }, - ) - expect(onError.mock.calls[0]).toMatchObject([ - { - code: ErrorCodes.X_V_SKIP_UNEXPECTED_SLOT, - }, - ]) - }) - - test('on component with only dynamic slot', () => { - const onError = vi.fn() - parseWithSkipTransform( - ` - - `, - { onError }, - ) - expect(onError.mock.calls[0]).toMatchObject([ - { - code: ErrorCodes.X_V_SKIP_UNEXPECTED_SLOT, - }, - ]) - }) - test('with v-for', () => { const onError = vi.fn() parseWithSkipTransform(`
`, { diff --git a/packages/compiler-core/src/transforms/vSkip.ts b/packages/compiler-core/src/transforms/vSkip.ts index cd04c8db89..fc877ba84b 100644 --- a/packages/compiler-core/src/transforms/vSkip.ts +++ b/packages/compiler-core/src/transforms/vSkip.ts @@ -38,7 +38,10 @@ export const transformSkip: NodeTransform = createStructuralDirectiveTransform( return processSkip(node, dir, context, (skipNode?: SkipNode) => { return () => { const codegenNode = node.codegenNode! - if (node.tagType === ElementTypes.COMPONENT) { + if ( + node.tagType === ElementTypes.COMPONENT && + node.tag !== 'Teleport' + ) { if (codegenNode.type === NodeTypes.VNODE_CALL) { codegenNode.tag = getVNodeTag( context, @@ -107,7 +110,10 @@ export function processSkip( } let skipNode: SkipNode | undefined - if (node.tagType === ElementTypes.ELEMENT) { + if ( + node.tagType === ElementTypes.ELEMENT || + (node.tagType === ElementTypes.COMPONENT && node.tag === 'Teleport') + ) { const children = node.children // if children is empty, create comment node const consequent = diff --git a/packages/compiler-ssr/__tests__/ssrVSkip.spec.ts b/packages/compiler-ssr/__tests__/ssrVSkip.spec.ts index 4929912b6f..778a31c48f 100644 --- a/packages/compiler-ssr/__tests__/ssrVSkip.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVSkip.spec.ts @@ -206,7 +206,7 @@ describe('ssr: v-skip', () => { `) }) - test('on component with default slot', () => { + test.todo('on component with default slot', () => { expect(compile(`foo`).code).toMatchInlineSnapshot(` "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createTextVNode: _createTextVNode } = require("vue") const { ssrRenderComponent: _ssrRenderComponent, ssrRenderSkipComponent: _ssrRenderSkipComponent } = require("vue/server-renderer") @@ -230,7 +230,7 @@ describe('ssr: v-skip', () => { `) }) - test('on component with multiple named slot', () => { + test.todo('on component with multiple named slot', () => { expect( compile( ` @@ -270,7 +270,7 @@ describe('ssr: v-skip', () => { `) }) - test('on component with multiple implicit slot', () => { + test.todo('on component with multiple implicit slot', () => { expect( compile( ` @@ -325,10 +325,10 @@ describe('ssr: v-skip', () => { ).code, ).toMatchInlineSnapshot(` "const { resolveDynamicComponent: _resolveDynamicComponent, withCtx: _withCtx, renderSlot: _renderSlot, createVNode: _createVNode } = require("vue") - const { ssrRenderSlot: _ssrRenderSlot, ssrRenderVNode: _ssrRenderVNode, ssrRenderSkipComponent: _ssrRenderSkipComponent } = require("vue/server-renderer") + const { ssrRenderSlot: _ssrRenderSlot, ssrRenderVNode: _ssrRenderVNode } = require("vue/server-renderer") return function ssrRender(_ctx, _push, _parent, _attrs) { - _ssrRenderSkipComponent(_push, _ctx.ok, _push, _createVNode(_resolveDynamicComponent(_ctx.Comp), _attrs, { + _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.Comp), _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent, _scopeId) diff --git a/packages/compiler-ssr/src/transforms/ssrVSkip.ts b/packages/compiler-ssr/src/transforms/ssrVSkip.ts index e7d111299f..8d9f94fca2 100644 --- a/packages/compiler-ssr/src/transforms/ssrVSkip.ts +++ b/packages/compiler-ssr/src/transforms/ssrVSkip.ts @@ -10,19 +10,27 @@ import { } from '@vue/compiler-core' import { processIfBranch } from './ssrVIf' import type { SSRTransformContext } from '../ssrCodegenTransform' -import { SSR_RENDER_SKIP_COMPONENT } from '../runtimeHelpers' +import { + SSR_RENDER_COMPONENT, + SSR_RENDER_SKIP_COMPONENT, + SSR_RENDER_VNODE, +} from '../runtimeHelpers' export const ssrTransformSkip: NodeTransform = createStructuralDirectiveTransform('skip', (node, dir, context) => { processSkip(node, dir, context) return () => { if (node.tagType === ElementTypes.COMPONENT && node.ssrCodegenNode) { - const { arguments: args, loc } = node.ssrCodegenNode - node.ssrCodegenNode = createCallExpression( - context.helper(SSR_RENDER_SKIP_COMPONENT), - [`_push`, dir.exp!, ...args], - loc, - ) + const { callee, arguments: args, loc } = node.ssrCodegenNode + if (callee === SSR_RENDER_COMPONENT) { + node.ssrCodegenNode = createCallExpression( + context.helper(SSR_RENDER_SKIP_COMPONENT), + [`_push`, dir.exp!, ...args], + loc, + ) + } else if (callee === SSR_RENDER_VNODE) { + // TODO + } } } }) diff --git a/packages/runtime-core/src/helpers/resolveAssets.ts b/packages/runtime-core/src/helpers/resolveAssets.ts index dc7d13a6df..6e2d6fcebd 100644 --- a/packages/runtime-core/src/helpers/resolveAssets.ts +++ b/packages/runtime-core/src/helpers/resolveAssets.ts @@ -11,6 +11,7 @@ import { warn } from '../warning' import type { VNodeTypes } from '../vnode' import { type ComponentPublicInstance, + createCommentVNode, defineComponent, renderSlot, } from '@vue/runtime-core' @@ -156,7 +157,9 @@ export function resolveSkipComponent( ? _comp || (_comp = defineComponent({ render(this: ComponentPublicInstance) { - return renderSlot(this.$slots, 'default') + return renderSlot(this.$slots, 'default', undefined, () => [ + createCommentVNode('v-skip'), + ]) }, })) : Comp