refactor(ivy): ensure hello world doesn't pull in context discovery creation code (#25895)

PR Close #25895
This commit is contained in:
Matias Niemelä 2018-09-10 11:22:35 -07:00
parent 8dc2b119fb
commit 10a656fc38
7 changed files with 49 additions and 67 deletions

View File

@ -133,7 +133,7 @@ export function renderComponent<T>(
executeInitAndContentHooks(); executeInitAndContentHooks();
setHostBindings(rootView[TVIEW].hostBindings); setHostBindings(rootView[TVIEW].hostBindings);
detectChangesInternal(elementNode.data as LViewData, elementNode, component); detectChangesInternal(elementNode.data as LViewData, component);
} finally { } finally {
leaveView(oldView); leaveView(oldView);
if (rendererFactory.end) rendererFactory.end(); if (rendererFactory.end) rendererFactory.end();

View File

@ -185,10 +185,11 @@ export function getLElementNode(target: any): LElementNode|null {
return context ? getLNodeFromViewData(context.lViewData, context.lNodeIndex) : null; return context ? getLNodeFromViewData(context.lViewData, context.lNodeIndex) : null;
} }
export function getLElementFromRootComponent(componentInstance: {}): LElementNode|null { export function getLElementFromRootComponent(rootComponentInstance: {}): LElementNode|null {
// the host element for the root component is ALWAYS the first element // the host element for the root component is ALWAYS the first element
// in the lViewData array (which is where HEADER_OFFSET points to) // in the lViewData array (which is where HEADER_OFFSET points to)
return getLElementFromComponent(componentInstance, HEADER_OFFSET); const lViewData = readPatchedLViewData(rootComponentInstance) !;
return readElementValue(lViewData[HEADER_OFFSET]);
} }
/** /**
@ -198,15 +199,14 @@ export function getLElementFromRootComponent(componentInstance: {}): LElementNod
* that `getContext` has in the event that an Angular application doesn't need to have * that `getContext` has in the event that an Angular application doesn't need to have
* any programmatic access to an element's context (only change detection uses this function). * any programmatic access to an element's context (only change detection uses this function).
*/ */
export function getLElementFromComponent( export function getLElementFromComponent(componentInstance: {}): LElementNode|null {
componentInstance: {}, expectedLNodeIndex?: number): LElementNode|null {
let lViewData = readPatchedData(componentInstance); let lViewData = readPatchedData(componentInstance);
let lNode: LElementNode; let lNode: LElementNode;
if (Array.isArray(lViewData)) { if (Array.isArray(lViewData)) {
expectedLNodeIndex = expectedLNodeIndex || findViaComponent(lViewData, componentInstance); const lNodeIndex = findViaComponent(lViewData, componentInstance);
lNode = readElementValue(lViewData[expectedLNodeIndex]); lNode = readElementValue(lViewData[lNodeIndex]);
const context = createLContext(lViewData, expectedLNodeIndex, lNode.native); const context = createLContext(lViewData, lNodeIndex, lNode.native);
context.component = componentInstance; context.component = componentInstance;
attachPatchData(componentInstance, context); attachPatchData(componentInstance, context);
attachPatchData(context.native, context); attachPatchData(context.native, context);
@ -234,6 +234,14 @@ export function readPatchedData(target: any): LViewData|LContext|null {
return target[MONKEY_PATCH_KEY_NAME]; return target[MONKEY_PATCH_KEY_NAME];
} }
export function readPatchedLViewData(target: any): LViewData|null {
const value = readPatchedData(target);
if (value) {
return Array.isArray(value) ? value : (value as LContext).lViewData;
}
return null;
}
export function isComponentInstance(instance: any): boolean { export function isComponentInstance(instance: any): boolean {
return instance && instance.constructor && instance.constructor.ngComponentDef; return instance && instance.constructor && instance.constructor.ngComponentDef;
} }

View File

@ -13,7 +13,7 @@ import {Sanitizer} from '../sanitization/security';
import {StyleSanitizeFn} from '../sanitization/style_sanitizer'; import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotEqual} from './assert'; import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotEqual} from './assert';
import {attachPatchData, getLElementFromComponent, getLElementFromRootComponent} from './context_discovery'; import {attachPatchData, getLElementFromComponent, getLElementFromRootComponent, readPatchedData, readPatchedLViewData} from './context_discovery';
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors'; import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks'; import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container'; import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
@ -1769,6 +1769,9 @@ export function baseDirectiveCreate<T>(
ngDevMode && assertPreviousIsParent(); ngDevMode && assertPreviousIsParent();
attachPatchData(directive, viewData); attachPatchData(directive, viewData);
if (hostNode) {
attachPatchData(hostNode.native, viewData);
}
if (directives == null) viewData[DIRECTIVES] = directives = []; if (directives == null) viewData[DIRECTIVES] = directives = [];
@ -2175,7 +2178,7 @@ export function componentRefresh<T>(adjustedElementIndex: number): void {
// Only attached CheckAlways components or attached, dirty OnPush components should be checked // Only attached CheckAlways components or attached, dirty OnPush components should be checked
if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
detectChangesInternal(hostView, element, hostView[CONTEXT]); detectChangesInternal(hostView, hostView[CONTEXT]);
} }
} }
@ -2435,7 +2438,7 @@ export function tick<T>(component: T): void {
function tickRootContext(rootContext: RootContext) { function tickRootContext(rootContext: RootContext) {
for (let i = 0; i < rootContext.components.length; i++) { for (let i = 0; i < rootContext.components.length; i++) {
const rootComponent = rootContext.components[i]; const rootComponent = rootContext.components[i];
renderComponentOrTemplate(getRootView(rootComponent), rootComponent); renderComponentOrTemplate(readPatchedLViewData(rootComponent) !, rootComponent);
} }
} }
@ -2448,8 +2451,7 @@ function tickRootContext(rootContext: RootContext) {
export function getRootView(component: any): LViewData { export function getRootView(component: any): LViewData {
ngDevMode && assertDefined(component, 'component'); ngDevMode && assertDefined(component, 'component');
const lElementNode = _getComponentHostLElementNode(component); let lViewData = readPatchedLViewData(component) !;
let lViewData = lElementNode.view;
while (lViewData[PARENT]) { while (lViewData[PARENT]) {
lViewData = lViewData[PARENT] !; lViewData = lViewData[PARENT] !;
} }
@ -2470,11 +2472,10 @@ export function getRootView(component: any): LViewData {
* @param component The component which the change detection should be performed on. * @param component The component which the change detection should be performed on.
*/ */
export function detectChanges<T>(component: T): void { export function detectChanges<T>(component: T): void {
const hostNode = _getComponentHostLElementNode(component); const hostNode = getLElementFromComponent(component) !;
ngDevMode && ngDevMode &&
assertDefined( assertDefined(hostNode, 'Component host node should be attached to an LViewData instance.');
hostNode.data, 'Component host node should be attached to an LViewData instance.'); detectChangesInternal(hostNode.data !, component);
detectChangesInternal(hostNode.data as LViewData, hostNode, component);
} }
/** /**
@ -2521,8 +2522,7 @@ export function checkNoChangesInRootView(lViewData: LViewData): void {
} }
/** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */
export function detectChangesInternal<T>( export function detectChangesInternal<T>(hostView: LViewData, component: T) {
hostView: LViewData, hostNode: LElementNode, component: T) {
const hostTView = hostView[TVIEW]; const hostTView = hostView[TVIEW];
const oldView = enterView(hostView, null); const oldView = enterView(hostView, null);
const templateFn = hostTView.template !; const templateFn = hostTView.template !;
@ -2569,8 +2569,8 @@ function updateViewQuery<T>(viewQuery: ComponentQuery<{}>| null, component: T):
*/ */
export function markDirty<T>(component: T) { export function markDirty<T>(component: T) {
ngDevMode && assertDefined(component, 'component'); ngDevMode && assertDefined(component, 'component');
const lElementNode = _getComponentHostLElementNode(component); const lViewData = readPatchedLViewData(component) !;
markViewDirty(lElementNode.view); markViewDirty(lViewData);
} }
/////////////////////////////// ///////////////////////////////
@ -2881,11 +2881,9 @@ function assertDataNext(index: number, arr?: any[]) {
arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`); arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
} }
export function _getComponentHostLElementNode<T>( export function _getComponentHostLElementNode(component: any): LElementNode {
component: T, isRootComponent?: boolean): LElementNode {
ngDevMode && assertDefined(component, 'expecting component got null'); ngDevMode && assertDefined(component, 'expecting component got null');
const lElementNode = isRootComponent ? getLElementFromRootComponent(component) ! : const lElementNode = getLElementFromComponent(component) !;
getLElementFromComponent(component) !;
ngDevMode && assertDefined(component, 'object is not a component'); ngDevMode && assertDefined(component, 'object is not a component');
return lElementNode; return lElementNode;
} }

View File

@ -98,9 +98,6 @@
{ {
"name": "_CLEAN_PROMISE" "name": "_CLEAN_PROMISE"
}, },
{
"name": "_getComponentHostLElementNode"
},
{ {
"name": "_renderCompCount" "name": "_renderCompCount"
}, },
@ -137,9 +134,6 @@
{ {
"name": "componentRefresh" "name": "componentRefresh"
}, },
{
"name": "createLContext"
},
{ {
"name": "createLNode" "name": "createLNode"
}, },
@ -200,9 +194,6 @@
{ {
"name": "extractPipeDef" "name": "extractPipeDef"
}, },
{
"name": "findViaComponent"
},
{ {
"name": "firstTemplatePass" "name": "firstTemplatePass"
}, },
@ -218,12 +209,6 @@
{ {
"name": "getDirectiveDef" "name": "getDirectiveDef"
}, },
{
"name": "getLElementFromComponent"
},
{
"name": "getLElementFromRootComponent"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -251,9 +236,6 @@
{ {
"name": "getRenderParent" "name": "getRenderParent"
}, },
{
"name": "getRootView"
},
{ {
"name": "hostElement" "name": "hostElement"
}, },
@ -290,6 +272,9 @@
{ {
"name": "readPatchedData" "name": "readPatchedData"
}, },
{
"name": "readPatchedLViewData"
},
{ {
"name": "refreshChildComponents" "name": "refreshChildComponents"
}, },

View File

@ -314,9 +314,6 @@
{ {
"name": "_devMode" "name": "_devMode"
}, },
{
"name": "_getComponentHostLElementNode"
},
{ {
"name": "_global" "name": "_global"
}, },
@ -596,9 +593,6 @@
{ {
"name": "getLElementFromComponent" "name": "getLElementFromComponent"
}, },
{
"name": "getLElementFromRootComponent"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -671,9 +665,6 @@
{ {
"name": "getRendererFactory" "name": "getRendererFactory"
}, },
{
"name": "getRootView"
},
{ {
"name": "getStyleSanitizer" "name": "getStyleSanitizer"
}, },
@ -854,6 +845,9 @@
{ {
"name": "readPatchedData" "name": "readPatchedData"
}, },
{
"name": "readPatchedLViewData"
},
{ {
"name": "reference" "name": "reference"
}, },

View File

@ -1622,9 +1622,6 @@
{ {
"name": "getLElementFromComponent" "name": "getLElementFromComponent"
}, },
{
"name": "getLElementFromRootComponent"
},
{ {
"name": "getLViewChild" "name": "getLViewChild"
}, },
@ -1772,9 +1769,6 @@
{ {
"name": "getRendererFactory" "name": "getRendererFactory"
}, },
{
"name": "getRootView"
},
{ {
"name": "getStyleSanitizer" "name": "getStyleSanitizer"
}, },
@ -2174,6 +2168,9 @@
{ {
"name": "readPatchedData" "name": "readPatchedData"
}, },
{
"name": "readPatchedLViewData"
},
{ {
"name": "recursivelyProcessProviders" "name": "recursivelyProcessProviders"
}, },

View File

@ -1581,7 +1581,7 @@ describe('render3 integration test', () => {
const host = fixture.hostElement; const host = fixture.hostElement;
const child = host.querySelector('child-comp') as any; const child = host.querySelector('child-comp') as any;
expect(child[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
const [kid1, kid2, kid3] = Array.from(host.querySelectorAll('child-comp > *')); const [kid1, kid2, kid3] = Array.from(host.querySelectorAll('child-comp > *'));
expect(kid1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(kid1[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
@ -1859,7 +1859,7 @@ describe('render3 integration test', () => {
expect(textNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(textNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
expect(projectorComp[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); expect(projectorComp[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
expect(header[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(header[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
expect(h1[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); expect(h1[MONKEY_PATCH_KEY_NAME]).toBeFalsy();
expect(p[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(p[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
@ -1936,19 +1936,19 @@ describe('render3 integration test', () => {
const hostElm = fixture.hostElement; const hostElm = fixture.hostElement;
const component = fixture.component; const component = fixture.component;
const componentContext = (component as any)[MONKEY_PATCH_KEY_NAME]; const componentLViewData = (component as any)[MONKEY_PATCH_KEY_NAME];
expect(Array.isArray(componentContext)).toBeFalsy(); expect(Array.isArray(componentLViewData)).toBeTruthy();
const hostContext = (hostElm as any)[MONKEY_PATCH_KEY_NAME]; const hostLViewData = (hostElm as any)[MONKEY_PATCH_KEY_NAME];
expect(hostContext).toBe(componentContext); expect(hostLViewData).toBe(componentLViewData);
const context1 = getContext(hostElm) !; const context1 = getContext(hostElm) !;
expect(context1).toBe(hostContext); expect(context1.lViewData).toBe(hostLViewData);
expect(context1.native).toEqual(hostElm); expect(context1.native).toEqual(hostElm);
const context2 = getContext(component) !; const context2 = getContext(component) !;
expect(context2).toBe(context1); expect(context2).toBe(context1);
expect(context2).toBe(hostContext); expect(context2.lViewData).toBe(hostLViewData);
expect(context2.native).toEqual(hostElm); expect(context2.native).toEqual(hostElm);
}); });
@ -2183,7 +2183,7 @@ describe('render3 integration test', () => {
const host = fixture.hostElement; const host = fixture.hostElement;
const child = host.querySelector('child-comp') as any; const child = host.querySelector('child-comp') as any;
expect(child[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy();
const context = getContext(child) !; const context = getContext(child) !;
expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy();