Skip to content

Commit d1de587

Browse files
marclavalIgorMinar
authored andcommitted
feat(core): add renderer factory in render3 (#20855)
PR Close #20855
1 parent 147aec4 commit d1de587

File tree

15 files changed

+342
-76
lines changed

15 files changed

+342
-76
lines changed

modules/benchmarks/src/largetable/iv/largetable.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

modules/benchmarks/src/largetable/render3/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function noop() {}
1717
export function main() {
1818
let component: LargeTableComponent;
1919
if (typeof window !== 'undefined') {
20-
component = renderComponent<LargeTableComponent>(LargeTableComponent, {renderer: document});
20+
component = renderComponent<LargeTableComponent>(LargeTableComponent);
2121
bindAction('#createDom', () => createDom(component));
2222
bindAction('#destroyDom', () => destroyDom(component));
2323
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));

modules/benchmarks/src/largetable/render3/table.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {C, E, T, V, b, c, defineComponent, detectChanges, e, rC, rc, s, t, v} from '@angular/core/src/render3/index';
9+
import {C, E, T, V, b, c, cR, cr, defineComponent, detectChanges, e, s, t, v} from '@angular/core/src/render3/index';
1010
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
1111

1212
import {TableCell, buildTable, emptyTable} from '../util';
@@ -31,7 +31,7 @@ export class LargeTableComponent {
3131
}
3232
e();
3333
}
34-
rC(2);
34+
cR(2);
3535
{
3636
for (let row of ctx.data) {
3737
let cm1 = V(1);
@@ -42,7 +42,7 @@ export class LargeTableComponent {
4242
c();
4343
e();
4444
}
45-
rC(1);
45+
cR(1);
4646
{
4747
for (let cell of row) {
4848
let cm2 = V(2);
@@ -58,12 +58,12 @@ export class LargeTableComponent {
5858
v();
5959
}
6060
}
61-
rc();
61+
cr();
6262
}
6363
v();
6464
}
6565
}
66-
rc();
66+
cr();
6767
},
6868
factory: () => new LargeTableComponent(),
6969
inputs: {data: 'data'}

modules/benchmarks/src/tree/render3/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function noop() {}
1515
export function main() {
1616
let component: TreeComponent;
1717
if (typeof window !== 'undefined') {
18-
component = renderComponent(TreeComponent, {renderer: document});
18+
component = renderComponent(TreeComponent);
1919
bindAction('#createDom', () => createDom(component));
2020
bindAction('#destroyDom', () => destroyDom(component));
2121
bindAction('#detectChanges', () => detectChanges(component));

modules/benchmarks/src/tree/render3/tree.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {C, D, E, T, V, b, b1, c, defineComponent, detectChanges as _detectChanges, e, p, rC, rc, s, t, v} from '@angular/core/src/render3/index';
9+
import {C, D, E, T, V, b, b1, c, cR, cr, defineComponent, detectChanges as _detectChanges, e, p, s, t, v} from '@angular/core/src/render3/index';
1010
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';
1111

1212
import {TreeNode, buildTree, emptyTree} from '../util';
@@ -50,7 +50,7 @@ export class TreeComponent {
5050
}
5151
s(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
5252
t(1, b1(' ', ctx.data.value, ' '));
53-
rC(2);
53+
cR(2);
5454
{
5555
if (ctx.data.left != null) {
5656
let cm0 = V(0);
@@ -66,8 +66,8 @@ export class TreeComponent {
6666
v();
6767
}
6868
}
69-
rc();
70-
rC(3);
69+
cr();
70+
cR(3);
7171
{
7272
if (ctx.data.right != null) {
7373
let cm0 = V(0);
@@ -83,7 +83,7 @@ export class TreeComponent {
8383
v();
8484
}
8585
}
86-
rc();
86+
cr();
8787
},
8888
factory: () => new TreeComponent,
8989
inputs: {data: 'data'}
@@ -118,22 +118,22 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
118118
}
119119
s(0, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
120120
t(1, b1(' ', ctx.value, ' '));
121-
rC(2);
121+
cR(2);
122122
{
123123
if (ctx.left != null) {
124124
let cm0 = V(0);
125125
{ TreeTpl(ctx.left, cm0); }
126126
v();
127127
}
128128
}
129-
rc();
130-
rC(3);
129+
cr();
130+
cR(3);
131131
{
132132
if (ctx.right != null) {
133133
let cm0 = V(0);
134134
{ TreeTpl(ctx.right, cm0); }
135135
v();
136136
}
137137
}
138-
rc();
138+
cr();
139139
}

modules/benchmarks/src/tree/render3_function/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function noop() {}
1515
export function main() {
1616
let component: TreeFunction;
1717
if (typeof window !== 'undefined') {
18-
component = renderComponent(TreeFunction, {renderer: document});
18+
component = renderComponent(TreeFunction);
1919
bindAction('#createDom', () => createDom(component));
2020
bindAction('#destroyDom', () => destroyDom(component));
2121
bindAction('#detectChanges', () => detectChanges(component));

packages/core/src/render3/component.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import {ComponentRef, EmbeddedViewRef, Injector} from '../core';
1010

1111
import {assertNotNull} from './assert';
12-
import {NG_HOST_SYMBOL, createError, createViewState, directive, elementHost, enterView, leaveView} from './instructions';
12+
import {NG_HOST_SYMBOL, createError, createViewState, directive, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
1313
import {LElement} from './l_node';
1414
import {ComponentDef, ComponentType} from './public_interfaces';
15-
import {RElement, Renderer3, RendererFactory3} from './renderer';
15+
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './renderer';
1616
import {notImplemented, stringify} from './util';
1717

1818

@@ -22,10 +22,8 @@ import {notImplemented, stringify} from './util';
2222
*/
2323
export interface CreateComponentOptionArgs {
2424
/**
25-
* Which renderer to use.
25+
* Which renderer factory to use.
2626
*/
27-
renderer?: Renderer3;
28-
2927
rendererFactory?: RendererFactory3;
3028

3129
/**
@@ -138,13 +136,16 @@ export const NULL_INJECTOR: Injector = {
138136
*/
139137
export function renderComponent<T>(
140138
componentType: ComponentType<T>, opts: CreateComponentOptionArgs = {}): T {
141-
const renderer = opts.renderer || document;
139+
const rendererFactory = opts.rendererFactory || domRendererFactory3;
142140
const componentDef = componentType.ngComponentDef;
143141
let component: T;
144-
const oldView = enterView(createViewState(-1, renderer, []), null);
142+
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
143+
const oldView = enterView(
144+
createViewState(-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), []),
145+
null !);
145146
try {
146147
// Create element node at index 0 in data array
147-
elementHost(opts.host || componentDef.tag, componentDef);
148+
hostElement(hostNode, componentDef);
148149
// Create directive instance with n() and store at index 1 in data array (el is 0)
149150
component = directive(1, componentDef.n(), componentDef);
150151
} finally {
@@ -163,15 +164,8 @@ export function detectChanges<T>(component: T) {
163164
createError('Not a directive instance', component);
164165
}
165166
ngDevMode && assertNotNull(hostNode.data, 'hostNode.data');
166-
const oldView = enterView(hostNode.view !, hostNode);
167-
try {
168-
// Element was stored at 0 and directive was stored at 1 in renderComponent
169-
// so to refresh the component, r() needs to be called with (1, 0)
170-
(component.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
171-
isDirty = false;
172-
} finally {
173-
leaveView(oldView);
174-
}
167+
renderComponentOrTemplate(hostNode, hostNode.view, component);
168+
isDirty = false;
175169
}
176170

177171
let isDirty = false;

packages/core/src/render3/instructions.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import {NgStaticData, LNodeStatic, LContainerStatic, InitialInputData, InitialIn
1818
import {assertNodeType} from './node_assert';
1919
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
2020
import {isNodeMatchingSelector} from './node_selector_matcher';
21-
import {ComponentDef, ComponentTemplate, DirectiveDef} from './public_interfaces';
21+
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef} from './public_interfaces';
2222
import {QueryList, QueryState_} from './query';
23-
import {RComment, RElement, RText, Renderer3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
23+
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
2424
import {isDifferent, stringify} from './util';
2525

2626
export {queryRefresh} from './query';
@@ -73,6 +73,7 @@ let nextNgElementId = 0;
7373
* Renderer2.
7474
*/
7575
let renderer: Renderer3;
76+
let rendererFactory: RendererFactory3;
7677

7778
/** Used to set the parent property when nodes are created. */
7879
let previousOrParentNode: LNode;
@@ -278,18 +279,44 @@ export function createLNode(
278279
/**
279280
*
280281
* @param host Existing node to render into.
281-
* @param renderer Renderer to use.
282282
* @param template Template function with the instructions.
283283
* @param context to pass into the template.
284284
*/
285-
export function renderTemplate<T>(host: LElement, template: ComponentTemplate<T>, context: T) {
285+
export function renderTemplate<T>(
286+
hostNode: RElement, template: ComponentTemplate<T>, context: T,
287+
providedRendererFactory: RendererFactory3, host: LElement | null): LElement {
288+
if (host == null) {
289+
rendererFactory = providedRendererFactory;
290+
host = createLNode(
291+
null, LNodeFlags.Element, hostNode,
292+
createViewState(-1, providedRendererFactory.createRenderer(null, null), []));
293+
}
286294
const hostView = host.data !;
287295
ngDevMode && assertNotEqual(hostView, null, 'hostView');
288296
hostView.ngStaticData = getTemplateStatic(template);
289-
const oldView = enterView(hostView, host);
297+
renderComponentOrTemplate(host, hostView, context, template);
298+
return host;
299+
}
300+
301+
export function renderComponentOrTemplate<T>(
302+
node: LElement, viewState: ViewState, componentOrContext: T, template?: ComponentTemplate<T>) {
303+
const oldView = enterView(viewState, node);
290304
try {
291-
template(context, creationMode);
305+
if (rendererFactory.begin) {
306+
rendererFactory.begin();
307+
}
308+
if (template) {
309+
ngStaticData = template.ngStaticData || (template.ngStaticData = [] as never);
310+
template(componentOrContext !, creationMode);
311+
} else {
312+
// Element was stored at 0 and directive was stored at 1 in renderComponent
313+
// so to refresh the component, r() needs to be called with (1, 0)
314+
(componentOrContext.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
315+
}
292316
} finally {
317+
if (rendererFactory.end) {
318+
rendererFactory.end();
319+
}
293320
leaveView(oldView);
294321
}
295322
}
@@ -406,7 +433,10 @@ export function elementStart(
406433
let componentView: ViewState|null = null;
407434
if (isHostElement) {
408435
const ngStaticData = getTemplateStatic((nameOrComponentDef as ComponentDef<any>).template);
409-
componentView = addToViewTree(createViewState(-1, renderer, ngStaticData));
436+
componentView = addToViewTree(createViewState(
437+
-1, rendererFactory.createRenderer(
438+
native, (nameOrComponentDef as ComponentDef<any>).rendererType),
439+
ngStaticData));
410440
}
411441

412442
// Only component views should be added to the view tree directly. Embedded views are
@@ -453,16 +483,19 @@ export function createError(text: string, token: any) {
453483

454484

455485
/**
456-
* Used for bootstrapping existing nodes into rendering pipeline.
486+
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
457487
*
458488
* @param elementOrSelector Render element or CSS selector to locate the element.
459489
*/
460-
export function elementHost(elementOrSelector: RElement | string, def: ComponentDef<any>) {
490+
export function locateHostElement(
491+
factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null {
461492
ngDevMode && assertDataInRange(-1);
493+
rendererFactory = factory;
494+
const defaultRenderer = factory.createRenderer(null, null);
462495
const rNode = typeof elementOrSelector === 'string' ?
463-
((renderer as ProceduralRenderer3).selectRootElement ?
464-
(renderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
465-
(renderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
496+
((defaultRenderer as ProceduralRenderer3).selectRootElement ?
497+
(defaultRenderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
498+
(defaultRenderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
466499
elementOrSelector;
467500
if (ngDevMode && !rNode) {
468501
if (typeof elementOrSelector === 'string') {
@@ -471,6 +504,15 @@ export function elementHost(elementOrSelector: RElement | string, def: Component
471504
throw createError('Host node is required:', elementOrSelector);
472505
}
473506
}
507+
return rNode;
508+
}
509+
510+
/**
511+
* Creates the host LNode..
512+
*
513+
* @param rNode Render host element.
514+
*/
515+
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
474516
createLNode(
475517
0, LNodeFlags.Element, rNode, createViewState(-1, renderer, getTemplateStatic(def.template)));
476518
}

packages/core/src/render3/public_interfaces.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Type} from '../core';
10-
9+
import {RendererType2, Type} from '../core';
10+
import {resolveRendererType2} from '../view/util';
1111
import {componentRefresh, diPublic} from './instructions';
1212

1313

@@ -108,6 +108,13 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
108108
* NOTE: only used with component directives.
109109
*/
110110
template: ComponentTemplate<T>;
111+
112+
/**
113+
* Renderer type data of the component.
114+
*
115+
* NOTE: only used with component directives.
116+
*/
117+
rendererType: RendererType2|null;
111118
}
112119

113120
export interface DirectiveDefArgs<T> {
@@ -125,6 +132,7 @@ export interface ComponentDefArgs<T> extends DirectiveDefArgs<T> {
125132
template: ComponentTemplate<T>;
126133
refresh?: (this: ComponentDef<T>, directiveIndex: number, elementIndex: number) => void;
127134
features?: ComponentDefFeature[];
135+
rendererType?: RendererType2;
128136
}
129137

130138
export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
@@ -156,6 +164,7 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
156164
inputs: invertObject(componentDefinition.inputs),
157165
outputs: invertObject(componentDefinition.outputs),
158166
methods: invertObject(componentDefinition.methods),
167+
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
159168
};
160169
const feature = componentDefinition.features;
161170
feature && feature.forEach((fn) => fn(def));

packages/core/src/render3/query.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {DirectiveDef} from '@angular/core/src/render3/public_interfaces';
109
import {Observable} from 'rxjs/Observable';
1110

1211
import * as viewEngine from '../core';
@@ -15,6 +14,7 @@ import {assertNotNull} from './assert';
1514
import {injectElementRefForNode} from './di';
1615
import {QueryState} from './interfaces';
1716
import {LContainer, LElement, LNode, LNodeFlags, LView} from './l_node';
17+
import {DirectiveDef} from './public_interfaces';
1818

1919

2020

0 commit comments

Comments
 (0)