8000 wip: hydrate v-if · vuejs/core@38d4889 · GitHub
[go: up one dir, main page]

Skip to content

Commit 38d4889

Browse files
committed
wip: hydrate v-if
1 parent b5762b5 commit 38d4889

File tree

2 files changed

+122
-4
lines changed

2 files changed

+122
-4
lines changed

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

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createVaporSSRApp, delegateEvents } from '../src'
2-
import { nextTick, ref } from '@vue/runtime-dom'
2+
import { nextTick, reactive, ref } from '@vue/runtime-dom'
33
import { compileScript, parse } from '@vue/compiler-sfc'
44
import * as runtimeVapor from '../src'
55
import * as runtimeDom from '@vue/runtime-dom'
@@ -50,8 +50,8 @@ function compile(
5050
async function testHydration(
5151
code: string,
5252
components: Record<string, string> = {},
53+
data: any = ref('foo'),
5354
) {
54-
const data = ref('foo')
5555
const ssrComponents: any = {}
5656
const clientComponents: any = {}
5757
for (const key in components) {
@@ -638,7 +638,100 @@ describe('Vapor Mode hydration', () => {
638638
)
639639
})
640640

641-
test.todo('if')
641+
describe('if', () => {
642+
test('basic toggle - true -> false', asy 8000 nc () => {
643+
const data = ref(true)
644+
const { container } = await testHydration(
645+
`<template>
646+
<div v-if="data">foo</div>
647+
</template>`,
648+
undefined,
649+
data,
650+
)
651+
expect(container.innerHTML).toMatchInlineSnapshot(
652+
`"<div>foo</div><!--if-->"`,
653+
)
654+
655+
data.value = false
656+
await nextTick()
657+
expect(container.innerHTML).toMatchInlineSnapshot(`"<!--if-->"`)
658+
})
659+
660+
test('basic toggle - false -> true', async () => {
661+
const data = ref(false)
662+
const { container } = await testHydration(
663+
`<template>
664+
<div v-if="data">foo</div>
665+
</template>`,
666+
undefined,
667+
data,
668+
)
669+
expect(container.innerHTML).toMatchInlineSnapshot(`"<!--if-->"`)
670+
671+
data.value = true
672+
await nextTick()
673+
expect(container.innerHTML).toMatchInlineSnapshot(
674+
`"<div>foo</div><!--if-->"`,
675+
)
676+
})
677+
678+
test('v-if/else-if/else chain - switch branches', async () => {
679+
const data = ref('a')
680+
const { container } = await testHydration(
681+
`<template>
682+
<div v-if="data === 'a'">foo</div>
683+
<div v-else-if="data === 'b'">bar</div>
684+
<div v-else>baz</div>
685+
</template>`,
686+
undefined,
687+
data,
688+
)
689+
expect(container.innerHTML).toMatchInlineSnapshot(
690+
`"<div>foo</div><!--if-->"`,
691+
)
692+
693+
data.value = 'b'
694+
await nextTick()
695+
expect(container.innerHTML).toMatchInlineSnapshot(
696+
`"<div>bar</div><!--if--><!--if-->"`,
697+
)
698+
699+
data.value = 'c'
700+
await nextTick()
701+
expect(container.innerHTML).toMatchInlineSnapshot(
702+
`"<div>baz</div><!--if--><!--if-->"`,
703+
)
704+
})
705+
706+
test('nested if', async () => {
707+
const data = reactive({ outer: true, inner: true })
708+
const { container } = await testHydration(
709+
`<template>
710+
<div v-if="data.outer">
711+
<span>outer</span>
712+
<div v-if="data.inner">inner</div>
713+
</div>
714+
</template>`,
715+
undefined,
716+
data,
717+
)
718+
expect(container.innerHTML).toMatchInlineSnapshot(
719+
`"<div><span>outer</span><div>inner</div><!--if--></div><!--if-->"`,
720+
)
721+
722+
data.inner = false
723+
await nextTick()
724+
expect(container.innerHTML).toMatchInlineSnapshot(
725+
`"<div><span>outer</span><!--if--></div><!--if-->"`,
726+
)
727+
728+
data.outer = false
729+
await nextTick()
730+
expect(container.innerHTML).toMatchInlineSnapshot(`"<!--if-->"`)
731+
})
732+
733+
test.todo('on component', async () => {})
734+
})
642735

643736
test.todo('for')
644737

packages/runtime-vapor/src/apiCreateIf.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { type Block, type BlockFn, DynamicFragment, insert } from './block'
2-
import { isHydrating, locateHydrationNode } from './dom/hydration'
2+
import {
3+
currentHydrationNode,
4+
isComment,
5+
isHydrating,
6+
locateHydrationNode,
7+
} from './dom/hydration'
38
import { insertionAnchor, insertionParent } from './insertionState'
49
import { renderEffect } from './renderEffect'
510

@@ -11,8 +16,10 @@ export function createIf(
1116
): Block {
1217
const _insertionParent = insertionParent
1318
const _insertionAnchor = insertionAnchor
19+
let _currentHydrationNode
1420
if (isHydrating) {
1521
locateHydrationNode()
22+
_currentHydrationNode = currentHydrationNode
1623
}
1724

1825
let frag: Block
@@ -27,5 +34,23 @@ export function createIf(
2734
insert(frag, _insertionParent, _insertionAnchor)
2835
}
2936

37+
// if the current hydration node is a comment, use it as an anchor
38+
// otherwise need to insert the anchor node
39+
// OR adjust ssr output to add anchor for v-if
40+
else if (isHydrating && _currentHydrationNode) {
41+
const parentNode = _currentHydrationNode.parentNode
42+
if (parentNode) {
43+
if (isComment(_currentHydrationNode, '')) {
44+
if (__DEV__) _currentHydrationNode.data = 'if'
45+
;(frag as DynamicFragment).anchor = _currentHydrationNode
46+
} else {
47+
parentNode.insertBefore(
48+
(frag as DynamicFragment).anchor,
49+
_currentHydrationNode.nextSibling,
50+
)
51+
}
52+
}
53+
}
54+
3055
return frag
3156
}

0 commit comments

Comments
 (0)
0