Skip to content

Commit e9c9e49

Browse files
committed
wip: refactor hydration for v-if
1 parent 38d4889 commit e9c9e49

17 files changed

+274
-67
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ describe('ssr: components', () => {
245245
_push(\`<span\${_scopeId}></span>\`)
246246
})
247247
_push(\`<!--]--></div>\`)
248+
_push(\`<!--$-->\`)
248249
} else {
249250
_push(\`<!---->\`)
250251
}
@@ -268,6 +269,7 @@ describe('ssr: components', () => {
268269
_push(\`<span\${_scopeId}></span>\`)
269270
})
270271
_push(\`<!--]--></div>\`)
272+
_push(\`<!--$-->\`)
271273
} else {
272274
_push(\`<!---->\`)
273275
}
@@ -361,6 +363,7 @@ describe('ssr: components', () => {
361363
_push(\`\`)
362364
if (false) {
363365
_push(\`<div\${_scopeId}></div>\`)
366+
_push(\`<!--$-->\`)
364367
} else {
365368
_push(\`<!---->\`)
366369
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('ssr: attrs fallthrough', () => {
2929
_push(\`<!--[-->\`)
3030
if (true) {
3131
_push(\`<div></div>\`)
32+
_push(\`<!--$-->\`)
3233
} else {
3334
_push(\`<!---->\`)
3435
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ describe('ssr: inject <style vars>', () => {
7070
const _cssVars = { style: { color: _ctx.color }}
7171
if (_ctx.ok) {
7272
_push(\`<div\${_ssrRenderAttrs(_mergeProps(_attrs, _cssVars))}></div>\`)
73+
_push(\`<!--$-->\`)
7374
} else {
7475
_push(\`<!--[--><div\${
7576
_ssrRenderAttrs(_cssVars)

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

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ describe('ssr: <slot>', () => {
153153
return function ssrRender(_ctx, _push, _parent, _attrs) {
154154
if (true) {
155155
_ssrRenderSlotInner(_ctx.$slots, "default", {}, null, _push, _parent, null, true)
156+
_push(\`<!--$-->\`)
156157
} else {
157158
_push(\`<!---->\`)
158159
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ describe('transition-group', () => {
5454
})
5555
if (false) {
5656
_push(\`<div></div>\`)
57+
_push(\`<!--$-->\`)
5758
}
5859
_push(\`</ul>\`)
5960
}"
@@ -123,6 +124,7 @@ describe('transition-group', () => {
123124
})
124125
if (_ctx.ok) {
125126
_push(\`<div>ok</div>\`)
127+
_push(\`<!--$-->\`)
126128
}
127129
_push(\`<!--]-->\`)
128130
}"

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

+21-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ describe('ssr: v-if', () => {
88
return function ssrRender(_ctx, _push, _parent, _attrs) {
99
if (_ctx.foo) {
1010
_push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
11+
_push(\`<!--$-->\`)
1112
} else {
1213
_push(\`<!---->\`)
1314
}
@@ -23,6 +24,7 @@ describe('ssr: v-if', () => {
2324
return function ssrRender(_ctx, _push, _parent, _attrs) {
2425
if (_ctx.foo) {
2526
_push(\`<div\${_ssrRenderAttrs(_attrs)}>hello<span>ok</span></div>\`)
27+
_push(\`<!--$-->\`)
2628
} else {
2729
_push(\`<!---->\`)
2830
}
@@ -38,6 +40,7 @@ describe('ssr: v-if', () => {
3840
return function ssrRender(_ctx, _push, _parent, _attrs) {
3941
if (_ctx.foo) {
4042
_push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
43+
_push(\`<!--$-->\`)
4144
} else {
4245
_push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
4346
}
@@ -53,8 +56,10 @@ describe('ssr: v-if', () => {
5356
return function ssrRender(_ctx, _push, _parent, _attrs) {
5457
if (_ctx.foo) {
5558
_push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
59+
_push(\`<!--$-->\`)
5660
} else if (_ctx.bar) {
5761
_push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
62+
_push(\`<!--$-->\`)
5863
} else {
5964
_push(\`<!---->\`)
6065
}
@@ -70,8 +75,10 @@ describe('ssr: v-if', () => {
7075
return function ssrRender(_ctx, _push, _parent, _attrs) {
7176
if (_ctx.foo) {
7277
_push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
78+
_push(\`<!--$-->\`)
7379
} else if (_ctx.bar) {
7480
_push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
81+
_push(\`<!--$-->\`)
7582
} else {
7683
_push(\`<p\${_ssrRenderAttrs(_attrs)}></p>\`)
7784
}
@@ -82,15 +89,16 @@ describe('ssr: v-if', () => {
8289
test('<template v-if> (text)', () => {
8390
expect(compile(`<template v-if="foo">hello</template>`).code)
8491
.toMatchInlineSnapshot(`
85-
"
86-
return function ssrRender(_ctx, _push, _parent, _attrs) {
87-
if (_ctx.foo) {
88-
_push(\`<!--[-->hello<!--]-->\`)
89-
} else {
90-
_push(\`<!---->\`)
91-
}
92-
}"
93-
`)
92+
"
93+
return function ssrRender(_ctx, _push, _parent, _attrs) {
94+
if (_ctx.foo) {
95+
_push(\`<!--[-->hello<!--]-->\`)
96+
_push(\`<!--$-->\`)
97+
} else {
98+
_push(\`<!---->\`)
99+
}
100+
}"
101+
`)
94102
})
95103

96104
test('<template v-if> (single element)', () => {
@@ -102,6 +110,7 @@ describe('ssr: v-if', () => {
102110
return function ssrRender(_ctx, _push, _parent, _attrs) {
103111
if (_ctx.foo) {
104112
_push(\`<div\${_ssrRenderAttrs(_attrs)}>hi</div>\`)
113+
_push(\`<!--$-->\`)
105114
} else {
106115
_push(\`<!---->\`)
107116
}
@@ -118,6 +127,7 @@ describe('ssr: v-if', () => {
118127
return function ssrRender(_ctx, _push, _parent, _attrs) {
119128
if (_ctx.foo) {
120129
_push(\`<!--[--><div>hi</div><div>ho</div><!--]-->\`)
130+
_push(\`<!--$-->\`)
121131
} else {
122132
_push(\`<!---->\`)
123133
}
@@ -138,6 +148,7 @@ describe('ssr: v-if', () => {
138148
_push(\`<div></div>\`)
139149
})
140150
_push(\`<!--]-->\`)
151+
_push(\`<!--$-->\`)
141152
} else {
142153
_push(\`<!---->\`)
143154
}
@@ -156,6 +167,7 @@ describe('ssr: v-if', () => {
156167
return function ssrRender(_ctx, _push, _parent, _attrs) {
157168
if (_ctx.foo) {
158169
_push(\`<!--[--><div>hi</div><div>ho</div><!--]-->\`)
170+
_push(\`<!--$-->\`)
159171
} else {
160172
_push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
161173
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ describe('ssr: v-model', () => {
9191
? _ssrLooseContain(_ctx.model, _ctx.i)
9292
: _ssrLooseEqual(_ctx.model, _ctx.i))) ? " selected" : ""
9393
}></option>\`)
94+
_push(\`<!--$-->\`)
9495
} else {
9596
_push(\`<!---->\`)
9697
}

packages/compiler-ssr/src/ssrCodegenTransform.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,13 @@ function processChildrenDynamicInfo(
295295

296296
for (let i = 0; i < filteredChildren.length; i++) {
297297
const child = filteredChildren[i]
298-
if (isStaticChildNode(child)) continue
299-
298+
if (
299+
isStaticChildNode(child) ||
300+
// v-if has an anchor, which can be used to distinguish the boundary
301+
child.type === NodeTypes.IF
302+
) {
303+
continue
304+
}
300305
child._ssrDynamicInfo = {
301306
hasStaticPrevious: false,
302307
hasStaticNext: false,

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,13 @@ function processIfBranch(
7474
(children.length !== 1 || children[0].type !== NodeTypes.ELEMENT) &&
7575
// optimize away nested fragments when the only child is a ForNode
7676
!(children.length === 1 && children[0].type === NodeTypes.FOR)
77-
return processChildrenAsStatement(branch, context, needFragmentWrapper)
77+
const statement = processChildrenAsStatement(
78+
branch,
79+
context,
80+
needFragmentWrapper,
81+
)
82+
if (branch.condition) {
83+
statement.body.push(createCallExpression(`_push`, ['`<!--$-->`']))
84+
}
85+
return statement
7886
}

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -598,14 +598,14 @@ describe('SSR hydration', () => {
598598
const ctx: SSRContext = {}
599599
container.innerHTML = await renderToString(h(App), ctx)
600600
expect(container.innerHTML).toBe(
601-
'<div><!--teleport start--><!--teleport end--></div>',
601+
'<div><!--teleport start--><!--teleport end--><!--$--></div>',
602602
)
603603
teleportContainer.innerHTML = ctx.teleports!['#target']
604604

605605
// hydrate
606606
createSSRApp(App).mount(container)
607607
expect(container.innerHTML).toBe(
608-
'<div><!--teleport start--><!--teleport end--></div>',
608+
'<div><!--teleport start--><!--teleport end--><!--$--></div>',
609609
)
610610
expect(teleportContainer.innerHTML).toBe(
611611
'<!--teleport start anchor--><span>Teleported Comp1</span><!--teleport anchor-->',
@@ -614,7 +614,7 @@ describe('SSR hydration', () => {
614614

615615
toggle.value = false
616616
await nextTick()
617-
expect(container.innerHTML).toBe('<div><div>Comp2</div></div>')
617+
expect(container.innerHTML).toBe('<div><div>Comp2</div><!--$--></div>')
618618
expect(teleportContainer.innerHTML).toBe('')
619619
})
620620

@@ -657,21 +657,21 @@ describe('SSR hydration', () => {
657657
// server render
658658
container.innerHTML = await renderToString(h(App))
659659
expect(container.innerHTML).toBe(
660-
'<div><!--teleport start--><!--teleport end--></div>',
660+
'<div><!--teleport start--><!--teleport end--><!--$--></div>',
661661
)
662662
expect(teleportContainer.innerHTML).toBe('')
663663

664664
// hydrate
665665
createSSRApp(App).mount(container)
666666
expect(container.innerHTML).toBe(
667-
'<div><!--teleport start--><!--teleport end--></div>',
667+
'<div><!--teleport start--><!--teleport end--><!--$--></div>',
668668
)
669669
expect(teleportContainer.innerHTML).toBe('<span>Teleported Comp1</span>')
670670
expect(`Hydration children mismatch`).toHaveBeenWarned()
671671

672672
toggle.value = false
673673
await nextTick()
674-
expect(container.innerHTML).toBe('<div><div>Comp2</div></div>')
674+
expect(container.innerHTML).toBe('<div><div>Comp2</div><!--$--></div>')
675675
expect(teleportContainer.innerHTML).toBe('')
676676
})
677677

packages/runtime-core/src/hydration.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,14 @@ const getContainerType = (
8484
return undefined
8585
}
8686

87-
export function isDynamicAnchor(node: Node): boolean {
87+
export function isDynamicAnchor(node: Node): node is Comment {
8888
return isComment(node) && (node.data === '[[' || node.data === ']]')
8989
}
9090

91+
export function isDynamicFragmentEndAnchor(node: Node): node is Comment {
92+
return isComment(node) && node.data === '$'
93+
}
94+
9195
export const isComment = (node: Node): node is Comment =>
9296
node.nodeType === DOMNodeTypes.COMMENT
9397

@@ -125,8 +129,10 @@ export function createHydrationFunctions(
125129

126130
function nextSibling(node: Node) {
127131
let n = next(node)
128-
// skip dynamic anchors
129-
if (n && isDynamicAnchor(n)) {
132+
// skip if:
133+
// - dynamic anchors (`<!--[-->`, `<!--]-->`)
134+
// - dynamic fragment end anchors (`<!--$-->`)
135+
if (n && (isDynamicAnchor(n) || isDynamicFragmentEndAnchor(n))) {
130136
n = next(n)
131137
}
132138
return n
@@ -158,7 +164,9 @@ export function createHydrationFunctions(
158164
slotScopeIds: string[] | null,
159165
optimized = false,
160166
): Node | null => {
161-
if (isDynamicAnchor(node)) node = nextSibling(node)!
167+
if (isDynamicAnchor(node) || isDynamicFragmentEndAnchor(node)) {
168+
node = nextSibling(node)!
169+
}
162170
optimized = optimized || !!vnode.dynamicChildren
163171
const isFragmentStart = isComment(node) && node.data === '['
164172
const onMismatch = () =>

packages/runtime-core/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -560,4 +560,4 @@ export { initFeatureFlags } from './featureFlags'
560560
/**
561561
* @internal
562562
*/
563-
export { isDynamicAnchor } from './hydration'
563+
export { isDynamicAnchor, isDynamicFragmentEndAnchor } from './hydration'

0 commit comments

Comments
 (0)