wip: update
This commit is contained in:
parent
e5399c3418
commit
4253b0ce3e
|
@ -1963,8 +1963,56 @@ describe('Vapor Mode hydration', () => {
|
|||
data,
|
||||
)
|
||||
|
||||
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div><!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->hi</div>"`,
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div>` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`hi` +
|
||||
`</div>`,
|
||||
)
|
||||
|
||||
data.msg = 'bar'
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div>` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`bar` +
|
||||
`</div>`,
|
||||
)
|
||||
})
|
||||
|
||||
test('mixed root slot and text node', async () => {
|
||||
const data = reactive({
|
||||
text: 'foo',
|
||||
msg: 'hi',
|
||||
})
|
||||
const { container } = await testHydration(
|
||||
`<template>
|
||||
<components.Child>
|
||||
<span>{{data.text}}</span>
|
||||
</components.Child>
|
||||
</template>`,
|
||||
{
|
||||
Child: `<template>{{data.text}}<slot/>{{data.msg}}</template>`,
|
||||
},
|
||||
data,
|
||||
)
|
||||
|
||||
expect(container.innerHTML).toBe(
|
||||
`<!--[-->` +
|
||||
`foo` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`hi` +
|
||||
`<!--]-->`,
|
||||
)
|
||||
|
||||
data.msg = 'bar'
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
`<!--[-->` +
|
||||
`foo` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`bar` +
|
||||
`<!--]-->`,
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -1985,8 +2033,20 @@ describe('Vapor Mode hydration', () => {
|
|||
data,
|
||||
)
|
||||
|
||||
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div><!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}--><div>hi</div></div>"`,
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div>` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`<div>hi</div>` +
|
||||
`</div>`,
|
||||
)
|
||||
|
||||
data.msg = 'bar'
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div>` +
|
||||
`<!--[--><span>foo</span><!--]--><!--${slotAnchorLabel}-->` +
|
||||
`<div>bar</div>` +
|
||||
`</div>`,
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -2024,6 +2084,7 @@ describe('Vapor Mode hydration', () => {
|
|||
`<div>bar</div>` +
|
||||
`</div>`,
|
||||
)
|
||||
|
||||
data.msg2 = 'hello'
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
|
|
|
@ -22,7 +22,10 @@ export function createDynamicComponent(
|
|||
const _insertionAnchor = insertionAnchor
|
||||
if (!isHydrating) resetInsertionState()
|
||||
|
||||
const frag = new DynamicFragment(DYNAMIC_COMPONENT_ANCHOR_LABEL)
|
||||
const frag =
|
||||
isHydrating || __DEV__
|
||||
? new DynamicFragment(DYNAMIC_COMPONENT_ANCHOR_LABEL)
|
||||
: new DynamicFragment()
|
||||
renderEffect(() => {
|
||||
const value = getter()
|
||||
frag.update(
|
||||
|
|
|
@ -16,11 +16,7 @@ import {
|
|||
isObject,
|
||||
isString,
|
||||
} from '@vue/shared'
|
||||
import {
|
||||
createComment,
|
||||
createTextNode,
|
||||
findVaporFragmentAnchor,
|
||||
} from './dom/node'
|
||||
import { createComment, createTextNode } from './dom/node'
|
||||
import {
|
||||
type Block,
|
||||
VaporFragment,
|
||||
|
@ -34,6 +30,7 @@ import { renderEffect } from './renderEffect'
|
|||
import { VaporVForFlags } from '../../shared/src/vaporFlags'
|
||||
import {
|
||||
currentHydrationNode,
|
||||
findVaporFragmentAnchor,
|
||||
isHydrating,
|
||||
locateHydrationNode,
|
||||
} from './dom/hydration'
|
||||
|
|
|
@ -22,7 +22,10 @@ export function createIf(
|
|||
if (once) {
|
||||
frag = condition() ? b1() : b2 ? b2() : []
|
||||
} else {
|
||||
frag = new DynamicFragment(IF_ANCHOR_LABEL)
|
||||
frag =
|
||||
isHydrating || __DEV__
|
||||
? new DynamicFragment(IF_ANCHOR_LABEL)
|
||||
: new DynamicFragment()
|
||||
renderEffect(() => (frag as DynamicFragment).update(condition() ? b1 : b2))
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,11 @@ import {
|
|||
mountComponent,
|
||||
unmountComponent,
|
||||
} from './component'
|
||||
import {
|
||||
createComment,
|
||||
createTextNode,
|
||||
findVaporFragmentAnchor,
|
||||
} from './dom/node'
|
||||
import { createComment, createTextNode } from './dom/node'
|
||||
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
|
||||
import {
|
||||
currentHydrationNode,
|
||||
findVaporFragmentAnchor,
|
||||
isComment,
|
||||
isHydrating,
|
||||
locateHydrationNode,
|
||||
|
@ -92,13 +89,11 @@ export class DynamicFragment extends VaporFragment {
|
|||
}
|
||||
|
||||
hydrate(label: string): void {
|
||||
// for v-if="false" the hydrationNode will be a empty comment node
|
||||
// use it as anchor.
|
||||
// otherwise, use the next sibling comment node as anchor
|
||||
// for `v-if="false"` the node will be an empty comment node use it as the anchor.
|
||||
// otherwise, find next sibling vapor fragment anchor
|
||||
if (isComment(currentHydrationNode!, '')) {
|
||||
this.anchor = currentHydrationNode
|
||||
} else {
|
||||
// find next sibling dynamic fragment end anchor
|
||||
const anchor = findVaporFragmentAnchor(currentHydrationNode!, label)!
|
||||
if (anchor) {
|
||||
this.anchor = anchor
|
||||
|
|
|
@ -124,7 +124,10 @@ export function createSlot(
|
|||
fallback,
|
||||
)
|
||||
} else {
|
||||
fragment = new DynamicFragment(SLOT_ANCHOR_LABEL)
|
||||
fragment =
|
||||
isHydrating || __DEV__
|
||||
? new DynamicFragment(SLOT_ANCHOR_LABEL)
|
||||
: new DynamicFragment()
|
||||
const isDynamicName = isFunction(name)
|
||||
const renderSlot = () => {
|
||||
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
enableHydrationNodeLookup,
|
||||
next,
|
||||
} from './node'
|
||||
import { isVaporFragmentEndAnchor } from '@vue/shared'
|
||||
import { isDynamicAnchor, isVaporFragmentEndAnchor } from '@vue/shared'
|
||||
|
||||
export let isHydrating = false
|
||||
export let currentHydrationNode: Node | null = null
|
||||
|
@ -191,3 +191,29 @@ export function locateEndAnchor(
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function isNonHydrationNode(node: Node): boolean {
|
||||
return (
|
||||
// empty text nodes
|
||||
isEmptyText(node) ||
|
||||
// dynamic node anchors (<!--[[-->, <!--]]-->)
|
||||
isDynamicAnchor(node) ||
|
||||
// fragment end anchor (`<!--]-->`)
|
||||
isComment(node, ']') ||
|
||||
// vapor fragment end anchors
|
||||
isVaporFragmentEndAnchor(node)
|
||||
)
|
||||
}
|
||||
|
||||
export function findVaporFragmentAnchor(
|
||||
node: Node,
|
||||
anchorLabel: string,
|
||||
): Comment | null {
|
||||
let n = node.nextSibling
|
||||
while (n) {
|
||||
if (isComment(n, anchorLabel)) return n
|
||||
n = n.nextSibling
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { isComment, isEmptyText, locateEndAnchor } from './hydration'
|
||||
import { isComment, isNonHydrationNode, locateEndAnchor } from './hydration'
|
||||
import {
|
||||
DYNAMIC_END_ANCHOR_LABEL,
|
||||
DYNAMIC_START_ANCHOR_LABEL,
|
||||
isDynamicAnchor,
|
||||
isVaporFragmentEndAnchor,
|
||||
} from '@vue/shared'
|
||||
|
||||
|
@ -42,7 +41,7 @@ export function __child(node: ParentNode): Node {
|
|||
* _setInsertionState(n2, 0) -> slot fragment
|
||||
*
|
||||
* during hydration:
|
||||
* const n2 = _template("<div><!--[-->slot<!--]--><!--slot-->Hi</div>")()
|
||||
* const n2 = <div><!--[-->slot<!--]--><!--slot-->Hi</div> // server output
|
||||
* const n1 = _child(n2) -> should be `Hi` instead of the slot fragment
|
||||
* _setInsertionState(n2, 0) -> slot fragment
|
||||
*/
|
||||
|
@ -79,7 +78,19 @@ function _next(node: Node): Node {
|
|||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function __next(node: Node): Node {
|
||||
node = handleWrappedNode(node)
|
||||
// process dynamic node (<!--[[-->...<!--]]-->) as a single node
|
||||
if (isComment(node, DYNAMIC_START_ANCHOR_LABEL)) {
|
||||
node = locateEndAnchor(
|
||||
node,
|
||||
DYNAMIC_START_ANCHOR_LABEL,
|
||||
DYNAMIC_END_ANCHOR_LABEL,
|
||||
)!
|
||||
}
|
||||
|
||||
// process fragment (<!--[-->...<!--]-->) as a single node
|
||||
else if (isComment(node, '[')) {
|
||||
node = locateEndAnchor(node)!
|
||||
}
|
||||
|
||||
let n = node.nextSibling!
|
||||
while (n && isNonHydrationNode(n)) {
|
||||
|
@ -142,47 +153,3 @@ export function disableHydrationNodeLookup(): void {
|
|||
next.impl = _next
|
||||
nthChild.impl = _nthChild
|
||||
}
|
||||
|
||||
function isNonHydrationNode(node: Node) {
|
||||
return (
|
||||
// empty text nodes, no need to hydrate
|
||||
isEmptyText(node) ||
|
||||
// dynamic node anchors (<!--[[-->, <!--]]-->)
|
||||
isDynamicAnchor(node) ||
|
||||
// fragment end anchor (`<!--]-->`)
|
||||
isComment(node, ']') ||
|
||||
// vapor fragment end anchors
|
||||
isVaporFragmentEndAnchor(node)
|
||||
)
|
||||
}
|
||||
|
||||
export function findVaporFragmentAnchor(
|
||||
node: Node,
|
||||
anchorLabel: string,
|
||||
): Comment | null {
|
||||
let n = node.nextSibling
|
||||
while (n) {
|
||||
if (isComment(n, anchorLabel)) return n
|
||||
n = n.nextSibling
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function handleWrappedNode(node: Node): Node {
|
||||
// process dynamic node (<!--[[-->...<!--]]-->) as a single one
|
||||
if (isComment(node, DYNAMIC_START_ANCHOR_LABEL)) {
|
||||
return locateEndAnchor(
|
||||
node,
|
||||
DYNAMIC_START_ANCHOR_LABEL,
|
||||
DYNAMIC_END_ANCHOR_LABEL,
|
||||
)!
|
||||
}
|
||||
|
||||
// process fragment (<!--[-->...<!--]-->) as a single one
|
||||
else if (isComment(node, '[')) {
|
||||
return locateEndAnchor(node)!
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue