fix(ivy): avoid DOM element assertions if procedural renderer is used (#33156)
Prior to this commit, Ivy runtime asserted that a given element is an instance of a DOM node. These asserts may not be correct in case custom renderer is used, which operates objects with a shape different than DOM nodes. This commit updates the code to avoid the mentioned checks in case procedural renderer is used. PR Close #33156
This commit is contained in:
parent
ec6a9f2a02
commit
11e04b1892
|
@ -1463,8 +1463,8 @@ const LContainerArray: any = ((typeof ngDevMode === 'undefined' || ngDevMode) &&
|
||||||
export function createLContainer(
|
export function createLContainer(
|
||||||
hostNative: RElement | RComment | LView, currentView: LView, native: RComment, tNode: TNode,
|
hostNative: RElement | RComment | LView, currentView: LView, native: RComment, tNode: TNode,
|
||||||
isForViewContainerRef?: boolean): LContainer {
|
isForViewContainerRef?: boolean): LContainer {
|
||||||
ngDevMode && assertDomNode(native);
|
|
||||||
ngDevMode && assertLView(currentView);
|
ngDevMode && assertLView(currentView);
|
||||||
|
ngDevMode && !isProceduralRenderer(currentView[RENDERER]) && assertDomNode(native);
|
||||||
// https://jsperf.com/array-literal-vs-new-array-really
|
// https://jsperf.com/array-literal-vs-new-array-really
|
||||||
const lContainer: LContainer = new (ngDevMode ? LContainerArray : Array)(
|
const lContainer: LContainer = new (ngDevMode ? LContainerArray : Array)(
|
||||||
hostNative, // host native
|
hostNative, // host native
|
||||||
|
|
|
@ -93,7 +93,7 @@ function applyToElementOrContainer(
|
||||||
lNodeToHandle = lNodeToHandle[HOST] !;
|
lNodeToHandle = lNodeToHandle[HOST] !;
|
||||||
}
|
}
|
||||||
const rNode: RNode = unwrapRNode(lNodeToHandle);
|
const rNode: RNode = unwrapRNode(lNodeToHandle);
|
||||||
ngDevMode && assertDomNode(rNode);
|
ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode);
|
||||||
|
|
||||||
if (action === WalkTNodeTreeAction.Create && parent !== null) {
|
if (action === WalkTNodeTreeAction.Create && parent !== null) {
|
||||||
if (beforeNode == null) {
|
if (beforeNode == null) {
|
||||||
|
|
|
@ -11,9 +11,9 @@ import {assertTNodeForLView} from '../assert';
|
||||||
import {LContainer, TYPE} from '../interfaces/container';
|
import {LContainer, TYPE} from '../interfaces/container';
|
||||||
import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context';
|
import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context';
|
||||||
import {TNode} from '../interfaces/node';
|
import {TNode} from '../interfaces/node';
|
||||||
import {RNode} from '../interfaces/renderer';
|
import {RNode, isProceduralRenderer} from '../interfaces/renderer';
|
||||||
import {isLContainer, isLView} from '../interfaces/type_checks';
|
import {isLContainer, isLView} from '../interfaces/type_checks';
|
||||||
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, PREORDER_HOOK_FLAGS, TData, TVIEW} from '../interfaces/view';
|
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, PREORDER_HOOK_FLAGS, RENDERER, TData, TVIEW} from '../interfaces/view';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ export function getNativeByTNode(tNode: TNode, lView: LView): RNode {
|
||||||
ngDevMode && assertTNodeForLView(tNode, lView);
|
ngDevMode && assertTNodeForLView(tNode, lView);
|
||||||
ngDevMode && assertDataInRange(lView, tNode.index);
|
ngDevMode && assertDataInRange(lView, tNode.index);
|
||||||
const node: RNode = unwrapRNode(lView[tNode.index]);
|
const node: RNode = unwrapRNode(lView[tNode.index]);
|
||||||
ngDevMode && assertDomNode(node);
|
ngDevMode && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ export function getNativeByTNodeOrNull(tNode: TNode, lView: LView): RNode|null {
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
ngDevMode && assertTNodeForLView(tNode, lView);
|
ngDevMode && assertTNodeForLView(tNode, lView);
|
||||||
const node: RNode|null = unwrapRNode(lView[index]);
|
const node: RNode|null = unwrapRNode(lView[index]);
|
||||||
ngDevMode && node !== null && assertDomNode(node);
|
ngDevMode && node !== null && !isProceduralRenderer(lView[RENDERER]) && assertDomNode(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -198,3 +198,49 @@ function getAnimationRendererFactory2(document: any): RendererFactory2 {
|
||||||
document.body, new MockAnimationDriver(), new ɵNoopAnimationStyleNormalizer()),
|
document.body, new MockAnimationDriver(), new ɵNoopAnimationStyleNormalizer()),
|
||||||
fakeNgZone);
|
fakeNgZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('custom renderer', () => {
|
||||||
|
@Component({
|
||||||
|
selector: 'some-component',
|
||||||
|
template: `<div><span></span></div>`,
|
||||||
|
})
|
||||||
|
class SomeComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a patched renderer factory that creates elements with a shape different than DOM node
|
||||||
|
*/
|
||||||
|
function createPatchedRendererFactory(document: any) {
|
||||||
|
let rendererFactory = getRendererFactory2(document);
|
||||||
|
const origCreateRenderer = rendererFactory.createRenderer;
|
||||||
|
rendererFactory.createRenderer = function(element: any, type: RendererType2|null) {
|
||||||
|
const renderer = origCreateRenderer.call(this, element, type);
|
||||||
|
renderer.appendChild = () => {};
|
||||||
|
renderer.createElement = (name: string) => ({
|
||||||
|
name,
|
||||||
|
el: document.createElement(name),
|
||||||
|
});
|
||||||
|
return renderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
return rendererFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [SomeComponent],
|
||||||
|
providers: [{
|
||||||
|
provide: RendererFactory2,
|
||||||
|
useFactory: (document: any) => createPatchedRendererFactory(document),
|
||||||
|
deps: [DOCUMENT]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not trigger errors', () => {
|
||||||
|
expect(() => {
|
||||||
|
const fixture = TestBed.createComponent(SomeComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue