refactor(core): refactor i18n node creation to prepare for hydration (#54722)

Adds a `locateOrCreateNode` helper and uses it for all DOM operations in preparation for supporting hydration.

PR Close #54722
This commit is contained in:
Gerald Monaco 2024-03-06 15:59:08 +00:00 committed by Andrew Scott
parent 658ae699d8
commit 0daa1ea19d

View file

@ -18,7 +18,7 @@ import {RElement, RNode, RText} from '../interfaces/renderer_dom';
import {SanitizerFn} from '../interfaces/sanitization';
import {HEADER_OFFSET, LView, RENDERER, TView} from '../interfaces/view';
import {createCommentNode, createElementNode, createTextNode, nativeInsertBefore, nativeParentNode, nativeRemoveNode, updateTextNode} from '../node_manipulation';
import {getBindingIndex} from '../state';
import {getBindingIndex, lastNodeWasCreated} from '../state';
import {renderStringify} from '../util/stringify_utils';
import {getNativeByIndex, unwrapRNode} from '../util/view_utils';
@ -78,6 +78,25 @@ export function applyI18n(tView: TView, lView: LView, index: number) {
changeMaskCounter = 0;
}
function locateOrCreateNode(
lView: LView, index: number, textOrName: string,
nodeType: typeof Node.COMMENT_NODE|typeof Node.TEXT_NODE|typeof Node.ELEMENT_NODE) {
// TODO: Add support for hydration
lastNodeWasCreated(true);
const renderer = lView[RENDERER];
switch (nodeType) {
case Node.COMMENT_NODE:
return createCommentNode(renderer, textOrName);
case Node.TEXT_NODE:
return createTextNode(renderer, textOrName);
case Node.ELEMENT_NODE:
return createElementNode(renderer, textOrName, null);
}
}
/**
* Apply `I18nCreateOpCodes` op-codes as stored in `TI18n.create`.
@ -106,7 +125,7 @@ export function applyCreateOpCodes(
// We only create new DOM nodes if they don't already exist: If ICU switches case back to a
// case which was already instantiated, no need to create new DOM nodes.
rNode = lView[index] =
isComment ? renderer.createComment(text) : createTextNode(renderer, text);
locateOrCreateNode(lView, index, text, isComment ? Node.COMMENT_NODE : Node.TEXT_NODE);
}
if (appendNow && parentRNode !== null) {
nativeInsertBefore(renderer, parentRNode, rNode, insertInFrontOf, false);
@ -141,7 +160,7 @@ export function applyMutableOpCodes(
if (lView[textNodeIndex] === null) {
ngDevMode && ngDevMode.rendererCreateTextNode++;
ngDevMode && assertIndexInRange(lView, textNodeIndex);
lView[textNodeIndex] = createTextNode(renderer, opCode);
lView[textNodeIndex] = locateOrCreateNode(lView, textNodeIndex, opCode, Node.TEXT_NODE);
}
} else if (typeof opCode == 'number') {
switch (opCode & IcuCreateOpCode.MASK_INSTRUCTION) {
@ -219,7 +238,7 @@ export function applyMutableOpCodes(
ngDevMode && ngDevMode.rendererCreateComment++;
ngDevMode && assertIndexInExpandoRange(lView, commentNodeIndex);
const commentRNode = lView[commentNodeIndex] =
createCommentNode(renderer, commentValue);
locateOrCreateNode(lView, commentNodeIndex, commentValue, Node.COMMENT_NODE);
// FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
attachPatchData(commentRNode, lView);
}
@ -236,7 +255,7 @@ export function applyMutableOpCodes(
ngDevMode && ngDevMode.rendererCreateElement++;
ngDevMode && assertIndexInExpandoRange(lView, elementNodeIndex);
const elementRNode = lView[elementNodeIndex] =
createElementNode(renderer, tagName, null);
locateOrCreateNode(lView, elementNodeIndex, tagName, Node.ELEMENT_NODE);
// FIXME(misko): Attaching patch data is only needed for the root (Also add tests)
attachPatchData(elementRNode, lView);
}