perf(ivy): attempt rendering initial styling only if present (#32979)
PR Close #32979
This commit is contained in:
parent
e6881b5b42
commit
60047037a3
|
@ -152,10 +152,6 @@ export function getOrCreateNodeInjectorForNode(
|
||||||
insertBloom(tView.data, tNode); // foundation for node bloom
|
insertBloom(tView.data, tNode); // foundation for node bloom
|
||||||
insertBloom(hostView, null); // foundation for cumulative bloom
|
insertBloom(hostView, null); // foundation for cumulative bloom
|
||||||
insertBloom(tView.blueprint, null);
|
insertBloom(tView.blueprint, null);
|
||||||
|
|
||||||
ngDevMode && assertEqual(
|
|
||||||
tNode.flags === 0 || tNode.flags === TNodeFlags.isComponentHost, true,
|
|
||||||
'expected tNode.flags to not be initialized');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentLoc = getParentInjectorLocation(tNode, hostView);
|
const parentLoc = getParentInjectorLocation(tNode, hostView);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {assertDataInRange, assertDefined, assertEqual} from '../../util/assert';
|
||||||
import {assertHasParent} from '../assert';
|
import {assertHasParent} from '../assert';
|
||||||
import {attachPatchData} from '../context_discovery';
|
import {attachPatchData} from '../context_discovery';
|
||||||
import {registerPostOrderHooks} from '../hooks';
|
import {registerPostOrderHooks} from '../hooks';
|
||||||
import {TAttributes, TNodeType} from '../interfaces/node';
|
import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||||
import {RElement} from '../interfaces/renderer';
|
import {RElement} from '../interfaces/renderer';
|
||||||
import {StylingMapArray, TStylingContext} from '../interfaces/styling';
|
import {StylingMapArray, TStylingContext} from '../interfaces/styling';
|
||||||
import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks';
|
import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks';
|
||||||
|
@ -64,7 +64,9 @@ export function ɵɵelementStart(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((tNode.flags & TNodeFlags.hasInitialStyling) === TNodeFlags.hasInitialStyling) {
|
||||||
renderInitialStyling(renderer, native, tNode);
|
renderInitialStyling(renderer, native, tNode);
|
||||||
|
}
|
||||||
|
|
||||||
appendChild(native, tNode, lView);
|
appendChild(native, tNode, lView);
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,7 @@ export const TNodeConstructor = class TNode implements ITNode {
|
||||||
if (this.flags & TNodeFlags.hasClassInput) flags.push('TNodeFlags.hasClassInput');
|
if (this.flags & TNodeFlags.hasClassInput) flags.push('TNodeFlags.hasClassInput');
|
||||||
if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery');
|
if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery');
|
||||||
if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput');
|
if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput');
|
||||||
|
if (this.flags & TNodeFlags.hasInitialStyling) flags.push('TNodeFlags.hasInitialStyling');
|
||||||
if (this.flags & TNodeFlags.isComponentHost) flags.push('TNodeFlags.isComponentHost');
|
if (this.flags & TNodeFlags.isComponentHost) flags.push('TNodeFlags.isComponentHost');
|
||||||
if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost');
|
if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost');
|
||||||
if (this.flags & TNodeFlags.isDetached) flags.push('TNodeFlags.isDetached');
|
if (this.flags & TNodeFlags.isDetached) flags.push('TNodeFlags.isDetached');
|
||||||
|
|
|
@ -1232,7 +1232,7 @@ function findDirectiveMatches(
|
||||||
*/
|
*/
|
||||||
export function markAsComponentHost(tView: TView, hostTNode: TNode): void {
|
export function markAsComponentHost(tView: TView, hostTNode: TNode): void {
|
||||||
ngDevMode && assertFirstTemplatePass(tView);
|
ngDevMode && assertFirstTemplatePass(tView);
|
||||||
hostTNode.flags = TNodeFlags.isComponentHost;
|
hostTNode.flags |= TNodeFlags.isComponentHost;
|
||||||
(tView.components || (tView.components = ngDevMode ? new TViewComponents() : [
|
(tView.components || (tView.components = ngDevMode ? new TViewComponents() : [
|
||||||
])).push(hostTNode.index);
|
])).push(hostTNode.index);
|
||||||
}
|
}
|
||||||
|
@ -1279,16 +1279,11 @@ function saveNameToExportMap(
|
||||||
* @param index the initial index
|
* @param index the initial index
|
||||||
*/
|
*/
|
||||||
export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) {
|
export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) {
|
||||||
const flags = tNode.flags;
|
|
||||||
ngDevMode && assertEqual(
|
|
||||||
flags === 0 || flags === TNodeFlags.isComponentHost, true,
|
|
||||||
'expected node flags to not be initialized');
|
|
||||||
|
|
||||||
ngDevMode && assertNotEqual(
|
ngDevMode && assertNotEqual(
|
||||||
numberOfDirectives, tNode.directiveEnd - tNode.directiveStart,
|
numberOfDirectives, tNode.directiveEnd - tNode.directiveStart,
|
||||||
'Reached the max number of directives');
|
'Reached the max number of directives');
|
||||||
|
tNode.flags |= TNodeFlags.isDirectiveHost;
|
||||||
// When the first directive is created on a node, save the index
|
// When the first directive is created on a node, save the index
|
||||||
tNode.flags = (flags & TNodeFlags.isComponentHost) | TNodeFlags.isDirectiveHost;
|
|
||||||
tNode.directiveStart = index;
|
tNode.directiveStart = index;
|
||||||
tNode.directiveEnd = index + numberOfDirectives;
|
tNode.directiveEnd = index + numberOfDirectives;
|
||||||
tNode.providerIndexes = index;
|
tNode.providerIndexes = index;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import {SafeValue} from '../../sanitization/bypass';
|
import {SafeValue} from '../../sanitization/bypass';
|
||||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||||
import {setInputsForProperty} from '../instructions/shared';
|
import {setInputsForProperty} from '../instructions/shared';
|
||||||
import {AttributeMarker, TAttributes, TNode, TNodeType} from '../interfaces/node';
|
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||||
import {RElement} from '../interfaces/renderer';
|
import {RElement} from '../interfaces/renderer';
|
||||||
import {StylingMapArray, StylingMapArrayIndex, TStylingContext} from '../interfaces/styling';
|
import {StylingMapArray, StylingMapArrayIndex, TStylingContext} from '../interfaces/styling';
|
||||||
import {BINDING_INDEX, LView, RENDERER} from '../interfaces/view';
|
import {BINDING_INDEX, LView, RENDERER} from '../interfaces/view';
|
||||||
|
@ -474,6 +474,10 @@ export function registerInitialStylingOnTNode(
|
||||||
updateRawValueOnContext(tNode.styles, stylingMapToString(styles, false));
|
updateRawValueOnContext(tNode.styles, stylingMapToString(styles, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasAdditionalInitialStyling) {
|
||||||
|
tNode.flags |= TNodeFlags.hasInitialStyling;
|
||||||
|
}
|
||||||
|
|
||||||
return hasAdditionalInitialStyling;
|
return hasAdditionalInitialStyling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,11 @@ export const enum TNodeFlags {
|
||||||
/** This bit is set if the node has any "style" inputs */
|
/** This bit is set if the node has any "style" inputs */
|
||||||
hasStyleInput = 0b00100000,
|
hasStyleInput = 0b00100000,
|
||||||
|
|
||||||
|
/** This bit is set if the node has initial styling */
|
||||||
|
hasInitialStyling = 0b01000000,
|
||||||
|
|
||||||
/** This bit is set if the node has been detached by i18n */
|
/** This bit is set if the node has been detached by i18n */
|
||||||
isDetached = 0b01000000,
|
isDetached = 0b10000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -113,6 +113,34 @@ describe('styling', () => {
|
||||||
expect(outer.textContent.trim()).toEqual('outer');
|
expect(outer.textContent.trim()).toEqual('outer');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render initial styling for repeated nodes that a component host', () => {
|
||||||
|
@Component({
|
||||||
|
selector: '[comp]',
|
||||||
|
template: '',
|
||||||
|
})
|
||||||
|
class Comp {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: `
|
||||||
|
<ng-template ngFor [ngForOf]="items" let-item>
|
||||||
|
<p comp class="a">A</p>
|
||||||
|
</ng-template>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class App {
|
||||||
|
items = [1, 2, 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [App, Comp],
|
||||||
|
});
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.debugElement.queryAll(By.css('.a')).length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('should do nothing for empty style bindings', () => {
|
it('should do nothing for empty style bindings', () => {
|
||||||
@Component({template: '<div [style.color]></div>'})
|
@Component({template: '<div [style.color]></div>'})
|
||||||
class App {
|
class App {
|
||||||
|
|
Loading…
Reference in New Issue