Skip to content

Commit 9b7e68d

Browse files
committed
wip: refactor
1 parent 9c30fd4 commit 9b7e68d

File tree

5 files changed

+94
-74
lines changed

5 files changed

+94
-74
lines changed

packages/compiler-ssr/__tests__/ssrElement.spec.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ describe('ssr: element', () => {
398398
})
399399

400400
describe('dynamic child anchor', () => {
401-
test('with consecutive components', () => {
401+
test('consecutive components', () => {
402402
expect(
403403
getCompiledString(`
404404
<div>
@@ -409,14 +409,11 @@ describe('ssr: element', () => {
409409
</div>
410410
`),
411411
).toMatchInlineSnapshot(`
412-
"\`<div><div></div>\`)
413-
_push("<!--[[-->")
412+
"\`<div><div></div><!--[[-->\`)
414413
_push(_ssrRenderComponent(_component_Comp1, null, null, _parent))
415-
_push("<!--]]-->")
416-
_push("<!--[[-->")
414+
_push(\`<!--]]--><!--[[-->\`)
417415
_push(_ssrRenderComponent(_component_Comp2, null, null, _parent))
418-
_push("<!--]]-->")
419-
_push(\`<div></div></div>\`"
416+
_push(\`<!--]]--><div></div></div>\`"
420417
`)
421418
})
422419
})

packages/compiler-ssr/src/ssrCodegenTransform.ts

+88
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,29 @@ export function processChildren(
157157
asFragment = false,
158158
disableNestedFragments = false,
159159
disableComment = false,
160+
asDynamic = false,
160161
): void {
162+
if (asDynamic) {
163+
context.pushStringPart(`<!--[[-->`)
164+
}
161165
if (asFragment) {
162166
context.pushStringPart(`<!--[-->`)
163167
}
168+
164169
const { children } = parent
165170
for (let i = 0; i < children.length; i++) {
166171
const child = children[i]
172+
if (shouldProcessAsDynamic(parent, child)) {
173+
processChildren(
174+
{ children: [child] },
175+
context,
176+
asFragment,
177+
disableNestedFragments,
178+
disableComment,
179+
true,
180+
)
181+
continue
182+
}
167183
switch (child.type) {
168184
case NodeTypes.ELEMENT:
169185
switch (child.tagType) {
@@ -237,6 +253,9 @@ export function processChildren(
237253
if (asFragment) {
238254
context.pushStringPart(`<!--]-->`)
239255
}
256+
if (asDynamic) {
257+
context.pushStringPart(`<!--]]-->`)
258+
}
240259
}
241260

242261
export function processChildrenAsStatement(
@@ -249,3 +268,72 @@ export function processChildrenAsStatement(
249268
processChildren(parent, childContext, asFragment)
250269
return createBlockStatement(childContext.body)
251270
}
271+
272+
const isStaticElement = (c: TemplateChildNode): boolean =>
273+
c.type === NodeTypes.ELEMENT && c.tagType !== ElementTypes.COMPONENT
274+
275+
/**
276+
* Check if a node should be processed as dynamic.
277+
* This is primarily used in Vapor mode hydration to wrap dynamic parts
278+
* with markers (`<!--[[-->` and `<!--]]-->`).
279+
*
280+
* <element>
281+
* <element/> // Static previous sibling
282+
* <Comp/> // Dynamic node (current)
283+
* <Comp/> // Dynamic next sibling
284+
* <element/> // Static next sibling
285+
* </element>
286+
*/
287+
function shouldProcessAsDynamic(
288+
parent: { tag?: string; children: TemplateChildNode[] },
289+
node: TemplateChildNode,
290+
): boolean {
291+
// 1. Must be a dynamic node type
292+
if (isStaticElement(node)) return false
293+
// 2. Must be inside a parent element
294+
if (!parent.tag) return false
295+
296+
const children = parent.children
297+
const len = children.length
298+
const index = children.indexOf(node)
299+
300+
// 3. Check for a static previous sibling
301+
let hasStaticPreviousSibling = false
302+
if (index > 0) {
303+
for (let i = index - 1; i >= 0; i--) {
304+
if (isStaticElement(children[i])) {
305+
hasStaticPreviousSibling = true
306+
break
307+
}
308+
}
309+
}
310+
if (!hasStaticPreviousSibling) return false
311+
312+
// 4. Check for a static next sibling
313+
let hasStaticNextSibling = false
314+
if (index > -1 && index < len - 1) {
315+
for (let i = index + 1; i < len; i++) {
316+
if (isStaticElement(children[i])) {
317+
hasStaticNextSibling = true
318+
break
319+
}
320+
}
321+
}
322+
if (!hasStaticNextSibling) return false
323+
324+
// 5. Check for a consecutive dynamic sibling (immediately before or after)
325+
let hasConsecutiveDynamicNodes = false
326+
if (index > 0 && !isStaticElement(children[index - 1])) {
327+
hasConsecutiveDynamicNodes = true
328+
}
329+
if (
330+
!hasConsecutiveDynamicNodes &&
331+
index < len - 1 &&
332+
!isStaticElement(children[index + 1])
333+
) {
334+
hasConsecutiveDynamicNodes = true
335+
}
336+
337+
// Only process as dynamic if all conditions are met
338+
return hasConsecutiveDynamicNodes
339+
}

packages/compiler-ssr/src/transforms/ssrTransformComponent.ts

-65
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,6 @@ export function ssrProcessComponent(
255255
node.ssrCodegenNode.arguments.push(`_scopeId`)
256256
}
257257

258-
// `<!--[[-->` marks the start of the dynamic children
259-
// Only used in Vapor hydration, VDOM hydration
260-
// skips this marker.
261-
const needDynamicAnchor = shouldAddDynamicAnchor(parent, node)
262-
if (needDynamicAnchor) {
263-
context.pushStatement(createCallExpression(`_push`, [`"<!--[[-->"`]))
264-
}
265258
if (typeof component === 'string') {
266259
// static component
267260
context.pushStatement(
@@ -272,9 +265,6 @@ export function ssrProcessComponent(
272265
// the codegen node is a `renderVNode` call
273266
context.pushStatement(node.ssrCodegenNode)
274267
}
275-
if (needDynamicAnchor) {
276-
context.pushStatement(createCallExpression(`_push`, [`"<!--]]-->"`]))
277-
}
278268
}
279269
}
280270

@@ -394,58 +384,3 @@ function clone(v: any): any {
394384
return v
395385
}
396386
}
397-
398-
function shouldAddDynamicAnchor(
399-
parent: { tag?: string; children: TemplateChildNode[] },
400-
node: TemplateChildNode,
401-
): boolean {
402-
if (!parent.tag) return false
403-
404-
const children = parent.children
405-
const len = children.length
406-
const index = children.indexOf(node)
407-
408-
const isStaticElement = (c: TemplateChildNode): boolean =>
409-
c.type === NodeTypes.ELEMENT && c.tagType !== ElementTypes.COMPONENT
410-
411-
let hasStaticPreviousSibling = false
412-
if (index > 0) {
413-
for (let i = index - 1; i >= 0; i--) {
414-
if (isStaticElement(children[i])) {
415-
hasStaticPreviousSibling = true
416-
break
417-
}
418-
}
419-
}
420-
421-
let hasStaticNextSibling = false
422-
if (hasStaticPreviousSibling && index > -1 && index < len - 1) {
423-
for (let i = index + 1; i < len; i++) {
424-
if (isStaticElement(children[i])) {
425-
hasStaticNextSibling = true
426-
break
427-
}
428-
}
429-
}
430-
431-
let hasConsecutiveDynamicNodes = false
432-
if (index > 0 && index < len - 1) {
433-
if (index > 0 && !isStaticElement(children[index - 1])) {
434-
hasConsecutiveDynamicNodes = true
435-
}
436-
437-
if (
438-
!hasConsecutiveDynamicNodes &&
439-
index < len - 1 &&
440-
!isStaticElement(children[index + 1])
441-
) {
442-
hasConsecutiveDynamicNodes = true
443-
}
444-
}
445-
446-
return (
447-
hasStaticPreviousSibling &&
448-
hasStaticNextSibling &&
449-
hasConsecutiveDynamicNodes
450-
)
451-
}

packages/runtime-core/__tests__/hydration.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ describe('SSR hydration', () => {
18441844
})
18451845

18461846
describe('dynamic child anchor', () => {
1847-
test('with consecutive components', () => {
1847+
test('consecutive components', () => {
18481848
const Comp = {
18491849
render() {
18501850
return createTextVNode('foo')

packages/runtime-vapor/src/dom/hydration.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function locateHydrationNodeImpl() {
7676
if (insertionAnchor === 0) {
7777
node = child(insertionParent!)
7878
} else if (insertionParent && insertionAnchor) {
79-
// dynamic child anchor `<!--[[-->`
79+
// dynamic anchor `<!--[[-->`
8080
if (insertionAnchor && isDynamicStart(insertionAnchor)) {
8181
const anchor = (insertionParent!.$lds = insertionParent!.$lds
8282
? // continuous dynamic children, the next dynamic start must exist

0 commit comments

Comments
 (0)