processExpression,
} from '@vue/compiler-dom'
import {
- DYNAMIC_END_ANCHOR_LABEL,
- DYNAMIC_START_ANCHOR_LABEL,
+ BLOCK_END_ANCHOR_LABEL,
+ BLOCK_START_ANCHOR_LABEL,
escapeHtml,
isString,
} from '@vue/shared'
asFragment = false,
disableNestedFragments = false,
disableComment = false,
- asDynamic = false,
+ asBlock = false,
): void {
- if (asDynamic) {
- context.pushStringPart(`<!--${DYNAMIC_START_ANCHOR_LABEL}-->`)
+ if (asBlock) {
+ context.pushStringPart(`<!--${BLOCK_START_ANCHOR_LABEL}-->`)
}
if (asFragment) {
context.pushStringPart(`<!--[-->`)
const { children, type, tagType } = parent as PlainElementNode
const inElement =
type === NodeTypes.ELEMENT && tagType === ElementTypes.ELEMENT
- if (inElement) processChildrenDynamicInfo(children)
+ if (inElement) processChildrenBlockInfo(children)
for (let i = 0; i < children.length; i++) {
const child = children[i]
- if (inElement && shouldProcessChildAsDynamic(parent, child)) {
+ if (inElement && shouldProcessChildAsBlock(parent, child)) {
processChildren(
{ children: [child] },
context,
break
case ElementTypes.COMPONENT:
if (inElement)
- context.pushStringPart(`<!--${DYNAMIC_START_ANCHOR_LABEL}-->`)
+ context.pushStringPart(`<!--${BLOCK_START_ANCHOR_LABEL}-->`)
ssrProcessComponent(child, context, parent)
if (inElement)
- context.pushStringPart(`<!--${DYNAMIC_END_ANCHOR_LABEL}-->`)
+ context.pushStringPart(`<!--${BLOCK_END_ANCHOR_LABEL}-->`)
break
case ElementTypes.SLOT:
ssrProcessSlotOutlet(child, context)
if (asFragment) {
context.pushStringPart(`<!--]-->`)
}
- if (asDynamic) {
- context.pushStringPart(`<!--${DYNAMIC_END_ANCHOR_LABEL}-->`)
+ if (asBlock) {
+ context.pushStringPart(`<!--${BLOCK_END_ANCHOR_LABEL}-->`)
}
}
c.type === NodeTypes.TEXT ||
c.type === NodeTypes.COMMENT
-interface DynamicInfo {
+interface BlockInfo {
hasStaticPrevious: boolean
hasStaticNext: boolean
- prevDynamicCount: number
- nextDynamicCount: number
+ prevBlockCount: number
+ nextBlockCount: number
}
-function processChildrenDynamicInfo(
- children: (TemplateChildNode & { _ssrDynamicInfo?: DynamicInfo })[],
+function processChildrenBlockInfo(
+ children: (TemplateChildNode & { _ssrBlockInfo?: BlockInfo })[],
): void {
const filteredChildren = children.filter(
child => !(child.type === NodeTypes.TEXT && !child.content.trim()),
) {
continue
}
- child._ssrDynamicInfo = {
+ child._ssrBlockInfo = {
hasStaticPrevious: false,
hasStaticNext: false,
- prevDynamicCount: 0,
- nextDynamicCount: 0,
+ prevBlockCount: 0,
+ nextBlockCount: 0,
}
- const info = child._ssrDynamicInfo
+ const info = child._ssrBlockInfo
- // Calculate the previous static and dynamic node counts
+ // Calculate the previous static and block node counts
let foundStaticPrev = false
- let dynamicCountPrev = 0
+ let blockCountPrev = 0
for (let j = i - 1; j >= 0; j--) {
const prevChild = filteredChildren[j]
if (isStaticChildNode(prevChild)) {
foundStaticPrev = true
break
}
- // if the previous child has dynamic info, use it
- else if (prevChild._ssrDynamicInfo) {
- foundStaticPrev = prevChild._ssrDynamicInfo.hasStaticPrevious
- dynamicCountPrev = prevChild._ssrDynamicInfo.prevDynamicCount + 1
+ // if the previous child has block info, use it
+ else if (prevChild._ssrBlockInfo) {
+ foundStaticPrev = prevChild._ssrBlockInfo.hasStaticPrevious
+ blockCountPrev = prevChild._ssrBlockInfo.prevBlockCount + 1
break
}
- dynamicCountPrev++
+ blockCountPrev++
}
info.hasStaticPrevious = foundStaticPrev
- info.prevDynamicCount = dynamicCountPrev
+ info.prevBlockCount = blockCountPrev
- // Calculate the number of static and dynamic nodes afterwards
+ // Calculate the number of static and block nodes afterwards
let foundStaticNext = false
- let dynamicCountNext = 0
+ let blockCountNext = 0
for (let j = i + 1; j < filteredChildren.length; j++) {
const nextChild = filteredChildren[j]
if (isStaticChildNode(nextChild)) {
foundStaticNext = true
break
}
- // if the next child has dynamic info, use it
- else if (nextChild._ssrDynamicInfo) {
- foundStaticNext = nextChild._ssrDynamicInfo.hasStaticNext
- dynamicCountNext = nextChild._ssrDynamicInfo.nextDynamicCount + 1
+ // if the next child has block info, use it
+ else if (nextChild._ssrBlockInfo) {
+ foundStaticNext = nextChild._ssrBlockInfo.hasStaticNext
+ blockCountNext = nextChild._ssrBlockInfo.nextBlockCount + 1
break
}
- dynamicCountNext++
+ blockCountNext++
}
info.hasStaticNext = foundStaticNext
- info.nextDynamicCount = dynamicCountNext
+ info.nextBlockCount = blockCountNext
}
}
-/**
- * Check if a node should be processed as dynamic child.
- * This is primarily used in Vapor mode hydration to wrap dynamic parts
- * with markers (`<!--[[-->` and `<!--]]-->`).
- * The purpose is to distinguish the boundaries of nodes during vapor hydration
- *
- * 1. two consecutive dynamic nodes should only wrap the second one
- * <element>
- * <element/> // Static node
- * <Comp/> // Dynamic node -> should NOT be wrapped
- * <Comp/> // Dynamic node -> should be wrapped
- * <element/> // Static node
- * </element>
- *
- * 2. three or more consecutive dynamic nodes should only wrap the
- * middle nodes, leaving the first and last static.
- * <element>
- * <element/> // Static node
- * <Comp/> // Dynamic node -> should NOT be wrapped
- * <Comp/> // Dynamic node -> should be wrapped
- * <Comp/> // Dynamic node -> should be wrapped
- * <Comp/> // Dynamic node -> should NOT be wrapped
- * <element/> // Static node
- * </element>
- */
-function shouldProcessChildAsDynamic(
+function shouldProcessChildAsBlock(
parent: { tag?: string; children: TemplateChildNode[] },
- node: TemplateChildNode & { _ssrDynamicInfo?: DynamicInfo },
+ node: TemplateChildNode & { _ssrBlockInfo?: BlockInfo },
): boolean {
// must be inside a parent element
if (!parent.tag) return false
- // must has dynamic info
- const { _ssrDynamicInfo: info } = node
+ // must has block info
+ const { _ssrBlockInfo: info } = node
if (!info) return false
- const {
- hasStaticPrevious,
- hasStaticNext,
- prevDynamicCount,
- nextDynamicCount,
- } = info
+ const { hasStaticPrevious, hasStaticNext, prevBlockCount, nextBlockCount } =
+ info
// must have static nodes on both sides
if (!hasStaticPrevious || !hasStaticNext) return false
- const dynamicNodeCount = 1 + prevDynamicCount + nextDynamicCount
+ const blockNodeCount = 1 + prevBlockCount + nextBlockCount
- // For two consecutive dynamic nodes, mark the second one as dynamic
- if (dynamicNodeCount === 2) {
- return prevDynamicCount > 0
+ // For two consecutive block nodes, mark the second one as block
+ if (blockNodeCount === 2) {
+ return prevBlockCount > 0
}
- // For three or more dynamic nodes, mark the middle nodes as dynamic
- else if (dynamicNodeCount >= 3) {
- return prevDynamicCount > 0 && nextDynamicCount > 0
+ // For three or more block nodes, mark the middle nodes as block
+ else if (blockNodeCount >= 3) {
+ return prevBlockCount > 0 && nextBlockCount > 0
}
return false
import { isComment, isNonHydrationNode, locateEndAnchor } from './hydration'
import {
- DYNAMIC_END_ANCHOR_LABEL,
- DYNAMIC_START_ANCHOR_LABEL,
- isVaporAnchors,
+ BLOCK_END_ANCHOR_LABEL,
+ BLOCK_START_ANCHOR_LABEL,
+ isVaporAnchor,
} from '@vue/shared'
/*! #__NO_SIDE_EFFECTS__ */
* The subsequent `_setText(n1, ...)` would fail or target the wrong node.
*
* Solution (`__child`):
- * - `__child(n2, offset)` is used during hydration. It skips the dynamic children
+ * - `__child(n2, offset)` is used during hydration. It skips the block children
* to find the "Actual Text Node", correctly matching the client's expectation
* for `n1`.
*/
}
let n = offset ? __nthChild(node, offset) : node.firstChild!
- while (n && (isComment(n, '[') || isVaporAnchors(n))) {
+ while (n && (isComment(n, '[') || isVaporAnchor(n))) {
if (isComment(n, '[')) {
n = locateEndAnchor(n)!.nextSibling!
} else {
/**
* Hydration-specific version of `next`.
*
- * SSR comment anchors (fragments `<!--[-->...<!--]-->`, dynamic `<!--[[-->...<!--]]-->`)
+ * SSR comment anchors (fragments `<!--[-->...<!--]-->`, block `<!--[[-->...<!--]]-->`)
* disrupt standard `node.nextSibling` traversal during hydration. `_next` might
* return a comment node or an internal node of a fragment instead of skipping
* the entire fragment block.
*
* Example:
- * Template: `<div>Node1<!>Node2</div>` (where <!> is a dynamic component placeholder)
+ * Template: `<div>Node1<!>Node2</div>` (where <!> is a block node placeholder)
*
* Client Compiled Code (Simplified):
* const n2 = t0() // n2 = `<div>Node1<!---->Node2</div>`
* allowing the component to be hydrated correctly relative to `Node1` and `Node2`.
*
* This function ensures traversal correctly skips over non-hydration nodes and
- * treats entire fragment/dynamic blocks (when starting *from* their beginning anchor)
+ * treats entire fragment/block nodes (when starting *from* their beginning anchor)
* as single logical units to find the next actual sibling node for hydration matching.
*/
/*! #__NO_SIDE_EFFECTS__ */
export function __next(node: Node): Node {
- // process dynamic node (<!--[[-->...<!--]]-->) as a single node
- if (isComment(node, DYNAMIC_START_ANCHOR_LABEL)) {
+ // process block node (<!--[[-->...<!--]]-->) as a single node
+ if (isComment(node, BLOCK_START_ANCHOR_LABEL)) {
node = locateEndAnchor(
node,
- DYNAMIC_START_ANCHOR_LABEL,
- DYNAMIC_END_ANCHOR_LABEL,
+ BLOCK_START_ANCHOR_LABEL,
+ BLOCK_END_ANCHOR_LABEL,
)!
}