]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: don't add anchor if children are only one block node
authordaiwei <daiwei521@126.com>
Wed, 13 Aug 2025 09:53:14 +0000 (17:53 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 13 Aug 2025 09:56:20 +0000 (17:56 +0800)
packages/compiler-ssr/__tests__/ssrVaporAnchors.spec.ts
packages/compiler-ssr/src/ssrCodegenTransform.ts
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap
packages/compiler-vapor/src/transforms/transformChildren.ts
packages/runtime-vapor/__tests__/hydration.spec.ts

index d530ee1f4c1253da48aea72b8db28da4b09c6f28..50657f37345d5efaabb60e5c903def752ee95563 100644 (file)
@@ -25,7 +25,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -50,7 +50,7 @@ describe('insertion anchors', () => {
             }),
             _: 1 /* STABLE */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
 
@@ -81,7 +81,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -108,7 +108,7 @@ describe('insertion anchors', () => {
             }),
             _: 3 /* FORWARDED */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
 
@@ -155,7 +155,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -197,7 +197,7 @@ describe('insertion anchors', () => {
             }),
             _: 1 /* STABLE */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
 
@@ -283,7 +283,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -370,7 +370,7 @@ describe('insertion anchors', () => {
             }),
             _: 1 /* STABLE */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
 
@@ -388,7 +388,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.tag), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -426,7 +426,7 @@ describe('insertion anchors', () => {
             }),
             _: 1 /* STABLE */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
 
@@ -455,7 +455,7 @@ describe('insertion anchors', () => {
           { vapor: true },
         ),
       ).toMatchInlineSnapshot(`
-        "\`<!--[a-->\`)
+        "\`\`)
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
             default: _withCtx((_, _push, _parent, _scopeId) => {
               if (_push) {
@@ -480,7 +480,7 @@ describe('insertion anchors', () => {
             }),
             _: 1 /* STABLE */
           }), _parent)
-          _push(\`<!--dynamic-component--><!--a]-->\`"
+          _push(\`<!--dynamic-component-->\`"
       `)
     })
   })
@@ -544,7 +544,7 @@ describe('insertion anchors', () => {
         },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent('div'), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
@@ -575,7 +575,7 @@ describe('insertion anchors', () => {
           }),
           _: 1 /* STABLE */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 })
@@ -595,7 +595,7 @@ describe('block anchors', () => {
         },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.tag), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
@@ -638,7 +638,7 @@ describe('block anchors', () => {
           }),
           _: 1 /* STABLE */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 
@@ -655,7 +655,7 @@ describe('block anchors', () => {
         },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.tag), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
@@ -700,7 +700,7 @@ describe('block anchors', () => {
           }),
           _: 1 /* STABLE */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 
@@ -715,7 +715,7 @@ describe('block anchors', () => {
         },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.tag), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
@@ -739,7 +739,7 @@ describe('block anchors', () => {
           }),
           _: 1 /* STABLE */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 
@@ -771,7 +771,7 @@ describe('block anchors', () => {
         { vapor: true },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.tag), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
@@ -790,7 +790,7 @@ describe('block anchors', () => {
           }),
           _: 3 /* FORWARDED */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 
@@ -805,27 +805,25 @@ describe('block anchors', () => {
         { vapor: true },
       ),
     ).toMatchInlineSnapshot(`
-      "\`<!--[a-->\`)
+      "\`\`)
         _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("tag"), null, {
           default: _withCtx((_, _push, _parent, _scopeId) => {
             if (_push) {
-              _push(\`<div\${_scopeId}><!--[a-->\`)
+              _push(\`<div\${_scopeId}>\`)
               _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("foo"), null, null), _parent, _scopeId)
-              _push(\`<!--dynamic-component--><!--a]--></div>\`)
+              _push(\`<!--dynamic-component--></div>\`)
             } else {
               return [
                 _createVNode("div", null, [
-                  _createCommentVNode("[a"),
                   (_openBlock(), _createBlock(_resolveDynamicComponent("foo"))),
-                  _createCommentVNode("dynamic-component"),
-                  _createCommentVNode("a]")
+                  _createCommentVNode("dynamic-component")
                 ])
               ]
             }
           }),
           _: 1 /* STABLE */
         }), _parent)
-        _push(\`<!--dynamic-component--><!--a]-->\`"
+        _push(\`<!--dynamic-component-->\`"
     `)
   })
 })
index fc32850e7e25c36cebb89a5c52d2c4ff19ad7c92..79a3738df305625d5e0348f7aae76f76eed4cce5 100644 (file)
@@ -280,9 +280,11 @@ export function processChildrenAsStatement(
 export function processBlockNodeAnchor(children: TemplateChildNode[]): void {
   let prevBlocks: (TemplateChildNode & { anchor?: string })[] = []
   let hasStaticNode = false
+  let blockCount = 0
   for (const child of children) {
     if (isBlockNode(child)) {
       prevBlocks.push(child)
+      blockCount++
     }
 
     if (isStaticNode(child)) {
@@ -304,7 +306,9 @@ export function processBlockNodeAnchor(children: TemplateChildNode[]): void {
     }
   }
 
-  if (prevBlocks.length) {
+  // When there is only one block node, no anchor is needed,
+  // firstChild is used as the hydration node
+  if (prevBlocks.length && !(blockCount === 1 && !hasStaticNode)) {
     // append anchor
     prevBlocks.forEach(child => (child.anchor = BLOCK_APPEND_ANCHOR_LABEL))
   }
index 103e174e99328f4142c192e808c280f5c5e81167..f11bfbcc6f163ff1699500770e6d43d8c033a932 100644 (file)
@@ -38,7 +38,7 @@ export function render(_ctx) {
     "default": () => {
       const n0 = _createIf(() => (true), () => {
         const n3 = t0()
-        _setInsertionState(n3, null)
+        _setInsertionState(n3)
         const n2 = _createComponentWithFallback(_component_Bar)
         _withVaporDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]])
         return n3
@@ -220,7 +220,7 @@ export function render(_ctx) {
   const _component_Comp = _resolveComponent("Comp")
   const n3 = t0()
   const n1 = _child(n3)
-  _setInsertionState(n1, null)
+  _setInsertionState(n1)
   const n0 = _createSlot("default", null)
   _setInsertionState(n3, null)
   const n2 = _createComponentWithFallback(_component_Comp)
index e7745851e5aab15a342940aebefc81a7a45459d6..09329d2e9cd84323ddd7d7303866f0e1e8e2cba1 100644 (file)
@@ -87,7 +87,7 @@ const t1 = _template("<div></div>", true)
 export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
     const n5 = t1()
-    _setInsertionState(n5, null)
+    _setInsertionState(n5)
     const n2 = _createFor(() => (_for_item0.value), (_for_item1) => {
       const n4 = t0()
       const x4 = _child(n4, -1)
index 4ca745ef0f575bcfefe521764cfea16fb0ddea7b..b6107d5a1a1c63067461c43cda989eb22e144065 100644 (file)
@@ -42,7 +42,7 @@ const t0 = _template("<div></div>", true)
 export function render(_ctx) {
   const _component_Comp = _resolveComponent("Comp")
   const n1 = t0()
-  _setInsertionState(n1, null)
+  _setInsertionState(n1)
   const n0 = _createComponentWithFallback(_component_Comp, { id: () => (_ctx.foo) }, null, null, true)
   return n1
 }"
index e4dcd4d9f37efef42eb0535bd80e349da8e008a3..1ad8dae5ede63f59bf655eaae41ed2646901e907 100644 (file)
@@ -60,11 +60,13 @@ export const transformChildren: NodeTransform = (node, context) => {
 function processDynamicChildren(context: TransformContext<ElementNode>) {
   let prevDynamics: IRDynamicInfo[] = []
   let hasStaticTemplate = false
+  let dynamicCount = 0
   const children = context.dynamic.children
 
   for (const [index, child] of children.entries()) {
     if (child.flags & DynamicFlag.INSERT) {
       prevDynamics.push(child)
+      dynamicCount++
     }
 
     if (!(child.flags & DynamicFlag.NON_TEMPLATE)) {
@@ -84,7 +86,13 @@ function processDynamicChildren(context: TransformContext<ElementNode>) {
   }
 
   if (prevDynamics.length) {
-    registerInsertion(prevDynamics, context, -2 /* append */)
+    registerInsertion(
+      prevDynamics,
+      context,
+      // When there is only one dynamic node, no anchor is needed,
+      // firstChild is used as the hydration node
+      dynamicCount === 1 && !hasStaticTemplate ? undefined : -2 /* append */,
+    )
   }
 }
 
index b501f1a5806a3a460d629e0be33d86cfcfbc26ca..ba322918172b3f0ce056bbf6d0d3b9dce2da6055 100644 (file)
@@ -1354,11 +1354,7 @@ describe('Vapor Mode hydration', () => {
         data,
       )
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
-        `
-        "<div>
-        <!--[a-->foo<!--a]-->
-        </div><!--if-->"
-      `,
+        `"<div>foo</div><!--if-->"`,
       )
 
       data.value = false
@@ -1731,10 +1727,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><div>true</div>-true-<!--]-->
-        <!--if--><!--a]-->
-        </div>"
+        <!--if--></div>"
       `,
       )
 
@@ -1743,10 +1737,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><!--]-->
-        <!--if--><!--a]-->
-        </div>"
+        <!--if--></div>"
       `,
       )
 
@@ -1754,10 +1746,8 @@ describe('Vapor Mode hydration', () => {
       await nextTick()
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(`
         "<div>
-        <!--[a-->
         <!--[--><!--]-->
-        <div>true</div>-true-<!--if--><!--a]-->
-        </div>"
+        <div>true</div>-true-<!--if--></div>"
       `)
     })
 
@@ -1922,10 +1912,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><span>a</span><span>b</span><span>c</span><!--]-->
-        <!--for--><!--a]-->
-        </div>"
+        <!--for--></div>"
       `,
       )
 
@@ -1934,10 +1922,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><span>a</span><span>b</span><span>c</span><!--]-->
-        <span>d</span><!--for--><!--a]-->
-        </div>"
+        <span>d</span><!--for--></div>"
       `,
       )
     })
@@ -2062,10 +2048,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><div>comp</div><div>comp</div><div>comp</div><!--]-->
-        <!--for--><!--a]-->
-        </div>"
+        <!--for--></div>"
       `,
       )
 
@@ -2074,10 +2058,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><div>comp</div><div>comp</div><div>comp</div><!--]-->
-        <div>comp</div><!--for--><!--a]-->
-        </div>"
+        <div>comp</div><!--for--></div>"
       `,
       )
     })
@@ -2099,7 +2081,6 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[-->
         <!--[--><span>a</span><!--]-->
         <!--slot-->
@@ -2107,8 +2088,7 @@ describe('Vapor Mode hydration', () => {
         <!--slot-->
         <!--[--><span>c</span><!--]-->
         <!--slot--><!--]-->
-        <!--for--><!--a]-->
-        </div>"
+        <!--for--></div>"
       `,
       )
 
@@ -2117,7 +2097,6 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[-->
         <!--[--><span>a</span><!--]-->
         <!--slot-->
@@ -2125,8 +2104,7 @@ describe('Vapor Mode hydration', () => {
         <!--slot-->
         <!--[--><span>c</span><!--]-->
         <!--slot--><!--]-->
-        <span>d</span><!--slot--><!--for--><!--a]-->
-        </div>"
+        <span>d</span><!--slot--><!--for--></div>"
       `,
       )
     })
@@ -2146,14 +2124,12 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--]-->
-        <!--for--><!--a]-->
-        </div>"
+        <!--for--></div>"
       `,
       )
 
@@ -2162,14 +2138,12 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--[--><div>foo</div>-bar-<!--]-->
         <!--]-->
-        <div>foo</div>-bar-<!--for--><!--a]-->
-        </div>"
+        <div>foo</div>-bar-<!--for--></div>"
       `,
       )
     })
@@ -3029,15 +3003,11 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[p--><div>
-        <!--[a--><div>
-        <!--[a-->
+        <!--[p--><div><div>
         <!--[-->
         <!--[--><span>foo</span><!--]-->
         <!--slot--><!--]-->
-        <!--slot--><!--a]-->
-        </div><!--a]-->
-        </div><!--p]-->
+        <!--slot--></div></div><!--p]-->
         <div>bar</div></div>"
       `,
       )
@@ -3048,15 +3018,11 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[p--><div>
-        <!--[a--><div>
-        <!--[a-->
+        <!--[p--><div><div>
         <!--[-->
         <!--[--><span>foo1</span><!--]-->
         <!--slot--><!--]-->
-        <!--slot--><!--a]-->
-        </div><!--a]-->
-        </div><!--p]-->
+        <!--slot--></div></div><!--p]-->
         <div>bar1</div></div>"
       `,
       )
@@ -3079,10 +3045,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><!--slot-->foo<!--]-->
-        <!--slot--><!--a]-->
-        </div>"
+        <!--slot--></div>"
       `,
       )
 
@@ -3091,10 +3055,8 @@ describe('Vapor Mode hydration', () => {
       expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
         `
         "<div>
-        <!--[a-->
         <!--[--><!--slot-->foo1<!--]-->
-        <!--slot--><!--a]-->
-        </div>"
+        <!--slot--></div>"
       `,
       )
     })
@@ -3378,10 +3340,8 @@ describe('VDOM interop', () => {
     expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
       `
       "<div>
-      <!--[a-->
       <!--[-->true<!--]-->
-      <!--slot--><!--a]-->
-      </div>"
+      <!--slot--></div>"
     `,
     )
 
@@ -3390,10 +3350,8 @@ describe('VDOM interop', () => {
     expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
       `
       "<div>
-      <!--[a-->
       <!--[-->false<!--]-->
-      <!--slot--><!--a]-->
-      </div>"
+      <!--slot--></div>"
     `,
     )
   })