Skip to content

Commit 1434ba9

Browse files
alxhubatscott
authored andcommitted
refactor(core): remove experimental Renderer3 abstraction (angular#46605)
This commit removes the `Renderer3` experiment which attempted to use the real DOM API as Angular's renderer. As shown in the diff, having this experiment around added real code complexity to Angular that could not be removed by an optimizer. Since we no longer feel this experiment is worth continuing, we're removing the `Renderer3` concept and all supporting code. PR Close angular#46605
1 parent af600cd commit 1434ba9

File tree

25 files changed

+149
-662
lines changed

25 files changed

+149
-662
lines changed

goldens/size-tracking/aio-payloads.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
"aio-local": {
1313
"uncompressed": {
1414
"runtime": 4325,
15-
"main": 456957,
15+
"main": 455915,
1616
"polyfills": 33922,
1717
"styles": 72616,
1818
"light-theme": 78276,
1919
"dark-theme": 78381
2020
}
2121
}
22-
}
22+
}

goldens/size-tracking/integration-payloads.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cli-hello-world": {
33
"uncompressed": {
44
"runtime": 1083,
5-
"main": 126542,
5+
"main": 125325,
66
"polyfills": 33824
77
}
88
},
@@ -19,43 +19,43 @@
1919
"cli-hello-world-ivy-compat": {
2020
"uncompressed": {
2121
"runtime": 1102,
22-
"main": 133416,
22+
"main": 132311,
2323
"polyfills": 33957
2424
}
2525
},
2626
"cli-hello-world-ivy-i18n": {
2727
"uncompressed": {
2828
"runtime": 926,
29-
"main": 125825,
29+
"main": 124982,
3030
"polyfills": 35252
3131
}
3232
},
3333
"cli-hello-world-lazy": {
3434
"uncompressed": {
3535
"runtime": 2835,
36-
"main": 237683,
36+
"main": 236657,
3737
"polyfills": 33842,
3838
"src_app_lazy_lazy_module_ts": 780
3939
}
4040
},
4141
"forms": {
4242
"uncompressed": {
4343
"runtime": 1063,
44-
"main": 158766,
44+
"main": 157479,
4545
"polyfills": 33804
4646
}
4747
},
4848
"animations": {
4949
"uncompressed": {
5050
"runtime": 1070,
51-
"main": 157739,
51+
"main": 157064,
5252
"polyfills": 33814
5353
}
5454
},
5555
"standalone-bootstrap": {
5656
"uncompressed": {
5757
"runtime": 1090,
58-
"main": 83707,
58+
"main": 83013,
5959
"polyfills": 33945
6060
}
6161
},
@@ -68,4 +68,4 @@
6868
"bundle": 1214857
6969
}
7070
}
71-
}
71+
}

packages/core/src/debug/debug_node.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,7 @@ function _queryNodeChildren(
477477
// Renderer2, however that's not the case in Ivy. This approach is being used because:
478478
// 1. Matching the ViewEngine behavior would mean potentially introducing a depedency
479479
// from `Renderer2` to Ivy which could bring Ivy code into ViewEngine.
480-
// 2. We would have to make `Renderer3` "know" about debug nodes.
481-
// 3. It allows us to capture nodes that were inserted directly via the DOM.
480+
// 2. It allows us to capture nodes that were inserted directly via the DOM.
482481
nativeNode && _queryNativeNodeDescendants(nativeNode, predicate, matches, elementsOnly);
483482
}
484483
// In all cases, if a dynamic container exists for this node, each view inside it has to be

packages/core/src/render/api.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
*/
88

99
import {InjectionToken} from '../di/injection_token';
10-
import {isProceduralRenderer} from '../render3/interfaces/renderer';
1110
import {isLView} from '../render3/interfaces/type_checks';
12-
import {LView, RENDERER} from '../render3/interfaces/view';
11+
import {RENDERER} from '../render3/interfaces/view';
1312
import {getCurrentTNode, getLView} from '../render3/state';
1413
import {getComponentLViewByIndex} from '../render3/util/view_utils';
1514

@@ -240,21 +239,12 @@ export abstract class Renderer2 {
240239
static __NG_ELEMENT_ID__: () => Renderer2 = () => injectRenderer2();
241240
}
242241

243-
/** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */
244-
function getOrCreateRenderer2(lView: LView): Renderer2 {
245-
const renderer = lView[RENDERER];
246-
if (ngDevMode && !isProceduralRenderer(renderer)) {
247-
throw new Error('Cannot inject Renderer2 when the application uses Renderer3!');
248-
}
249-
return renderer as Renderer2;
250-
}
251-
252242
/** Injects a Renderer2 for the current component. */
253243
export function injectRenderer2(): Renderer2 {
254244
// We need the Renderer to be based on the component that it's being injected into, however since
255245
// DI happens before we've entered its view, `getLView` will return the parent view instead.
256246
const lView = getLView();
257247
const tNode = getCurrentTNode()!;
258248
const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
259-
return getOrCreateRenderer2(isLView(nodeAtIndex) ? nodeAtIndex : lView);
249+
return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER] as Renderer2;
260250
}

packages/core/src/render3/STATUS.md

Lines changed: 0 additions & 276 deletions
This file was deleted.

packages/core/src/render3/component.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {addToViewTree, CLEAN_PROMISE, createLView, createTView, getOrCreateTComp
2222
import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition';
2323
import {TElementNode, TNodeType} from './interfaces/node';
2424
import {PlayerHandler} from './interfaces/player';
25-
import {domRendererFactory3, enableRenderer3, Renderer3, RendererFactory} from './interfaces/renderer';
25+
import {Renderer, RendererFactory} from './interfaces/renderer';
2626
import {RElement} from './interfaces/renderer_dom';
2727
import {CONTEXT, HEADER_OFFSET, LView, LViewFlags, RootContext, RootContextFlags, TVIEW, TViewType} from './interfaces/view';
2828
import {writeDirectClass, writeDirectStyle} from './node_manipulation';
@@ -115,9 +115,7 @@ export function renderComponent<T>(
115115
ngDevMode && publishDefaultGlobalUtils();
116116
ngDevMode && assertComponentType(componentType);
117117

118-
enableRenderer3();
119-
120-
const rendererFactory = opts.rendererFactory || domRendererFactory3;
118+
const rendererFactory = opts.rendererFactory!;
121119
const sanitizer = opts.sanitizer || null;
122120
const componentDef = getComponentDef<T>(componentType)!;
123121
if (componentDef.type != componentType) (componentDef as {type: Type<any>}).type = componentType;
@@ -174,7 +172,7 @@ export function renderComponent<T>(
174172
*/
175173
export function createRootComponentView(
176174
rNode: RElement|null, def: ComponentDef<any>, rootView: LView, rendererFactory: RendererFactory,
177-
hostRenderer: Renderer3, sanitizer?: Sanitizer|null): LView {
175+
hostRenderer: Renderer, sanitizer?: Sanitizer|null): LView {
178176
const tView = rootView[TVIEW];
179177
const index = HEADER_OFFSET;
180178
ngDevMode && assertIndexInRange(rootView, index);

packages/core/src/render3/instructions/listener.ts

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import {assertIndexInRange} from '../../util/assert';
1111
import {isObservable} from '../../util/lang';
1212
import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
13-
import {GlobalTargetResolver, isProceduralRenderer, Renderer3} from '../interfaces/renderer';
13+
import {GlobalTargetResolver, Renderer} from '../interfaces/renderer';
1414
import {RElement} from '../interfaces/renderer_dom';
1515
import {isDirectiveHost} from '../interfaces/type_checks';
1616
import {CLEANUP, CONTEXT, LView, RENDERER, TView} from '../interfaces/view';
@@ -114,7 +114,7 @@ function findExistingListener(
114114
}
115115

116116
function listenerInternal(
117-
tView: TView, lView: LView<{}|null>, renderer: Renderer3, tNode: TNode, eventName: string,
117+
tView: TView, lView: LView<{}|null>, renderer: Renderer, tNode: TNode, eventName: string,
118118
listenerFn: (e?: any) => any, useCapture: boolean,
119119
eventTargetResolver?: GlobalTargetResolver): void {
120120
const isTNodeDirectiveHost = isDirectiveHost(tNode);
@@ -145,53 +145,45 @@ function listenerInternal(
145145

146146
// In order to match current behavior, native DOM event listeners must be added for all
147147
// events (including outputs).
148-
if (isProceduralRenderer(renderer)) {
149-
// There might be cases where multiple directives on the same element try to register an event
150-
// handler function for the same event. In this situation we want to avoid registration of
151-
// several native listeners as each registration would be intercepted by NgZone and
152-
// trigger change detection. This would mean that a single user action would result in several
153-
// change detections being invoked. To avoid this situation we want to have only one call to
154-
// native handler registration (for the same element and same type of event).
155-
//
156-
// In order to have just one native event handler in presence of multiple handler functions,
157-
// we just register a first handler function as a native event listener and then chain
158-
// (coalesce) other handler functions on top of the first native handler function.
159-
let existingListener = null;
160-
// Please note that the coalescing described here doesn't happen for events specifying an
161-
// alternative target (ex. (document:click)) - this is to keep backward compatibility with the
162-
// view engine.
163-
// Also, we don't have to search for existing listeners is there are no directives
164-
// matching on a given node as we can't register multiple event handlers for the same event in
165-
// a template (this would mean having duplicate attributes).
166-
if (!eventTargetResolver && isTNodeDirectiveHost) {
167-
existingListener = findExistingListener(tView, lView, eventName, tNode.index);
168-
}
169-
if (existingListener !== null) {
170-
// Attach a new listener to coalesced listeners list, maintaining the order in which
171-
// listeners are registered. For performance reasons, we keep a reference to the last
172-
// listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through
173-
// the entire set each time we need to add a new listener.
174-
const lastListenerFn = (<any>existingListener).__ngLastListenerFn__ || existingListener;
175-
lastListenerFn.__ngNextListenerFn__ = listenerFn;
176-
(<any>existingListener).__ngLastListenerFn__ = listenerFn;
177-
processOutputs = false;
178-
} else {
179-
listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
180-
const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn);
181-
ngDevMode && ngDevMode.rendererAddEventListener++;
182-
183-
lCleanup.push(listenerFn, cleanupFn);
184-
tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1);
185-
}
186148

149+
// There might be cases where multiple directives on the same element try to register an event
150+
// handler function for the same event. In this situation we want to avoid registration of
151+
// several native listeners as each registration would be intercepted by NgZone and
152+
// trigger change detection. This would mean that a single user action would result in several
153+
// change detections being invoked. To avoid this situation we want to have only one call to
154+
// native handler registration (for the same element and same type of event).
155+
//
156+
// In order to have just one native event handler in presence of multiple handler functions,
157+
// we just register a first handler function as a native event listener and then chain
158+
// (coalesce) other handler functions on top of the first native handler function.
159+
let existingListener = null;
160+
// Please note that the coalescing described here doesn't happen for events specifying an
161+
// alternative target (ex. (document:click)) - this is to keep backward compatibility with the
162+
// view engine.
163+
// Also, we don't have to search for existing listeners is there are no directives
164+
// matching on a given node as we can't register multiple event handlers for the same event in
165+
// a template (this would mean having duplicate attributes).
166+
if (!eventTargetResolver && isTNodeDirectiveHost) {
167+
existingListener = findExistingListener(tView, lView, eventName, tNode.index);
168+
}
169+
if (existingListener !== null) {
170+
// Attach a new listener to coalesced listeners list, maintaining the order in which
171+
// listeners are registered. For performance reasons, we keep a reference to the last
172+
// listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through
173+
// the entire set each time we need to add a new listener.
174+
const lastListenerFn = (<any>existingListener).__ngLastListenerFn__ || existingListener;
175+
lastListenerFn.__ngNextListenerFn__ = listenerFn;
176+
(<any>existingListener).__ngLastListenerFn__ = listenerFn;
177+
processOutputs = false;
187178
} else {
188-
listenerFn = wrapListener(tNode, lView, context, listenerFn, true /** preventDefault */);
189-
target.addEventListener(eventName, listenerFn, useCapture);
179+
listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
180+
const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn);
190181
ngDevMode && ngDevMode.rendererAddEventListener++;
191182

192-
lCleanup.push(listenerFn);
193-
tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCapture);
183+
lCleanup.push(listenerFn, cleanupFn);
184+
tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1);
194185
}
186+
195187
} else {
196188
// Even if there is no native listener to add, we still need to wrap the listener so that OnPush
197189
// ancestors are marked dirty when an event occurs.

packages/core/src/render3/instructions/lview_debug.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {NO_PARENT_INJECTOR, NodeInjectorOffset} from '../interfaces/injector';
2121
import {AttributeMarker, InsertBeforeIndex, PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, toTNodeTypeAsString} from '../interfaces/node';
2222
import {SelectorFlags} from '../interfaces/projection';
2323
import {LQueries, TQueries} from '../interfaces/query';
24-
import {Renderer3, RendererFactory} from '../interfaces/renderer';
24+
import {Renderer, RendererFactory} from '../interfaces/renderer';
2525
import {RComment, RElement, RNode} from '../interfaces/renderer_dom';
2626
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
2727
import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DebugNode, DECLARATION_VIEW, DestroyHookData, FLAGS, HEADER_OFFSET, HookData, HOST, HostBindingOpCodes, ID, INJECTOR, LContainerDebug as ILContainerDebug, LView, LViewDebug as ILViewDebug, LViewDebugRange, LViewDebugRangeContent, LViewFlags, NEXT, NodeInjectorDebug, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, T_HOST, TData, TView as ITView, TVIEW, TView, TViewType, TViewTypeAsString} from '../interfaces/view';
@@ -489,7 +489,7 @@ export class LViewDebug<T = unknown> implements ILViewDebug<T> {
489489
get rendererFactory(): RendererFactory {
490490
return this._raw_lView[RENDERER_FACTORY];
491491
}
492-
get renderer(): Renderer3 {
492+
get renderer(): Renderer {
493493
return this._raw_lView[RENDERER];
494494
}
495495
get sanitizer(): Sanitizer|null {

0 commit comments

Comments
 (0)