Skip to content

Commit

Permalink
feat(core): add renderer factory in render3 (angular#20855)
Browse files Browse the repository at this point in the history
PR Close angular#20855
  • Loading branch information
marclaval authored and IgorMinar committed Dec 22, 2017
1 parent 147aec4 commit d1de587
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 76 deletions.
4 changes: 2 additions & 2 deletions modules/benchmarks/src/largetable/iv/largetable.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion modules/benchmarks/src/largetable/render3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function noop() {}
export function main() {
let component: LargeTableComponent;
if (typeof window !== 'undefined') {
component = renderComponent<LargeTableComponent>(LargeTableComponent, {renderer: document});
component = renderComponent<LargeTableComponent>(LargeTableComponent);
bindAction('#createDom', () => createDom(component));
bindAction('#destroyDom', () => destroyDom(component));
bindAction('#updateDomProfile', profile(() => createDom(component), noop, 'update'));
Expand Down
10 changes: 5 additions & 5 deletions modules/benchmarks/src/largetable/render3/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

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

import {TableCell, buildTable, emptyTable} from '../util';
Expand All @@ -31,7 +31,7 @@ export class LargeTableComponent {
}
e();
}
rC(2);
cR(2);
{
for (let row of ctx.data) {
let cm1 = V(1);
Expand All @@ -42,7 +42,7 @@ export class LargeTableComponent {
c();
e();
}
rC(1);
cR(1);
{
for (let cell of row) {
let cm2 = V(2);
Expand All @@ -58,12 +58,12 @@ export class LargeTableComponent {
v();
}
}
rc();
cr();
}
v();
}
}
rc();
cr();
},
factory: () => new LargeTableComponent(),
inputs: {data: 'data'}
Expand Down
2 changes: 1 addition & 1 deletion modules/benchmarks/src/tree/render3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function noop() {}
export function main() {
let component: TreeComponent;
if (typeof window !== 'undefined') {
component = renderComponent(TreeComponent, {renderer: document});
component = renderComponent(TreeComponent);
bindAction('#createDom', () => createDom(component));
bindAction('#destroyDom', () => destroyDom(component));
bindAction('#detectChanges', () => detectChanges(component));
Expand Down
18 changes: 9 additions & 9 deletions modules/benchmarks/src/tree/render3/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

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';
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';
import {ComponentDef} from '@angular/core/src/render3/public_interfaces';

import {TreeNode, buildTree, emptyTree} from '../util';
Expand Down Expand Up @@ -50,7 +50,7 @@ export class TreeComponent {
}
s(0, 'background-color', b(ctx.data.depth % 2 ? '' : 'grey'));
t(1, b1(' ', ctx.data.value, ' '));
rC(2);
cR(2);
{
if (ctx.data.left != null) {
let cm0 = V(0);
Expand All @@ -66,8 +66,8 @@ export class TreeComponent {
v();
}
}
rc();
rC(3);
cr();
cR(3);
{
if (ctx.data.right != null) {
let cm0 = V(0);
Expand All @@ -83,7 +83,7 @@ export class TreeComponent {
v();
}
}
rc();
cr();
},
factory: () => new TreeComponent,
inputs: {data: 'data'}
Expand Down Expand Up @@ -118,22 +118,22 @@ export function TreeTpl(ctx: TreeNode, cm: boolean) {
}
s(0, 'background-color', b(ctx.depth % 2 ? '' : 'grey'));
t(1, b1(' ', ctx.value, ' '));
rC(2);
cR(2);
{
if (ctx.left != null) {
let cm0 = V(0);
{ TreeTpl(ctx.left, cm0); }
v();
}
}
rc();
rC(3);
cr();
cR(3);
{
if (ctx.right != null) {
let cm0 = V(0);
{ TreeTpl(ctx.right, cm0); }
v();
}
}
rc();
cr();
}
2 changes: 1 addition & 1 deletion modules/benchmarks/src/tree/render3_function/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function noop() {}
export function main() {
let component: TreeFunction;
if (typeof window !== 'undefined') {
component = renderComponent(TreeFunction, {renderer: document});
component = renderComponent(TreeFunction);
bindAction('#createDom', () => createDom(component));
bindAction('#destroyDom', () => destroyDom(component));
bindAction('#detectChanges', () => detectChanges(component));
Expand Down
28 changes: 11 additions & 17 deletions packages/core/src/render3/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import {ComponentRef, EmbeddedViewRef, Injector} from '../core';

import {assertNotNull} from './assert';
import {NG_HOST_SYMBOL, createError, createViewState, directive, elementHost, enterView, leaveView} from './instructions';
import {NG_HOST_SYMBOL, createError, createViewState, directive, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
import {LElement} from './l_node';
import {ComponentDef, ComponentType} from './public_interfaces';
import {RElement, Renderer3, RendererFactory3} from './renderer';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './renderer';
import {notImplemented, stringify} from './util';


Expand All @@ -22,10 +22,8 @@ import {notImplemented, stringify} from './util';
*/
export interface CreateComponentOptionArgs {
/**
* Which renderer to use.
* Which renderer factory to use.
*/
renderer?: Renderer3;

rendererFactory?: RendererFactory3;

/**
Expand Down Expand Up @@ -138,13 +136,16 @@ export const NULL_INJECTOR: Injector = {
*/
export function renderComponent<T>(
componentType: ComponentType<T>, opts: CreateComponentOptionArgs = {}): T {
const renderer = opts.renderer || document;
const rendererFactory = opts.rendererFactory || domRendererFactory3;
const componentDef = componentType.ngComponentDef;
let component: T;
const oldView = enterView(createViewState(-1, renderer, []), null);
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
const oldView = enterView(
createViewState(-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), []),
null !);
try {
// Create element node at index 0 in data array
elementHost(opts.host || componentDef.tag, componentDef);
hostElement(hostNode, componentDef);
// Create directive instance with n() and store at index 1 in data array (el is 0)
component = directive(1, componentDef.n(), componentDef);
} finally {
Expand All @@ -163,15 +164,8 @@ export function detectChanges<T>(component: T) {
createError('Not a directive instance', component);
}
ngDevMode && assertNotNull(hostNode.data, 'hostNode.data');
const oldView = enterView(hostNode.view !, hostNode);
try {
// Element was stored at 0 and directive was stored at 1 in renderComponent
// so to refresh the component, r() needs to be called with (1, 0)
(component.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
isDirty = false;
} finally {
leaveView(oldView);
}
renderComponentOrTemplate(hostNode, hostNode.view, component);
isDirty = false;
}

let isDirty = false;
Expand Down
66 changes: 54 additions & 12 deletions packages/core/src/render3/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import {NgStaticData, LNodeStatic, LContainerStatic, InitialInputData, InitialIn
import {assertNodeType} from './node_assert';
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
import {isNodeMatchingSelector} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, DirectiveDef} from './public_interfaces';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef} from './public_interfaces';
import {QueryList, QueryState_} from './query';
import {RComment, RElement, RText, Renderer3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
import {isDifferent, stringify} from './util';

export {queryRefresh} from './query';
Expand Down Expand Up @@ -73,6 +73,7 @@ let nextNgElementId = 0;
* Renderer2.
*/
let renderer: Renderer3;
let rendererFactory: RendererFactory3;

/** Used to set the parent property when nodes are created. */
let previousOrParentNode: LNode;
Expand Down Expand Up @@ -278,18 +279,44 @@ export function createLNode(
/**
*
* @param host Existing node to render into.
* @param renderer Renderer to use.
* @param template Template function with the instructions.
* @param context to pass into the template.
*/
export function renderTemplate<T>(host: LElement, template: ComponentTemplate<T>, context: T) {
export function renderTemplate<T>(
hostNode: RElement, template: ComponentTemplate<T>, context: T,
providedRendererFactory: RendererFactory3, host: LElement | null): LElement {
if (host == null) {
rendererFactory = providedRendererFactory;
host = createLNode(
null, LNodeFlags.Element, hostNode,
createViewState(-1, providedRendererFactory.createRenderer(null, null), []));
}
const hostView = host.data !;
ngDevMode && assertNotEqual(hostView, null, 'hostView');
hostView.ngStaticData = getTemplateStatic(template);
const oldView = enterView(hostView, host);
renderComponentOrTemplate(host, hostView, context, template);
return host;
}

export function renderComponentOrTemplate<T>(
node: LElement, viewState: ViewState, componentOrContext: T, template?: ComponentTemplate<T>) {
const oldView = enterView(viewState, node);
try {
template(context, creationMode);
if (rendererFactory.begin) {
rendererFactory.begin();
}
if (template) {
ngStaticData = template.ngStaticData || (template.ngStaticData = [] as never);
template(componentOrContext !, creationMode);
} else {
// Element was stored at 0 and directive was stored at 1 in renderComponent
// so to refresh the component, r() needs to be called with (1, 0)
(componentOrContext.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
}
} finally {
if (rendererFactory.end) {
rendererFactory.end();
}
leaveView(oldView);
}
}
Expand Down Expand Up @@ -406,7 +433,10 @@ export function elementStart(
let componentView: ViewState|null = null;
if (isHostElement) {
const ngStaticData = getTemplateStatic((nameOrComponentDef as ComponentDef<any>).template);
componentView = addToViewTree(createViewState(-1, renderer, ngStaticData));
componentView = addToViewTree(createViewState(
-1, rendererFactory.createRenderer(
native, (nameOrComponentDef as ComponentDef<any>).rendererType),
ngStaticData));
}

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


/**
* Used for bootstrapping existing nodes into rendering pipeline.
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
*
* @param elementOrSelector Render element or CSS selector to locate the element.
*/
export function elementHost(elementOrSelector: RElement | string, def: ComponentDef<any>) {
export function locateHostElement(
factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null {
ngDevMode && assertDataInRange(-1);
rendererFactory = factory;
const defaultRenderer = factory.createRenderer(null, null);
const rNode = typeof elementOrSelector === 'string' ?
((renderer as ProceduralRenderer3).selectRootElement ?
(renderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
(renderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
((defaultRenderer as ProceduralRenderer3).selectRootElement ?
(defaultRenderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
(defaultRenderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
elementOrSelector;
if (ngDevMode && !rNode) {
if (typeof elementOrSelector === 'string') {
Expand All @@ -471,6 +504,15 @@ export function elementHost(elementOrSelector: RElement | string, def: Component
throw createError('Host node is required:', elementOrSelector);
}
}
return rNode;
}

/**
* Creates the host LNode..
*
* @param rNode Render host element.
*/
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
createLNode(
0, LNodeFlags.Element, rNode, createViewState(-1, renderer, getTemplateStatic(def.template)));
}
Expand Down
13 changes: 11 additions & 2 deletions packages/core/src/render3/public_interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Type} from '../core';

import {RendererType2, Type} from '../core';
import {resolveRendererType2} from '../view/util';
import {componentRefresh, diPublic} from './instructions';


Expand Down Expand Up @@ -108,6 +108,13 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
* NOTE: only used with component directives.
*/
template: ComponentTemplate<T>;

/**
* Renderer type data of the component.
*
* NOTE: only used with component directives.
*/
rendererType: RendererType2|null;
}

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

export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
Expand Down Expand Up @@ -156,6 +164,7 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
inputs: invertObject(componentDefinition.inputs),
outputs: invertObject(componentDefinition.outputs),
methods: invertObject(componentDefinition.methods),
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
};
const feature = componentDefinition.features;
feature && feature.forEach((fn) => fn(def));
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/

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

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



Expand Down
Loading

0 comments on commit d1de587

Please sign in to comment.