From 3d5a919ac5c10194d6467b9d32b8985406b941ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Thu, 24 Jan 2019 23:50:12 +0000 Subject: [PATCH] refactor(ivy): clean up TNode not depending on LView (#28354) PR Close #28354 --- packages/core/src/render3/component_ref.ts | 6 +-- packages/core/src/render3/instructions.ts | 50 +++++++++++-------- .../bundling/todo/bundle.golden_symbols.json | 6 +-- .../render3/node_selector_matcher_spec.ts | 7 ++- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index a34b15181e..354c59f668 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -25,11 +25,11 @@ import {assertComponentType} from './assert'; import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component'; import {getComponentDef} from './definition'; import {NodeInjector} from './di'; -import {addToViewTree, createLView, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; +import {addToViewTree, assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node'; import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; -import {HEADER_OFFSET, LView, LViewFlags, RootContext} from './interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {enterView, leaveView} from './state'; import {defaultScheduler, getTNode} from './util'; import {createElementRef} from './view_engine_compatibility'; @@ -242,7 +242,7 @@ export class ComponentRef extends viewEngine_ComponentRef { super(); this.instance = instance; this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView); - this.hostView._tViewNode = createViewNode(-1, _rootLView); + this.hostView._tViewNode = assignTViewNodeToLView(_rootLView[TVIEW], null, -1, _rootLView); this.componentType = componentType; } diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index fd5df44544..f7bdef173c 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -205,17 +205,24 @@ export function createNodeAtIndex( assertLessThan(adjustedIndex, lView.length, `Slot should have been initialized with null`); lView[adjustedIndex] = native; + const previousOrParentTNode = getPreviousOrParentTNode(); + const isParent = getIsParent(); let tNode = tView.data[adjustedIndex] as TNode; if (tNode == null) { - // TODO(misko): Refactor createTNode so that it does not depend on LView. - tNode = tView.data[adjustedIndex] = createTNode(lView, type, adjustedIndex, name, attrs, null); + const parent = + isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; + + // Parents cannot cross component boundaries because components will be used in multiple places, + // so it's only set if the view is the same. + const parentInSameView = parent && parent !== lView[HOST_NODE]; + const tParentNode = parentInSameView ? parent as TElementNode | TContainerNode : null; + + tNode = tView.data[adjustedIndex] = createTNode(tParentNode, type, adjustedIndex, name, attrs); } // Now link ourselves into the tree. // We need this even if tNode exists, otherwise we might end up pointing to unexisting tNodes when // we use i18n (especially with ICU expressions that update the DOM during the update phase). - const previousOrParentTNode = getPreviousOrParentTNode(); - const isParent = getIsParent(); if (previousOrParentTNode) { if (isParent && previousOrParentTNode.child == null && (tNode.parent !== null || previousOrParentTNode.type === TNodeType.View)) { @@ -236,14 +243,20 @@ export function createNodeAtIndex( TProjectionNode & TIcuContainerNode; } -export function createViewNode(index: number, view: LView) { +export function assignTViewNodeToLView( + tView: TView, tParentNode: TNode | null, index: number, lView: LView): TViewNode { // View nodes are not stored in data because they can be added / removed at runtime (which // would cause indices to change). Their TNodes are instead stored in tView.node. - if (view[TVIEW].node == null) { - view[TVIEW].node = createTNode(view, TNodeType.View, index, null, null, null) as TViewNode; + let tNode = tView.node; + if (tNode == null) { + ngDevMode && tParentNode && + assertNodeOfPossibleTypes(tParentNode, TNodeType.Element, TNodeType.Container); + tView.node = tNode = createTNode( + tParentNode as TElementNode | TContainerNode | null, // + TNodeType.View, index, null, null) as TViewNode; } - return view[HOST_NODE] = view[TVIEW].node as TViewNode; + return lView[HOST_NODE] = tNode as TViewNode; } @@ -323,7 +336,7 @@ export function createEmbeddedViewAndNode( if (queries) { lView[QUERIES] = queries.createView(); } - createViewNode(-1, lView); + assignTViewNodeToLView(tView, null, -1, lView); if (tView.firstTemplatePass) { tView.node !.injectorIndex = injectorIndex; @@ -1221,18 +1234,9 @@ function savePropertyDebugData( * @returns the TNode object */ export function createTNode( - lView: LView, type: TNodeType, adjustedIndex: number, tagName: string | null, - attrs: TAttributes | null, tViews: TView[] | null): TNode { - const previousOrParentTNode = getPreviousOrParentTNode(); + tParent: TElementNode | TContainerNode | null, type: TNodeType, adjustedIndex: number, + tagName: string | null, attrs: TAttributes | null): TNode { ngDevMode && ngDevMode.tNode++; - const parent = - getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; - - // Parents cannot cross component boundaries because components will be used in multiple places, - // so it's only set if the view is the same. - const parentInSameView = parent && lView && parent !== lView[HOST_NODE]; - const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null; - return { type: type, index: adjustedIndex, @@ -1249,7 +1253,7 @@ export function createTNode( initialInputs: undefined, inputs: undefined, outputs: undefined, - tViews: tViews, + tViews: null, next: null, child: null, parent: tParent, @@ -2286,7 +2290,9 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num viewToRender[QUERIES] = lContainer[QUERIES] !.createView(); } - createViewNode(viewBlockId, viewToRender); + const tParentNode = getIsParent() ? previousOrParentTNode : + previousOrParentTNode && previousOrParentTNode.parent; + assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender); enterView(viewToRender, viewToRender[TVIEW].node); } if (lContainer) { diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index f22de17b05..d8f9477e9e 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -380,6 +380,9 @@ { "name": "assertTemplate" }, + { + "name": "assignTViewNodeToLView" + }, { "name": "attachPatchData" }, @@ -482,9 +485,6 @@ { "name": "createViewBlueprint" }, - { - "name": "createViewNode" - }, { "name": "decreaseElementDepthCount" }, diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index 822dcca3ac..9a62268fd1 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -12,17 +12,16 @@ import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} f import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher'; import {initializeStaticContext} from '../../src/render3/styling/class_and_style_bindings'; import {createTNode} from '@angular/core/src/render3/instructions'; -import {getLView} from '@angular/core/src/render3/state'; function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { - return createTNode(getLView(), TNodeType.Element, 0, tagName, attrs, null); + return createTNode(null, TNodeType.Element, 0, tagName, attrs); } describe('css selector matching', () => { function isMatching( tagName: string, attrsOrTNode: TAttributes | TNode | null, selector: CssSelector): boolean { const tNode = (!attrsOrTNode || Array.isArray(attrsOrTNode)) ? - createTNode(getLView(), TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes, null) : + createTNode(null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) : (attrsOrTNode as TNode); return isNodeMatchingSelector(tNode, selector, false); } @@ -307,7 +306,7 @@ describe('css selector matching', () => { () => { // selector: 'div.abc' const selector = ['div', SelectorFlags.CLASS, 'abc']; - const tNode = createTNode(getLView(), TNodeType.Element, 0, 'div', [], null); + const tNode = createTNode(null, TNodeType.Element, 0, 'div', []); //
(without attrs or styling context) expect(isMatching('div', tNode, selector)).toBeFalsy();