refactor(core): avoid creating DOM nodes before creating a TNode (#49172)

This commit updates the `elementStart` instruction to avoid creating DOM nodes before creating a corresponding TNode. This refactoring is needed to make sure this internal logic is consistent across all instructions.

PR Close #49172
This commit is contained in:
Andrew Kushnir
2023-02-22 21:46:45 -08:00
parent 04d8b6c61a
commit d0fa598fe4
2 changed files with 13 additions and 16 deletions
@@ -26,8 +26,8 @@ import {createDirectivesInstances, executeContentQueries, getOrCreateTNode, reso
function elementStartFirstCreatePass(
index: number, tView: TView, lView: LView, native: RElement, name: string,
attrsIndex?: number|null, localRefsIndex?: number): TElementNode {
index: number, tView: TView, lView: LView, name: string, attrsIndex?: number|null,
localRefsIndex?: number): TElementNode {
ngDevMode && assertFirstCreatePass(tView);
ngDevMode && ngDevMode.firstCreatePass++;
@@ -35,11 +35,7 @@ function elementStartFirstCreatePass(
const attrs = getConstant<TAttributes>(tViewConsts, attrsIndex);
const tNode = getOrCreateTNode(tView, index, TNodeType.Element, name, attrs);
const hasDirectives =
resolveDirectives(tView, lView, tNode, getConstant<string[]>(tViewConsts, localRefsIndex));
if (ngDevMode) {
validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
}
resolveDirectives(tView, lView, tNode, getConstant<string[]>(tViewConsts, localRefsIndex));
if (tNode.attrs !== null) {
computeStaticStyling(tNode, tNode.attrs, false);
@@ -85,11 +81,16 @@ export function ɵɵelementStart(
ngDevMode && assertIndexInRange(lView, adjustedIndex);
const renderer = lView[RENDERER];
const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace());
const tNode = tView.firstCreatePass ?
elementStartFirstCreatePass(
adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex) :
tView.data[adjustedIndex] as TElementNode;
const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace());
const hasDirectives = isDirectiveHost(tNode);
if (ngDevMode && tView.firstCreatePass) {
validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
}
setCurrentTNode(tNode, true);
setupStaticAttributes(renderer, native, tNode);
@@ -107,8 +108,7 @@ export function ɵɵelementStart(
}
increaseElementDepthCount();
if (isDirectiveHost(tNode)) {
if (hasDirectives) {
createDirectivesInstances(tView, lView, tNode);
executeContentQueries(tView, tNode, lView);
}
@@ -986,12 +986,11 @@ export function setNgReflectProperties(
*/
export function resolveDirectives(
tView: TView, lView: LView, tNode: TElementNode|TContainerNode|TElementContainerNode,
localRefs: string[]|null): boolean {
localRefs: string[]|null): void {
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in
// tsickle.
ngDevMode && assertFirstCreatePass(tView);
let hasDirectives = false;
if (getBindingsEnabled()) {
const exportsMap: ({[key: string]: number}|null) = localRefs === null ? null : {'': -1};
const matchResult = findDirectiveDefMatches(tView, tNode);
@@ -1005,14 +1004,12 @@ export function resolveDirectives(
}
if (directiveDefs !== null) {
hasDirectives = true;
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
}
if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap);
}
// Merge the template attrs last so that they have the highest priority.
tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs);
return hasDirectives;
}
/** Initializes the data structures necessary for a list of directives to be instantiated. */