From: daiwei Date: Tue, 22 Apr 2025 13:20:44 +0000 (+0800) Subject: wip: refactor X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d8443d3754b701766f3871af3142d7e1c02c478d;p=thirdparty%2Fvuejs%2Fcore.git wip: refactor --- diff --git a/packages/compiler-ssr/__tests__/ssrElement.spec.ts b/packages/compiler-ssr/__tests__/ssrElement.spec.ts index 59f6b0ffbc..fad8982389 100644 --- a/packages/compiler-ssr/__tests__/ssrElement.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrElement.spec.ts @@ -397,8 +397,8 @@ describe('ssr: element', () => { }) }) - describe('dynamic child anchor', () => { - test('with consecutive components', () => { + describe('dynamic anchor', () => { + test('consecutive components', () => { expect( getCompiledString(`
@@ -409,14 +409,11 @@ describe('ssr: element', () => {
`), ).toMatchInlineSnapshot(` - "\`
\`) - _push("") + "\`
\`) _push(_ssrRenderComponent(_component_Comp1, null, null, _parent)) - _push("") - _push("") + _push(\`\`) _push(_ssrRenderComponent(_component_Comp2, null, null, _parent)) - _push("") - _push(\`
\`" + _push(\`
\`" `) }) }) diff --git a/packages/compiler-ssr/src/ssrCodegenTransform.ts b/packages/compiler-ssr/src/ssrCodegenTransform.ts index 536cbb5c1e..c56dea164c 100644 --- a/packages/compiler-ssr/src/ssrCodegenTransform.ts +++ b/packages/compiler-ssr/src/ssrCodegenTransform.ts @@ -157,13 +157,29 @@ export function processChildren( asFragment = false, disableNestedFragments = false, disableComment = false, + asDynamic = false, ): void { + if (asDynamic) { + context.pushStringPart(``) + } if (asFragment) { context.pushStringPart(``) } + const { children } = parent for (let i = 0; i < children.length; i++) { const child = children[i] + if (shouldProcessAsDynamic(parent, child)) { + processChildren( + { children: [child] }, + context, + asFragment, + disableNestedFragments, + disableComment, + true, + ) + continue + } switch (child.type) { case NodeTypes.ELEMENT: switch (child.tagType) { @@ -237,6 +253,9 @@ export function processChildren( if (asFragment) { context.pushStringPart(``) } + if (asDynamic) { + context.pushStringPart(``) + } } export function processChildrenAsStatement( @@ -249,3 +268,72 @@ export function processChildrenAsStatement( processChildren(parent, childContext, asFragment) return createBlockStatement(childContext.body) } + +const isStaticElement = (c: TemplateChildNode): boolean => + c.type === NodeTypes.ELEMENT && c.tagType !== ElementTypes.COMPONENT + +/** + * Check if a node should be processed as dynamic. + * This is primarily used in Vapor mode hydration to wrap dynamic parts + * with markers (`` and ``). + * + * + * // Static previous sibling + * // Dynamic node (current) + * // Dynamic next sibling + * // Static next sibling + * + */ +function shouldProcessAsDynamic( + parent: { tag?: string; children: TemplateChildNode[] }, + node: TemplateChildNode, +): boolean { + // 1. Must be a dynamic node type + if (isStaticElement(node)) return false + // 2. Must be inside a parent element + if (!parent.tag) return false + + const children = parent.children + const len = children.length + const index = children.indexOf(node) + + // 3. Check for a static previous sibling + let hasStaticPreviousSibling = false + if (index > 0) { + for (let i = index - 1; i >= 0; i--) { + if (isStaticElement(children[i])) { + hasStaticPreviousSibling = true + break + } + } + } + if (!hasStaticPreviousSibling) return false + + // 4. Check for a static next sibling + let hasStaticNextSibling = false + if (index > -1 && index < len - 1) { + for (let i = index + 1; i < len; i++) { + if (isStaticElement(children[i])) { + hasStaticNextSibling = true + break + } + } + } + if (!hasStaticNextSibling) return false + + // 5. Check for a consecutive dynamic sibling (immediately before or after) + let hasConsecutiveDynamicNodes = false + if (index > 0 && !isStaticElement(children[index - 1])) { + hasConsecutiveDynamicNodes = true + } + if ( + !hasConsecutiveDynamicNodes && + index < len - 1 && + !isStaticElement(children[index + 1]) + ) { + hasConsecutiveDynamicNodes = true + } + + // Only process as dynamic if all conditions are met + return hasConsecutiveDynamicNodes +} diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts index 48df321337..cad1ee8102 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts @@ -255,13 +255,6 @@ export function ssrProcessComponent( node.ssrCodegenNode.arguments.push(`_scopeId`) } - // `` marks the start of the dynamic children - // Only used in Vapor hydration, VDOM hydration - // skips this marker. - const needDynamicAnchor = shouldAddDynamicAnchor(parent, node) - if (needDynamicAnchor) { - context.pushStatement(createCallExpression(`_push`, [`""`])) - } if (typeof component === 'string') { // static component context.pushStatement( @@ -272,9 +265,6 @@ export function ssrProcessComponent( // the codegen node is a `renderVNode` call context.pushStatement(node.ssrCodegenNode) } - if (needDynamicAnchor) { - context.pushStatement(createCallExpression(`_push`, [`""`])) - } } } @@ -394,58 +384,3 @@ function clone(v: any): any { return v } } - -function shouldAddDynamicAnchor( - parent: { tag?: string; children: TemplateChildNode[] }, - node: TemplateChildNode, -): boolean { - if (!parent.tag) return false - - const children = parent.children - const len = children.length - const index = children.indexOf(node) - - const isStaticElement = (c: TemplateChildNode): boolean => - c.type === NodeTypes.ELEMENT && c.tagType !== ElementTypes.COMPONENT - - let hasStaticPreviousSibling = false - if (index > 0) { - for (let i = index - 1; i >= 0; i--) { - if (isStaticElement(children[i])) { - hasStaticPreviousSibling = true - break - } - } - } - - let hasStaticNextSibling = false - if (hasStaticPreviousSibling && index > -1 && index < len - 1) { - for (let i = index + 1; i < len; i++) { - if (isStaticElement(children[i])) { - hasStaticNextSibling = true - break - } - } - } - - let hasConsecutiveDynamicNodes = false - if (index > 0 && index < len - 1) { - if (index > 0 && !isStaticElement(children[index - 1])) { - hasConsecutiveDynamicNodes = true - } - - if ( - !hasConsecutiveDynamicNodes && - index < len - 1 && - !isStaticElement(children[index + 1]) - ) { - hasConsecutiveDynamicNodes = true - } - } - - return ( - hasStaticPreviousSibling && - hasStaticNextSibling && - hasConsecutiveDynamicNodes - ) -} diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index a6a8960fb1..23b223526f 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -1843,8 +1843,8 @@ describe('SSR hydration', () => { } }) - describe('dynamic child anchor', () => { - test('with consecutive components', () => { + describe('dynamic anchor', () => { + test('consecutive components', () => { const Comp = { render() { return createTextVNode('foo') diff --git a/packages/runtime-vapor/src/dom/hydration.ts b/packages/runtime-vapor/src/dom/hydration.ts index a3b0eecb4b..30560801e5 100644 --- a/packages/runtime-vapor/src/dom/hydration.ts +++ b/packages/runtime-vapor/src/dom/hydration.ts @@ -75,9 +75,9 @@ function locateHydrationNodeImpl() { // prepend / firstChild if (insertionAnchor === 0) { node = child(insertionParent!) - } else if (insertionParent && insertionAnchor) { - // dynamic child anchor `` - if (insertionAnchor && isDynamicStart(insertionAnchor)) { + } else if (insertionAnchor) { + // dynamic anchor `` + if (isDynamicStart(insertionAnchor)) { const anchor = (insertionParent!.$lds = insertionParent!.$lds ? // continuous dynamic children, the next dynamic start must exist locateNextDynamicStart(insertionParent!.$lds)! @@ -87,11 +87,7 @@ function locateHydrationNodeImpl() { node = insertionAnchor } } else { - node = insertionAnchor - ? insertionAnchor.previousSibling - : insertionParent - ? insertionParent.lastChild - : currentHydrationNode + node = insertionParent ? insertionParent.lastChild : currentHydrationNode if (node && isComment(node, ']')) { // fragment backward search if (node.$fs) {