mirror of https://github.com/vuejs/core.git
refactor: add enableHydrationNodeLookup and disableHydrationNodeLookup functions for node handling
This commit is contained in:
parent
1248172216
commit
25b8fbe2fd
|
@ -84,6 +84,10 @@ const getContainerType = (
|
|||
return undefined
|
||||
}
|
||||
|
||||
export function isDynamicAnchor(node: Node): boolean {
|
||||
return isComment(node) && (node.data === '[[' || node.data === ']]')
|
||||
}
|
||||
|
||||
export const isComment = (node: Node): node is Comment =>
|
||||
node.nodeType === DOMNodeTypes.COMMENT
|
||||
|
||||
|
@ -119,10 +123,6 @@ export function createHydrationFunctions(
|
|||
},
|
||||
} = rendererInternals
|
||||
|
||||
function isDynamicAnchor(node: Node): boolean {
|
||||
return isComment(node) && (node.data === '[[' || node.data === ']]')
|
||||
}
|
||||
|
||||
function nextSibling(node: Node) {
|
||||
let n = next(node)
|
||||
// skip dynamic child anchor
|
||||
|
|
|
@ -557,3 +557,7 @@ export { startMeasure, endMeasure } from './profiling'
|
|||
* @internal
|
||||
*/
|
||||
export { initFeatureFlags } from './featureFlags'
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export { isDynamicAnchor } from './hydration'
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import { warn } from '@vue/runtime-dom'
|
||||
import {
|
||||
type Anchor,
|
||||
insertionAnchor,
|
||||
insertionParent,
|
||||
resetInsertionState,
|
||||
setInsertionState,
|
||||
} from '../insertionState'
|
||||
import { child, next } from './node'
|
||||
import {
|
||||
child,
|
||||
disableHydrationNodeLookup,
|
||||
enableHydrationNodeLookup,
|
||||
next,
|
||||
} from './node'
|
||||
|
||||
export let isHydrating = false
|
||||
export let currentHydrationNode: Node | null = null
|
||||
|
@ -25,18 +29,26 @@ export function withHydration(container: ParentNode, fn: () => void): void {
|
|||
;(Comment.prototype as any).$fs = undefined
|
||||
isOptimized = true
|
||||
}
|
||||
enableHydrationNodeLookup()
|
||||
isHydrating = true
|
||||
setInsertionState(container, 0)
|
||||
const res = fn()
|
||||
resetInsertionState()
|
||||
currentHydrationNode = null
|
||||
isHydrating = false
|
||||
disableHydrationNodeLookup()
|
||||
return res
|
||||
}
|
||||
|
||||
export let adoptTemplate: (node: Node, template: string) => Node | null
|
||||
export let locateHydrationNode: () => void
|
||||
|
||||
type Anchor = Comment & {
|
||||
// cached matching fragment start to avoid repeated traversal
|
||||
// on nested fragments
|
||||
$fs?: Anchor
|
||||
}
|
||||
|
||||
export const isComment = (node: Node, data: string): node is Anchor =>
|
||||
node.nodeType === 8 && (node as Comment).data === data
|
||||
|
||||
|
@ -120,10 +132,6 @@ function locateHydrationNodeImpl() {
|
|||
currentHydrationNode = node
|
||||
}
|
||||
|
||||
export function isDynamicAnchor(node: Node): node is Comment {
|
||||
return isComment(node, '[[') || isComment(node, ']]')
|
||||
}
|
||||
|
||||
export function isEmptyText(node: Node): node is Text {
|
||||
return node.nodeType === 3 && !(node as Text).data.trim()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import {
|
||||
isComment,
|
||||
isDynamicAnchor,
|
||||
isEmptyText,
|
||||
isHydrating,
|
||||
locateEndAnchor,
|
||||
} from './hydration'
|
||||
import { isDynamicAnchor } from '@vue/runtime-dom'
|
||||
import { isComment, isEmptyText, locateEndAnchor } from './hydration'
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function createTextNode(value = ''): Text {
|
||||
|
@ -27,9 +22,12 @@ export function child(node: ParentNode): Node {
|
|||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function nthChild(node: Node, i: number): Node {
|
||||
if (!isHydrating) return node.childNodes[i]
|
||||
export function _nthChild(node: Node, i: number): Node {
|
||||
return node.childNodes[i]
|
||||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function __nthChild(node: Node, i: number): Node {
|
||||
let n = node.firstChild!
|
||||
for (let start = 0; start < i; start++) {
|
||||
n = next(n) as ChildNode
|
||||
|
@ -38,9 +36,12 @@ export function nthChild(node: Node, i: number): Node {
|
|||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export function next(node: Node): Node {
|
||||
if (!isHydrating) return node.nextSibling!
|
||||
function _next(node: Node): Node {
|
||||
return node.nextSibling!
|
||||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
function __next(node: Node): Node {
|
||||
// process fragment as a single node
|
||||
if (node && isComment(node, '[')) {
|
||||
node = locateEndAnchor(node)!
|
||||
|
@ -53,3 +54,46 @@ export function next(node: Node): Node {
|
|||
}
|
||||
return n
|
||||
}
|
||||
|
||||
type NextFn = (node: Node) => Node
|
||||
type NthChildFn = (node: Node, i: number) => Node
|
||||
|
||||
interface DelegatedNextFunction extends NextFn {
|
||||
impl: NextFn
|
||||
}
|
||||
interface DelegatedNthChildFunction extends NthChildFn {
|
||||
impl: NthChildFn
|
||||
}
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export const next: DelegatedNextFunction = node => {
|
||||
return next.impl(node)
|
||||
}
|
||||
next.impl = _next
|
||||
|
||||
/*! #__NO_SIDE_EFFECTS__ */
|
||||
export const nthChild: DelegatedNthChildFunction = (node, i) => {
|
||||
return nthChild.impl(node, i)
|
||||
}
|
||||
nthChild.impl = _nthChild
|
||||
|
||||
// During hydration, there might be differences between the server-rendered (SSR)
|
||||
// HTML and the client-side template.
|
||||
// For example, a dynamic node `<!>` in the template might be rendered as a
|
||||
// `Fragment` (`<!--[-->...<!--]-->`) in the SSR output.
|
||||
// The content of the `Fragment` affects the lookup results of the `next` and
|
||||
// `nthChild` functions.
|
||||
// To ensure the hydration process correctly finds nodes, we need to treat the
|
||||
// `Fragment` as a single node.
|
||||
// Therefore, during hydration, we need to temporarily switch the implementations
|
||||
// of `next` and `nthChild`. After hydration is complete, their implementations
|
||||
// are restored to the original versions.
|
||||
export function enableHydrationNodeLookup(): void {
|
||||
next.impl = __next
|
||||
nthChild.impl = __nthChild
|
||||
}
|
||||
|
||||
export function disableHydrationNodeLookup(): void {
|
||||
next.impl = _next
|
||||
nthChild.impl = _nthChild
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
export let insertionParent:
|
||||
| (ParentNode & {
|
||||
// cached the last dynamic start anchor
|
||||
$lds?: Anchor
|
||||
})
|
||||
| undefined
|
||||
export let insertionAnchor: Node | 0 | undefined | null
|
||||
export let insertionParent: ParentNode | undefined
|
||||
export let insertionAnchor: Node | 0 | undefined
|
||||
|
||||
/**
|
||||
* This function is called before a block type that requires insertion
|
||||
|
@ -19,13 +14,3 @@ export function setInsertionState(parent: ParentNode, anchor?: Node | 0): void {
|
|||
export function resetInsertionState(): void {
|
||||
insertionParent = insertionAnchor = undefined
|
||||
}
|
||||
|
||||
export function setInsertionAnchor(anchor: Node | null): void {
|
||||
insertionAnchor = anchor
|
||||
}
|
||||
|
||||
export type Anchor = Comment & {
|
||||
// cached matching fragment start to avoid repeated traversal
|
||||
// on nested fragments
|
||||
$fs?: Anchor
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue