]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip(vapor): fix children gen for dynamic with anchor insertion
authorEvan You <evan@vuejs.org>
Tue, 11 Mar 2025 12:32:07 +0000 (20:32 +0800)
committerEvan You <evan@vuejs.org>
Tue, 11 Mar 2025 12:32:07 +0000 (20:32 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/transformChildren.spec.ts
packages/compiler-vapor/src/generators/template.ts
packages/runtime-vapor/__tests__/hydration.spec.ts

index 40c4096ce2938a102cc5399eeca2285510abfa55..5ae8a94f5b1270948377e0f9d0969a96a0e27cc8 100644 (file)
@@ -1,5 +1,22 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
+exports[`compiler: children transform > anchor insertion in middle 1`] = `
+"import { child as _child, next as _next, setInsertionState as _setInsertionState, createIf as _createIf, template as _template } from 'vue';
+const t0 = _template("<div></div>")
+const t1 = _template("<div><div></div><!><div></div></div>", true)
+
+export function render(_ctx) {
+  const n4 = t1()
+  const n3 = _next(_child(n4))
+  _setInsertionState(n4, n3)
+  const n0 = _createIf(() => (1), () => {
+    const n2 = t0()
+    return n2
+  }, null, true)
+  return n4
+}"
+`;
+
 exports[`compiler: children transform > children & sibling references 1`] = `
 "import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div><p> </p> <p> </p></div>", true)
index b94e555351833d593e366e696a949aae4638a655..e656312356cc97806810c248df3ed0ba4072572d 100644 (file)
@@ -59,4 +59,18 @@ describe('compiler: children transform', () => {
     expect(code).contains(`const n0 = _nthChild(n1, 2)`)
     expect(code).toMatchSnapshot()
   })
+
+  test('anchor insertion in middle', () => {
+    const { code } = compileWithElementTransform(
+      `<div>
+        <div></div>
+        <div v-if="1"></div>
+        <div></div>
+      </div>`,
+    )
+    // ensure the insertion anchor is generated before the insertion statement
+    expect(code).toMatch(`const n3 = _next(_child(n4))
+  _setInsertionState(n4, n3)`)
+    expect(code).toMatchSnapshot()
+  })
 })
index dfd0082d7e1f132ffddf455769713d2831e4d266..356c1ccbe15c4d77b400f435111c175b0c485056 100644 (file)
@@ -94,15 +94,23 @@ export function genChildren(
         push(...init)
       }
     }
+
+    if (id === child.anchor) {
+      push(...genSelf(child, context))
+    }
+
     if (id !== undefined) {
       push(...genDirectivesForElement(id, context))
     }
+
     prev = [variable, elementIndex]
     childrenToGen.push([child, variable])
   }
 
-  for (const [child, from] of childrenToGen) {
-    push(...genChildren(child, context, from))
+  if (childrenToGen.length) {
+    for (const [child, from] of childrenToGen) {
+      push(...genChildren(child, context, from))
+    }
   }
 
   return frag
index 666f5a68f04a427832ab4bae05b04a8317db0750..d89d5fab374a851b8ae5256d3005f542fe520fb4 100644 (file)
@@ -239,6 +239,27 @@ describe('Vapor Mode hydration', () => {
     )
   })
 
+  // problem is the <!> placeholder does not exist in SSR output
+  test.todo('component with anchor insertion', async () => {
+    const { container, data } = await testHydration(
+      `
+      <template><div><span/><components.Child/><span/></div></template>
+      `,
+      {
+        Child: `<template>{{ data }}</template>`,
+      },
+    )
+    expect(container.innerHTML).toMatchInlineSnapshot(
+      `"<div><span></span>foo<span></span></div>"`,
+    )
+
+    data.value = 'bar'
+    await nextTick()
+    expect(container.innerHTML).toMatchInlineSnapshot(
+      `"<div><span></span>foo<span></span></div>"`,
+    )
+  })
+
   test.todo('if')
 
   test.todo('for')