diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index e99ee1c21e..a8de81aab5 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 13411, + "main": 13266, "polyfills": 45340 } } diff --git a/modules/benchmarks/src/tree/render3_function/index.ts b/modules/benchmarks/src/tree/render3_function/index.ts index 1401374bf0..b08ab298af 100644 --- a/modules/benchmarks/src/tree/render3_function/index.ts +++ b/modules/benchmarks/src/tree/render3_function/index.ts @@ -17,6 +17,9 @@ function noop() {} export class TreeFunction { data: TreeNode = emptyTree; + /** @nocollapse */ + static ngFactoryDef = () => new TreeFunction; + /** @nocollapse */ static ngComponentDef = ɵɵdefineComponent({ type: TreeFunction, @@ -27,7 +30,6 @@ export class TreeFunction { // bit of a hack TreeTpl(rf, ctx.data); }, - factory: () => new TreeFunction, inputs: {data: 'data'} }); } diff --git a/packages/common/src/common.ts b/packages/common/src/common.ts index 750a5ef48b..b5bffa3bdf 100644 --- a/packages/common/src/common.ts +++ b/packages/common/src/common.ts @@ -29,5 +29,5 @@ export {ViewportScroller, NullViewportScroller as ɵNullViewportScroller} from ' export {NgClassImplProvider__POST_R3__ as ɵNgClassImplProvider__POST_R3__, NgClassR2Impl as ɵNgClassR2Impl, NgClassImpl as ɵNgClassImpl} from './directives/ng_class_impl'; export {NgStyleImplProvider__POST_R3__ as ɵNgStyleImplProvider__POST_R3__, NgStyleR2Impl as ɵNgStyleR2Impl, NgStyleImpl as ɵNgStyleImpl} from './directives/ng_style_impl'; -export {ngStyleDirectiveDef__POST_R3__ as ɵngStyleDirectiveDef__POST_R3__} from './directives/ng_style'; -export {ngClassDirectiveDef__POST_R3__ as ɵngClassDirectiveDef__POST_R3__} from './directives/ng_class'; +export {ngStyleDirectiveDef__POST_R3__ as ɵngStyleDirectiveDef__POST_R3__, ngStyleFactoryDef__POST_R3__ as ɵngStyleFactoryDef__POST_R3__} from './directives/ng_style'; +export {ngClassDirectiveDef__POST_R3__ as ɵngClassDirectiveDef__POST_R3__, ngClassFactoryDef__POST_R3__ as ɵngClassFactoryDef__POST_R3__} from './directives/ng_class'; diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index 61f42cefd4..238a1a2c38 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -32,7 +32,6 @@ export const ngClassDirectiveDef__PRE_R3__ = undefined; export const ngClassDirectiveDef__POST_R3__ = ɵɵdefineDirective({ type: function() {} as any, selectors: null as any, - factory: () => {}, hostBindings: function(rf: ɵRenderFlags, ctx: any, elIndex: number) { if (rf & ɵRenderFlags.Create) { ɵɵallocHostVars(1); @@ -47,6 +46,10 @@ export const ngClassDirectiveDef__POST_R3__ = ɵɵdefineDirective({ export const ngClassDirectiveDef = ngClassDirectiveDef__PRE_R3__; +export const ngClassFactoryDef__PRE_R3__ = undefined; +export const ngClassFactoryDef__POST_R3__ = function() {}; +export const ngClassFactoryDef = ngClassFactoryDef__PRE_R3__; + /** * Serves as the base non-VE container for NgClass. * @@ -63,6 +66,7 @@ export const ngClassDirectiveDef = ngClassDirectiveDef__PRE_R3__; */ export class NgClassBase { static ngDirectiveDef: any = ngClassDirectiveDef; + static ngFactoryDef: any = ngClassFactoryDef; constructor(protected _delegate: NgClassImpl) {} diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index 95f0dc7540..710b73afb9 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -25,6 +25,7 @@ import {NgStyleImpl, NgStyleImplProvider} from './ng_style_impl'; // used when the VE is present export const ngStyleDirectiveDef__PRE_R3__ = undefined; +export const ngStyleFactoryDef__PRE_R3__ = undefined; // used when the VE is not present (note the directive will // never be instantiated normally because it is apart of a @@ -32,7 +33,6 @@ export const ngStyleDirectiveDef__PRE_R3__ = undefined; export const ngStyleDirectiveDef__POST_R3__ = ɵɵdefineDirective({ type: function() {} as any, selectors: null as any, - factory: () => {}, hostBindings: function(rf: ɵRenderFlags, ctx: any, elIndex: number) { if (rf & ɵRenderFlags.Create) { ɵɵstyling(); @@ -44,7 +44,10 @@ export const ngStyleDirectiveDef__POST_R3__ = ɵɵdefineDirective({ } }); +export const ngStyleFactoryDef__POST_R3__ = function() {}; + export const ngStyleDirectiveDef = ngStyleDirectiveDef__PRE_R3__; +export const ngStyleFactoryDef = ngStyleDirectiveDef__PRE_R3__; /** * Serves as the base non-VE container for NgStyle. @@ -62,6 +65,7 @@ export const ngStyleDirectiveDef = ngStyleDirectiveDef__PRE_R3__; */ export class NgStyleBase { static ngDirectiveDef: any = ngStyleDirectiveDef; + static ngFactory: any = ngStyleFactoryDef; constructor(protected _delegate: NgStyleImpl) {} diff --git a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts index 99cf6c95df..d436b7342d 100644 --- a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts @@ -119,7 +119,7 @@ runInEachFileSystem(() => { const typingsFile = result.find(f => f.path === _('/typings/file.d.ts')) !; expect(typingsFile.contents) .toContain( - 'foo(x: number): number;\n static ngDirectiveDef: ɵngcc0.ɵɵDirectiveDefWithMeta'); + 'foo(x: number): number;\n static ngFactoryDef: ɵngcc0.ɵɵFactoryDef;\n static ngDirectiveDef: ɵngcc0.ɵɵDirectiveDefWithMeta'); }); it('should render imports into typings files', () => { diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts index a88d2689ea..5bfac8a122 100644 --- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts @@ -188,8 +188,8 @@ runInEachFileSystem(() => { decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy; expect(addDefinitionsSpy.calls.first().args[2]) - .toEqual( - `A.ngComponentDef = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], factory: function A_Factory(t) { return new (t || A)(); }, consts: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) { + .toEqual(`A.ngFactoryDef = function A_Factory(t) { return new (t || A)(); }; +A.ngComponentDef = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], consts: 1, vars: 1, template: function A_Template(rf, ctx) { if (rf & 1) { ɵngcc0.ɵɵtext(0); } if (rf & 2) { ɵngcc0.ɵɵtextInterpolate(ctx.person.name); @@ -227,9 +227,10 @@ runInEachFileSystem(() => { name: 'A', decorators: [jasmine.objectContaining({name: 'Directive'})] })); + expect(addDefinitionsSpy.calls.first().args[2]) - .toEqual( - `A.ngDirectiveDef = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } }); + .toEqual(`A.ngFactoryDef = function A_Factory(t) { return new (t || A)(); }; +A.ngDirectiveDef = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] }); /*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{ type: Directive, args: [{ selector: '[a]' }] diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 2b7ba63c5a..091c0f20fe 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -26,6 +26,7 @@ import {tsSourceMapBug29300Fixed} from '../../util/src/ts_source_map_bug_29300'; import {ResourceLoader} from './api'; import {extractDirectiveMetadata, parseFieldArrayValue} from './directive'; +import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, unwrapExpression} from './util'; @@ -517,18 +518,21 @@ export class ComponentDecoratorHandler implements } compile(node: ClassDeclaration, analysis: ComponentHandlerData, pool: ConstantPool): - CompileResult { - const res = compileComponentFromMetadata(analysis.meta, pool, makeBindingParser()); - - const statements = res.statements; + CompileResult[] { + const meta = analysis.meta; + const res = compileComponentFromMetadata(meta, pool, makeBindingParser()); + const factoryRes = compileNgFactoryDefField(meta); if (analysis.metadataStmt !== null) { - statements.push(analysis.metadataStmt); + factoryRes.statements.push(analysis.metadataStmt); } - return { - name: 'ngComponentDef', - initializer: res.expression, statements, - type: res.type, - }; + return [ + factoryRes, { + name: 'ngComponentDef', + initializer: res.expression, + statements: [], + type: res.type, + } + ]; } private _resolveLiteral(decorator: Decorator): ts.ObjectLiteralExpression { @@ -822,4 +826,4 @@ export interface ParsedTemplate { interface PreanalyzedTemplate extends ParsedTemplate { parseTemplate: (options?: ParseTemplateOptions) => ParsedTemplate; -} \ No newline at end of file +} diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index e3ccfc0fdd..394514a7c5 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -17,6 +17,7 @@ import {DynamicValue, EnumValue, PartialEvaluator} from '../../partial_evaluator import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; +import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; import {findAngularDecorator, getValidConstructorDependencies, readBaseClass, unwrapExpression, unwrapForwardRef} from './util'; @@ -90,18 +91,21 @@ export class DirectiveDecoratorHandler implements } compile(node: ClassDeclaration, analysis: DirectiveHandlerData, pool: ConstantPool): - CompileResult { - const res = compileDirectiveFromMetadata(analysis.meta, pool, makeBindingParser()); - const statements = res.statements; + CompileResult[] { + const meta = analysis.meta; + const res = compileDirectiveFromMetadata(meta, pool, makeBindingParser()); + const factoryRes = compileNgFactoryDefField(meta); if (analysis.metadataStmt !== null) { - statements.push(analysis.metadataStmt); + factoryRes.statements.push(analysis.metadataStmt); } - return { - name: 'ngDirectiveDef', - initializer: res.expression, - statements: statements, - type: res.type, - }; + return [ + factoryRes, { + name: 'ngDirectiveDef', + initializer: res.expression, + statements: [], + type: res.type, + } + ]; } } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts b/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts new file mode 100644 index 0000000000..1654ab87ec --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {R3FactoryDefMetadata, compileFactoryFromMetadata} from '@angular/compiler'; + +import {CompileResult} from '../../transform'; + +export function compileNgFactoryDefField(metadata: R3FactoryDefMetadata): CompileResult { + const res = compileFactoryFromMetadata(metadata); + return { + name: 'ngFactoryDef', + initializer: res.factory, + statements: res.statements, + type: res.type + }; +} diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index 6920807a35..4c44aafca8 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -16,6 +16,7 @@ import {PartialEvaluator} from '../../partial_evaluator'; import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; +import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; import {findAngularDecorator, getValidConstructorDependencies, unwrapExpression} from './util'; @@ -105,16 +106,20 @@ export class PipeDecoratorHandler implements DecoratorHandler { // The factory should look like this: const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; // The template should look like this (where IDENT is a wild card for an identifier): const template = ` @@ -94,7 +94,7 @@ describe('compiler compliance', () => { // The factory should look like this: const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; // The template should look like this (where IDENT is a wild card for an identifier): const template = ` @@ -142,7 +142,7 @@ describe('compiler compliance', () => { // The factory should look like this: const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; // The template should look like this (where IDENT is a wild card for an identifier): const template = ` @@ -190,7 +190,7 @@ describe('compiler compliance', () => { // The factory should look like this: const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; // The template should look like this (where IDENT is a wild card for an identifier): const template = ` @@ -306,7 +306,7 @@ describe('compiler compliance', () => { }; const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; const template = ` const $e0_attrs$ = [${AttributeMarker.Bindings}, "id"]; … @@ -361,7 +361,7 @@ describe('compiler compliance', () => { /////////////// const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; const template = ` template: function MyComponent_Template(rf, ctx) { if (rf & 1) { @@ -476,12 +476,9 @@ describe('compiler compliance', () => { }; const factory = - 'factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; + 'MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }'; const template = ` MyComponent.ngComponentDef = i0.ɵɵdefineComponent({type:MyComponent,selectors:[["my-component"]], - factory: function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 1, vars: 2, template: function MyComponent_Template(rf,ctx){ @@ -536,7 +533,6 @@ describe('compiler compliance', () => { ChildComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ChildComponent, selectors: [["child"]], - factory: function ChildComponent_Factory(t) { return new (t || ChildComponent)(); }, consts: 1, vars: 0, template: function ChildComponent_Template(rf, ctx) { @@ -547,15 +543,20 @@ describe('compiler compliance', () => { encapsulation: 2 });`; + const ChildComponentFactory = + `ChildComponent.ngFactoryDef = function ChildComponent_Factory(t) { return new (t || ChildComponent)(); };`; + // SomeDirective definition should be: const SomeDirectiveDefinition = ` SomeDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: SomeDirective, - selectors: [["", "some-directive", ""]], - factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); } + selectors: [["", "some-directive", ""]] }); `; + const SomeDirectiveFactory = + `SomeDirective.ngFactoryDef = function SomeDirective_Factory(t) {return new (t || SomeDirective)(); };`; + // MyComponent definition should be: const MyComponentDefinition = ` const $c1$ = ["some-directive", ""]; @@ -563,7 +564,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 2, vars: 0, template: function MyComponent_Template(rf, ctx) { @@ -577,13 +577,18 @@ describe('compiler compliance', () => { }); `; + const MyComponentFactory = + `MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); };`; const result = compile(files, angularFiles); const source = result.source; expectEmit(source, ChildComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); + expectEmit(source, ChildComponentFactory, 'Incorrect ChildComponent.ngFactoryDef'); expectEmit(source, SomeDirectiveDefinition, 'Incorrect SomeDirective.ngDirectiveDef'); + expectEmit(source, SomeDirectiveFactory, 'Incorrect SomeDirective.ngFactoryDef'); expectEmit(source, MyComponentDefinition, 'Incorrect MyComponentDefinition.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect MyComponentDefinition.ngFactoryDef'); }); it('should support complex selectors', () => { @@ -608,25 +613,31 @@ describe('compiler compliance', () => { const SomeDirectiveDefinition = ` SomeDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: SomeDirective, - selectors: [["div", "some-directive", "", 8, "foo", 3, "title", "", 9, "baz"]], - factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); } + selectors: [["div", "some-directive", "", 8, "foo", 3, "title", "", 9, "baz"]] }); `; + const SomeDirectiveFactory = + `SomeDirective.ngFactoryDef = function SomeDirective_Factory(t) {return new (t || SomeDirective)(); };`; + // OtherDirective definition should be: const OtherDirectiveDefinition = ` OtherDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: OtherDirective, - selectors: [["", 5, "span", "title", "", 9, "baz"]], - factory: function OtherDirective_Factory(t) {return new (t || OtherDirective)(); } + selectors: [["", 5, "span", "title", "", 9, "baz"]] }); `; + const OtherDirectiveFactory = + `OtherDirective.ngFactoryDef = function OtherDirective_Factory(t) {return new (t || OtherDirective)(); };`; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, SomeDirectiveDefinition, 'Incorrect SomeDirective.ngDirectiveDef'); + expectEmit(source, SomeDirectiveFactory, 'Incorrect SomeDirective.ngFactoryDef'); expectEmit(source, OtherDirectiveDefinition, 'Incorrect OtherDirective.ngDirectiveDef'); + expectEmit(source, OtherDirectiveFactory, 'Incorrect OtherDirective.ngFactoryDef'); }); it('should support components without selector', () => { @@ -650,7 +661,6 @@ describe('compiler compliance', () => { EmptyOutletComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: EmptyOutletComponent, selectors: [["ng-component"]], - factory: function EmptyOutletComponent_Factory(t) { return new (t || EmptyOutletComponent)(); }, consts: 1, vars: 0, template: function EmptyOutletComponent_Template(rf, ctx) { @@ -662,11 +672,16 @@ describe('compiler compliance', () => { }); `; + const EmptyOutletComponentFactory = + `EmptyOutletComponent.ngFactoryDef = function EmptyOutletComponent_Factory(t) { return new (t || EmptyOutletComponent)(); };`; + const result = compile(files, angularFiles); const source = result.source; expectEmit( source, EmptyOutletComponentDefinition, 'Incorrect EmptyOutletComponent.ngComponentDef'); + expectEmit( + source, EmptyOutletComponentFactory, 'Incorrect EmptyOutletComponent.ngFactoryDef'); }); it('should not treat ElementRef, ViewContainerRef, or ChangeDetectorRef specially when injecting', @@ -695,21 +710,23 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { - return new (t || MyComponent)( - $r3$.ɵɵdirectiveInject($i$.ElementRef), $r3$.ɵɵdirectiveInject($i$.ViewContainerRef), - $r3$.ɵɵdirectiveInject($i$.ChangeDetectorRef)); - }, consts: 0, vars: 0, template: function MyComponent_Template(rf, ctx) {}, encapsulation: 2 });`; + const MyComponentFactory = `MyComponent.ngFactoryDef = function MyComponent_Factory(t) { + return new (t || MyComponent)( + $r3$.ɵɵdirectiveInject($i$.ElementRef), $r3$.ɵɵdirectiveInject($i$.ViewContainerRef), + $r3$.ɵɵdirectiveInject($i$.ChangeDetectorRef)); + };`; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect MyComponent.ngFactoryDef'); }); it('should support structural directives', () => { @@ -740,9 +757,11 @@ describe('compiler compliance', () => { const IfDirectiveDefinition = ` IfDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: IfDirective, - selectors: [["", "if", ""]], - factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵɵdirectiveInject($i$.TemplateRef)); } + selectors: [["", "if", ""]] });`; + const IfDirectiveFactory = + `IfDirective.ngFactoryDef = function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵɵdirectiveInject($i$.TemplateRef)); };`; + const MyComponentDefinition = ` const $c1$ = ["foo", ""]; const $c2$ = [${AttributeMarker.Template}, "if"]; @@ -763,7 +782,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 3, vars: 0, template: function MyComponent_Template(rf, ctx) { @@ -777,11 +795,16 @@ describe('compiler compliance', () => { encapsulation: 2 });`; + const MyComponentFactory = + `MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); };`; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, IfDirectiveDefinition, 'Incorrect IfDirective.ngDirectiveDef'); + expectEmit(source, IfDirectiveFactory, 'Incorrect IfDirective.ngFactoryDef'); expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect MyComponent.ngFactoryDef'); }); describe('value composition', () => { @@ -826,7 +849,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 1, vars: 3, template: function MyApp_Template(rf, ctx) { @@ -908,7 +930,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 1, vars: 11, template: function MyApp_Template(rf, ctx) { @@ -971,7 +992,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 1, vars: 3, template: function MyApp_Template(rf, ctx) { @@ -1039,7 +1059,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 1, vars: 8, template: function MyApp_Template(rf, ctx) { @@ -1100,7 +1119,6 @@ describe('compiler compliance', () => { SimpleComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: SimpleComponent, selectors: [["simple"]], - factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); }, ngContentSelectors: $c0$, consts: 2, vars: 0, @@ -1123,7 +1141,6 @@ describe('compiler compliance', () => { ComplexComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ComplexComponent, selectors: [["complex"]], - factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); }, ngContentSelectors: _c4, consts: 4, vars: 0, @@ -1179,7 +1196,6 @@ describe('compiler compliance', () => { Cmp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: Cmp, selectors: [["ng-component"]], - factory: function Cmp_Factory(t) { return new (t || Cmp)(); }, ngContentSelectors: $c1$, consts: 3, vars: 0, @@ -1368,9 +1384,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { - return new(t || MyApp)(); - }, consts: 2, vars: 0, template: function MyApp_Template(rf, ctx) { @@ -1423,9 +1436,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { - return new(t || MyApp)(); - }, consts: 2, vars: 0, template: function MyApp_Template(rf, ctx) { @@ -1489,7 +1499,6 @@ describe('compiler compliance', () => { ViewQueryComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ViewQueryComponent, selectors: [["view-query-component"]], - factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); }, viewQuery: function ViewQueryComponent_Query(rf, ctx) { if (rf & 1) { $r3$.ɵɵviewQuery(SomeDirective, true); @@ -1600,7 +1609,6 @@ describe('compiler compliance', () => { ViewQueryComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ViewQueryComponent, selectors: [["view-query-component"]], - factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); }, viewQuery: function ViewQueryComponent_Query(rf, ctx) { if (rf & 1) { $r3$.ɵɵstaticViewQuery(SomeDirective, true); @@ -1727,9 +1735,6 @@ describe('compiler compliance', () => { ContentQueryComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ContentQueryComponent, selectors: [["content-query-component"]], - factory: function ContentQueryComponent_Factory(t) { - return new (t || ContentQueryComponent)(); - }, contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) { $r3$.ɵɵcontentQuery(dirIndex, SomeDirective, true); @@ -1849,9 +1854,6 @@ describe('compiler compliance', () => { ContentQueryComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: ContentQueryComponent, selectors: [["content-query-component"]], - factory: function ContentQueryComponent_Factory(t) { - return new (t || ContentQueryComponent)(); - }, contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) { $r3$.ɵɵstaticContentQuery(dirIndex, SomeDirective, true); @@ -1988,19 +1990,25 @@ describe('compiler compliance', () => { MyPipe.ngPipeDef = $r3$.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, - factory: function MyPipe_Factory(t) { return new (t || MyPipe)(); }, pure: false }); `; + const MyPipengFactoryDef = ` + MyPipe.ngFactoryDef = function MyPipe_Factory(t) { return new (t || MyPipe)(); }; + `; + const MyPurePipeDefinition = ` MyPurePipe.ngPipeDef = $r3$.ɵɵdefinePipe({ name: "myPurePipe", type: MyPurePipe, - factory: function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); }, pure: true });`; + const MyPurePipengFactoryDef = ` + MyPurePipe.ngFactoryDef = function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); }; + `; + const MyAppDefinition = ` const $c0$ = function ($a0$) { return [$a0$, 1, 2, 3, 4, 5]; @@ -2009,7 +2017,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 7, vars: 20, template: function MyApp_Template(rf, ctx) { @@ -2037,7 +2044,9 @@ describe('compiler compliance', () => { const source = result.source; expectEmit(source, MyPipeDefinition, 'Invalid pipe definition'); + expectEmit(source, MyPipengFactoryDef, 'Invalid pipe factory function'); expectEmit(source, MyPurePipeDefinition, 'Invalid pure pipe definition'); + expectEmit(source, MyPurePipengFactoryDef, 'Invalid pure pipe factory function'); expectEmit(source, MyAppDefinition, 'Invalid MyApp definition'); }); @@ -2075,7 +2084,6 @@ describe('compiler compliance', () => { MyApp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyApp, selectors: [["my-app"]], - factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, consts: 6, vars: 27, template: function MyApp_Template(rf, ctx) { @@ -2148,24 +2156,32 @@ describe('compiler compliance', () => { MyPipe.ngPipeDef = $r3$.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, - factory: function MyPipe_Factory(t) { return new (t || MyPipe)($r3$.ɵɵinjectPipeChangeDetectorRef()); }, pure: true }); `; + const MyPipeFactory = ` + MyPipe.ngFactoryDef = function MyPipe_Factory(t) { return new (t || MyPipe)($r3$.ɵɵinjectPipeChangeDetectorRef()); }; + `; + const MyOtherPipeDefinition = ` MyOtherPipe.ngPipeDef = $r3$.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, - factory: function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)($r3$.ɵɵinjectPipeChangeDetectorRef(8)); }, pure: true });`; + const MyOtherPipeFactory = ` + MyOtherPipe.ngFactoryDef = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)($r3$.ɵɵinjectPipeChangeDetectorRef(8)); }; + `; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyPipeDefinition, 'Invalid pipe definition'); + expectEmit(source, MyPipeFactory, 'Invalid pipe factory function'); expectEmit(source, MyOtherPipeDefinition, 'Invalid alternate pipe definition'); + expectEmit(source, MyOtherPipeFactory, 'Invalid alternate pipe factory function'); }); }); @@ -2191,7 +2207,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 3, vars: 1, template: function MyComponent_Template(rf, ctx) { @@ -2288,7 +2303,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 6, vars: 1, template: function MyComponent_Template(rf, ctx) { @@ -2434,7 +2448,6 @@ describe('compiler compliance', () => { LifecycleComp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: LifecycleComp, selectors: [["lifecycle-comp"]], - factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); }, inputs: {nameMin: ["name", "nameMin"]}, features: [$r3$.ɵɵNgOnChangesFeature()], consts: 0, @@ -2447,7 +2460,6 @@ describe('compiler compliance', () => { SimpleLayout.ngComponentDef = $r3$.ɵɵdefineComponent({ type: SimpleLayout, selectors: [["simple-layout"]], - factory: function SimpleLayout_Factory(t) { return new (t || SimpleLayout)(); }, consts: 2, vars: 2, template: function SimpleLayout_Template(rf, ctx) { @@ -2556,14 +2568,16 @@ describe('compiler compliance', () => { ForOfDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: ForOfDirective, selectors: [["", "forOf", ""]], - factory: function ForOfDirective_Factory(t) { - return new (t || ForOfDirective)($r3$.ɵɵdirectiveInject(ViewContainerRef), $r3$.ɵɵdirectiveInject(TemplateRef)); - }, features: [$r3$.ɵɵNgOnChangesFeature()], inputs: {forOf: "forOf"} }); `; + const ForDirectiveFactory = + `ForOfDirective.ngFactoryDef = function ForOfDirective_Factory(t) { + return new (t || ForOfDirective)($r3$.ɵɵdirectiveInject(ViewContainerRef), $r3$.ɵɵdirectiveInject(TemplateRef)); + };`; + const MyComponentDefinition = ` const $t1_attrs$ = [${AttributeMarker.Template}, "for", "forOf"]; function MyComponent__svg_g_1_Template(rf, ctx) { @@ -2578,7 +2592,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 2, vars: 1, template: function MyComponent_Template(rf, ctx){ @@ -2603,6 +2616,7 @@ describe('compiler compliance', () => { // TODO(benlesh): Enforce this when the directives are specified // expectEmit(source, ForDirectiveDefinition, 'Invalid directive definition'); + // expectEmit(source, ForDirectiveFactory, 'Invalid directive factory'); expectEmit(source, MyComponentDefinition, 'Invalid component definition'); }); @@ -2635,14 +2649,17 @@ describe('compiler compliance', () => { ForOfDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: ForOfDirective, selectors: [["", "forOf", ""]], - factory: function ForOfDirective_Factory(t) { - return new (t || ForOfDirective)($r3$.ɵɵdirectiveInject(ViewContainerRef), $r3$.ɵɵdirectiveInject(TemplateRef)); - }, features: [$r3$.ɵɵNgOnChangesFeature()], inputs: {forOf: "forOf"} }); `; + const ForDirectiveFactory = ` + ForOfDirective.ngFactoryDef = function ForOfDirective_Factory(t) { + return new (t || ForOfDirective)($r3$.ɵɵdirectiveInject(ViewContainerRef), $r3$.ɵɵdirectiveInject(TemplateRef)); + }; + `; + const MyComponentDefinition = ` const $t1_attrs$ = [${AttributeMarker.Template}, "for", "forOf"]; function MyComponent_li_1_Template(rf, ctx) { @@ -2661,7 +2678,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 2, vars: 1, template: function MyComponent_Template(rf, ctx) { @@ -2685,6 +2701,7 @@ describe('compiler compliance', () => { // TODO(chuckj): Enforce this when the directives are specified // expectEmit(source, ForDirectiveDefinition, 'Invalid directive definition'); + // expectEmit(source, ForDirectiveFactory, 'Invalid directive factory'); expectEmit(source, MyComponentDefinition, 'Invalid component definition'); }); @@ -2765,7 +2782,6 @@ describe('compiler compliance', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 2, vars: 1, template: function MyComponent_Template(rf, ctx) { @@ -2883,7 +2899,6 @@ describe('compiler compliance', () => { SomeDirective.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: SomeDirective, selectors: [["", "some-directive", ""]], - factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }, exportAs: ["someDir", "otherDir"] }); `; diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index 09d5b2b081..62f213eab3 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -671,7 +671,6 @@ describe('compiler compliance: bindings', () => { HostBindingDir.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: HostBindingDir, selectors: [["", "hostBindingDir", ""]], - factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); }, hostBindings: function HostBindingDir_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵallocHostVars(1); @@ -718,7 +717,6 @@ describe('compiler compliance: bindings', () => { HostBindingComp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: HostBindingComp, selectors: [["host-binding-comp"]], - factory: function HostBindingComp_Factory(t) { return new (t || HostBindingComp)(); }, hostBindings: function HostBindingComp_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵallocHostVars(3); @@ -766,7 +764,6 @@ describe('compiler compliance: bindings', () => { HostAttributeDir.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); }, hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵallocHostVars(1); @@ -811,7 +808,6 @@ describe('compiler compliance: bindings', () => { HostAttributeDir.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); }, hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵelementHostAttrs($c0$); @@ -869,7 +865,6 @@ describe('compiler compliance: bindings', () => { HostAttributeComp.ngComponentDef = $r3$.ɵɵdefineComponent({ type: HostAttributeComp, selectors: [["my-host-attribute-component"]], - factory: function HostAttributeComp_Factory(t) { return new (t || HostAttributeComp)(); }, hostBindings: function HostAttributeComp_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵelementHostAttrs($c0$); @@ -881,7 +876,6 @@ describe('compiler compliance: bindings', () => { HostAttributeDir.ngDirectiveDef = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); }, hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { if (rf & 1) { $r3$.ɵɵallocHostVars(2); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts index f68c5a037e..76c6e5bc2c 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts @@ -48,7 +48,7 @@ describe('compiler compliance: dependency injection', () => { }; const factory = ` - factory: function MyComponent_Factory(t) { + MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)( $r3$.ɵɵinjectAttribute('name'), $r3$.ɵɵdirectiveInject(MyService), diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts index c4c81049b1..cf7b82b27d 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts @@ -41,7 +41,6 @@ describe('compiler compliance: directives', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { @@ -53,10 +52,15 @@ describe('compiler compliance: directives', () => { }); `; + const MyComponentFactory = ` + MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; + `; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect ChildComponent.ngFactoryDef'); }); it('should not match directives on i18n-prefixed attributes', () => { @@ -87,7 +91,6 @@ describe('compiler compliance: directives', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { @@ -99,10 +102,15 @@ describe('compiler compliance: directives', () => { }); `; + const MyComponentFactory = ` + MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; + `; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect ChildComponent.ngFactoryDef'); }); it('should match directives on element bindings', () => { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts index 9f695ca116..cc7ffd6c8d 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts @@ -201,7 +201,6 @@ describe('compiler compliance: listen()', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 4, vars: 0, template: function MyComponent_Template(rf, ctx) { @@ -222,10 +221,15 @@ describe('compiler compliance: listen()', () => { }); `; + const MyComponentFactory = ` + MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; + `; + const result = compile(files, angularFiles); const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef'); + expectEmit(source, MyComponentFactory, 'Incorrect MyComponent.ngFactoryDef'); }); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_providers_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_providers_spec.ts index e46ac76c9c..08cf2e3810 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_providers_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_providers_spec.ts @@ -144,10 +144,10 @@ describe('compiler compliance: providers', () => { result.source, ` export class MyComponent { } + MyComponent.ngFactoryDef = function MyComponent_Factory(t) { return new (t || MyComponent)(); }; MyComponent.ngComponentDef = i0.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, consts: 1, vars: 0, template: function MyComponent_Template(rf, ctx) { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index b452bf516c..5ee32d42d9 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -131,9 +131,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors:[["my-component"]], - factory:function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 0, vars: 0, template: function MyComponent_Template(rf, $ctx$) { @@ -173,9 +170,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors:[["my-component"]], - factory:function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 0, vars: 0, template: function MyComponent_Template(rf, $ctx$) { @@ -524,9 +518,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors:[["my-component"]], - factory:function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 1, vars: 4, template: function MyComponent_Template(rf, $ctx$) { @@ -577,9 +568,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { - return new (t || MyComponent)(); - }, consts: 1, vars: 1, template: function MyComponent_Template(rf, ctx) { @@ -736,9 +724,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors:[["my-component"]], - factory:function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 1, vars: 4, template: function MyComponent_Template(rf, $ctx$) { @@ -791,9 +776,6 @@ describe('compiler compliance: styling', () => { MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors:[["my-component"]], - factory:function MyComponent_Factory(t){ - return new (t || MyComponent)(); - }, consts: 1, vars: 2, template: function MyComponent_Template(rf, $ctx$) { diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index d1daf105f5..2fabaee379 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -197,12 +197,14 @@ runInEachFileSystem(os => { const jsContents = env.getContents('test.js'); expect(jsContents).toContain('TestCmp.ngComponentDef = i0.ɵɵdefineComponent'); + expect(jsContents).toContain('TestCmp.ngFactoryDef = function'); expect(jsContents).not.toContain('__decorate'); const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( 'static ngComponentDef: i0.ɵɵComponentDefWithMeta'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef'); }); it('should compile Components (dynamic inline template) without errors', () => { @@ -220,12 +222,15 @@ runInEachFileSystem(os => { const jsContents = env.getContents('test.js'); expect(jsContents).toContain('TestCmp.ngComponentDef = i0.ɵɵdefineComponent'); + expect(jsContents).toContain('TestCmp.ngFactoryDef = function'); expect(jsContents).not.toContain('__decorate'); const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) .toContain( 'static ngComponentDef: i0.ɵɵComponentDefWithMeta'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef'); }); it('should compile Components (function call inline template) without errors', () => { @@ -246,12 +251,14 @@ runInEachFileSystem(os => { const jsContents = env.getContents('test.js'); expect(jsContents).toContain('TestCmp.ngComponentDef = i0.ɵɵdefineComponent'); + expect(jsContents).toContain('TestCmp.ngFactoryDef = function'); expect(jsContents).not.toContain('__decorate'); const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( 'static ngComponentDef: i0.ɵɵComponentDefWithMeta'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef'); }); it('should compile Components (external template) without errors', () => { @@ -880,10 +887,13 @@ runInEachFileSystem(os => { expect(jsContents) .toContain( - 'TestPipe.ngPipeDef = i0.ɵɵdefinePipe({ name: "test-pipe", type: TestPipe, ' + - 'factory: function TestPipe_Factory(t) { return new (t || TestPipe)(); }, pure: false })'); + 'TestPipe.ngPipeDef = i0.ɵɵdefinePipe({ name: "test-pipe", type: TestPipe, pure: false })'); + expect(jsContents) + .toContain( + 'TestPipe.ngFactoryDef = function TestPipe_Factory(t) { return new (t || TestPipe)(); }'); expect(dtsContents) .toContain('static ngPipeDef: i0.ɵɵPipeDefWithMeta;'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef;'); }); it('should compile pure Pipes without errors', () => { @@ -903,10 +913,13 @@ runInEachFileSystem(os => { expect(jsContents) .toContain( - 'TestPipe.ngPipeDef = i0.ɵɵdefinePipe({ name: "test-pipe", type: TestPipe, ' + - 'factory: function TestPipe_Factory(t) { return new (t || TestPipe)(); }, pure: true })'); + 'TestPipe.ngPipeDef = i0.ɵɵdefinePipe({ name: "test-pipe", type: TestPipe, pure: true })'); + expect(jsContents) + .toContain( + 'TestPipe.ngFactoryDef = function TestPipe_Factory(t) { return new (t || TestPipe)(); }'); expect(dtsContents) .toContain('static ngPipeDef: i0.ɵɵPipeDefWithMeta;'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef;'); }); it('should compile Pipes with dependencies', () => { @@ -947,6 +960,7 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain('static ngPipeDef: i0.ɵɵPipeDefWithMeta, "test-pipe">;'); + expect(dtsContents).toContain('static ngFactoryDef: i0.ɵɵFactoryDef>;'); }); it('should include @Pipes in @NgModule scopes', () => { @@ -1615,7 +1629,7 @@ runInEachFileSystem(os => { const jsContents = env.getContents('test.js'); expect(jsContents) .toContain( - `factory: function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵɵinjectAttribute("test"), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Injector), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.TemplateRef), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); }`); + `FooCmp.ngFactoryDef = function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵɵinjectAttribute("test"), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Injector), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.TemplateRef), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); }`); }); it('should generate queries for components', () => { diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index e4e1b00e6a..ae81738dfe 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -95,7 +95,7 @@ export {BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent export * from './render3/view/t2_api'; export * from './render3/view/t2_binder'; export {Identifiers as R3Identifiers} from './render3/r3_identifiers'; -export {R3DependencyMetadata, R3FactoryMetadata, R3ResolvedDependencyType} from './render3/r3_factory'; +export {R3DependencyMetadata, R3FactoryDefMetadata, R3ResolvedDependencyType, compileFactoryFromMetadata, R3FactoryMetadata} from './render3/r3_factory'; export {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler'; export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler'; export {makeBindingParser, parseTemplate, ParseTemplateOptions} from './render3/view/template'; @@ -106,4 +106,4 @@ export {publishFacade} from './jit_compiler_facade'; // This function call has a global side effects and publishes the compiler into global namespace for // the late binding of the Compiler to the @angular/core for jit compilation. -publishFacade(global); \ No newline at end of file +publishFacade(global); diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index 6f6a0099b6..b95c8c2115 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -39,6 +39,10 @@ export interface CompilerFacade { angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade): any; + compileFactory( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + meta: R3PipeMetadataFacade|R3DirectiveMetadataFacade|R3ComponentMetadataFacade, + isPipe?: boolean): any; createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan; diff --git a/packages/compiler/src/injectable_compiler_2.ts b/packages/compiler/src/injectable_compiler_2.ts index 068697f00a..5520b56ed1 100644 --- a/packages/compiler/src/injectable_compiler_2.ts +++ b/packages/compiler/src/injectable_compiler_2.ts @@ -37,6 +37,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { const factoryMeta = { name: meta.name, type: meta.type, + typeArgumentCount: meta.typeArgumentCount, deps: meta.ctorDeps, injectFn: Identifiers.inject, }; diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 9255851376..9b20d292bd 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -15,7 +15,7 @@ import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/int import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast'; import {JitEvaluator} from './output/output_jit'; import {ParseError, ParseSourceSpan, r3JitTypeSourceSpan} from './parse_util'; -import {R3DependencyMetadata, R3ResolvedDependencyType} from './render3/r3_factory'; +import {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFromMetadata} from './render3/r3_factory'; import {R3JitReflector} from './render3/r3_jit'; import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule} from './render3/r3_module_compiler'; import {compilePipeFromMetadata} from './render3/r3_pipe_compiler'; @@ -35,15 +35,16 @@ export class CompilerFacadeImpl implements CompilerFacade { compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3PipeMetadataFacade): any { - const res = compilePipeFromMetadata({ + const metadata = { name: facade.name, type: new WrappedNodeExpr(facade.type), typeArgumentCount: facade.typeArgumentCount, deps: convertR3DependencyMetadataArray(facade.deps), pipeName: facade.pipeName, pure: facade.pure, - }); - return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + }; + const res = compilePipeFromMetadata(metadata); + return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); } compileInjectable( @@ -105,8 +106,8 @@ export class CompilerFacadeImpl implements CompilerFacade { const meta: R3DirectiveMetadata = convertDirectiveFacadeToMetadata(facade); const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser); - const preStatements = [...constantPool.statements, ...res.statements]; - return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + return this.jitExpression( + res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements); } compileComponent( @@ -129,27 +130,41 @@ export class CompilerFacadeImpl implements CompilerFacade { // Compile the component metadata, including template, into an expression. // TODO(alxhub): implement inputs, outputs, queries, etc. + const metadata = { + ...facade as R3ComponentMetadataFacadeNoPropAndWhitespace, + ...convertDirectiveFacadeToMetadata(facade), + selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), + template, + wrapDirectivesAndPipesInClosure: false, + styles: facade.styles || [], + encapsulation: facade.encapsulation as any, + interpolation: interpolationConfig, + changeDetection: facade.changeDetection, + animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, + viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : + null, + relativeContextFilePath: '', + i18nUseExternalIds: true, + }; const res = compileComponentFromMetadata( - { - ...facade as R3ComponentMetadataFacadeNoPropAndWhitespace, - ...convertDirectiveFacadeToMetadata(facade), - selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(), - template, - wrapDirectivesAndPipesInClosure: false, - styles: facade.styles || [], - encapsulation: facade.encapsulation as any, - interpolation: interpolationConfig, - changeDetection: facade.changeDetection, - animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null, - viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : - null, - relativeContextFilePath: '', - i18nUseExternalIds: true, - }, - constantPool, makeBindingParser(interpolationConfig)); - const preStatements = [...constantPool.statements, ...res.statements]; + metadata, constantPool, makeBindingParser(interpolationConfig)); + const jitExpressionSourceMap = `ng:///${facade.name}.js`; return this.jitExpression( - res.expression, angularCoreEnv, `ng:///${facade.name}.js`, preStatements); + res.expression, angularCoreEnv, jitExpressionSourceMap, constantPool.statements); + } + + compileFactory( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + meta: R3PipeMetadataFacade|R3DirectiveMetadataFacade|R3ComponentMetadataFacade, + isPipe = false) { + const factoryRes = compileFactoryFromMetadata({ + name: meta.name, + type: new WrappedNodeExpr(meta.type), + typeArgumentCount: meta.typeArgumentCount, + deps: convertR3DependencyMetadataArray(meta.deps), isPipe + }); + return this.jitExpression( + factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements); } compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3BaseMetadataFacade): diff --git a/packages/compiler/src/render3/r3_factory.ts b/packages/compiler/src/render3/r3_factory.ts index 87b7edb6c3..d23dced86c 100644 --- a/packages/compiler/src/render3/r3_factory.ts +++ b/packages/compiler/src/render3/r3_factory.ts @@ -15,9 +15,11 @@ import * as o from '../output/output_ast'; import {Identifiers as R3} from '../render3/r3_identifiers'; import {OutputContext} from '../util'; +import {typeWithParameters} from './util'; import {unsupported} from './view/util'; + /** * Metadata required by the factory generator to generate a `factory` function for a type. */ @@ -36,6 +38,9 @@ export interface R3ConstructorFactoryMetadata { */ type: o.Expression; + /** Number of arguments for the `type`. */ + typeArgumentCount: number; + /** * Regardless of whether `fnOrClass` is a constructor function or a user-defined factory, it * may have 0 or more parameters, which will be injected according to the `R3DependencyMetadata` @@ -77,6 +82,14 @@ export interface R3ExpressionFactoryMetadata extends R3ConstructorFactoryMetadat export type R3FactoryMetadata = R3ConstructorFactoryMetadata | R3DelegatedFactoryMetadata | R3DelegatedFnOrClassMetadata | R3ExpressionFactoryMetadata; +export interface R3FactoryDefMetadata { + name: string; + type: o.Expression; + typeArgumentCount: number; + deps: R3DependencyMetadata[]|null; + isPipe?: boolean; +} + /** * Resolved type of a dependency. * @@ -140,11 +153,16 @@ export interface R3DependencyMetadata { skipSelf: boolean; } +export interface R3FactoryFn { + factory: o.Expression; + statements: o.Statement[]; + type: o.ExpressionType; +} + /** * Construct a factory function expression for the given `R3FactoryMetadata`. */ -export function compileFactoryFunction( - meta: R3FactoryMetadata, isPipe = false): {factory: o.Expression, statements: o.Statement[]} { +export function compileFactoryFunction(meta: R3FactoryMetadata, isPipe = false): R3FactoryFn { const t = o.variable('t'); const statements: o.Statement[] = []; @@ -234,9 +252,27 @@ export function compileFactoryFunction( [new o.FnParam('t', o.DYNAMIC_TYPE)], body, o.INFERRED_TYPE, undefined, `${meta.name}_Factory`), statements, + type: o.expressionType( + o.importExpr(R3.FactoryDef, [typeWithParameters(meta.type, meta.typeArgumentCount)])) }; } +/** + * Constructs the `ngFactoryDef` from directive/component/pipe metadata. + */ +export function compileFactoryFromMetadata(meta: R3FactoryDefMetadata): R3FactoryFn { + return compileFactoryFunction( + { + name: meta.name, + type: meta.type, + deps: meta.deps, + typeArgumentCount: meta.typeArgumentCount, + // TODO(crisbeto): this should be refactored once we start using it for injectables. + injectFn: R3.directiveInject, + }, + meta.isPipe); +} + function injectDependencies( deps: R3DependencyMetadata[], injectFn: o.ExternalReference, isPipe: boolean): o.Expression[] { return deps.map(dep => compileInjectDependency(dep, injectFn, isPipe)); diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 63bfc33536..65ba553d30 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -241,6 +241,11 @@ export class Identifiers { moduleName: CORE, }; + static FactoryDef: o.ExternalReference = { + name: 'ɵɵFactoryDef', + moduleName: CORE, + }; + static defineDirective: o.ExternalReference = { name: 'ɵɵdefineDirective', moduleName: CORE, diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index df83a468d6..2e3444bcbe 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -207,6 +207,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef { const result = compileFactoryFunction({ name: meta.name, type: meta.type, + typeArgumentCount: 0, deps: meta.deps, injectFn: R3.inject, }); diff --git a/packages/compiler/src/render3/r3_pipe_compiler.ts b/packages/compiler/src/render3/r3_pipe_compiler.ts index 2ebf1f3748..e13416a486 100644 --- a/packages/compiler/src/render3/r3_pipe_compiler.ts +++ b/packages/compiler/src/render3/r3_pipe_compiler.ts @@ -12,7 +12,7 @@ import {DefinitionKind} from '../constant_pool'; import * as o from '../output/output_ast'; import {OutputContext, error} from '../util'; -import {R3DependencyMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; +import {R3DependencyMetadata, compileFactoryFromMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; import {Identifiers as R3} from './r3_identifiers'; import {typeWithParameters} from './util'; @@ -57,16 +57,6 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) { // e.g. `type: MyPipe` definitionMapValues.push({key: 'type', value: metadata.type, quoted: false}); - const templateFactory = compileFactoryFunction( - { - name: metadata.name, - type: metadata.type, - deps: metadata.deps, - injectFn: R3.directiveInject, - }, - true); - definitionMapValues.push({key: 'factory', value: templateFactory.factory, quoted: false}); - // e.g. `pure: true` definitionMapValues.push({key: 'pure', value: o.literal(metadata.pure), quoted: false}); @@ -75,7 +65,8 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) { typeWithParameters(metadata.type, metadata.typeArgumentCount), new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)), ])); - return {expression, type, statements: templateFactory.statements}; + + return {expression, type}; } /** @@ -83,9 +74,8 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) { */ export function compilePipeFromRender2( outputCtx: OutputContext, pipe: CompilePipeMetadata, reflector: CompileReflector) { - const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = []; - const name = identifierName(pipe.type); + if (!name) { return error(`Cannot resolve the name of ${pipe.type}`); } @@ -98,12 +88,22 @@ export function compilePipeFromRender2( deps: dependenciesFromGlobalMetadata(pipe.type, outputCtx, reflector), pure: pipe.pure, }; - const res = compilePipeFromMetadata(metadata); - + const factoryRes = compileFactoryFromMetadata({...metadata, isPipe: true}); const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Pipe); - - outputCtx.statements.push(new o.ClassStmt( + const ngFactoryDefStatement = new o.ClassStmt( + /* name */ name, + /* parent */ null, + /* fields */ + [new o.ClassField( + /* name */ 'ngFactoryDef', + /* type */ o.INFERRED_TYPE, + /* modifiers */[o.StmtModifier.Static], + /* initializer */ factoryRes.factory)], + /* getters */[], + /* constructorMethod */ new o.ClassMethod(null, [], []), + /* methods */[]); + const pipeDefStatement = new o.ClassStmt( /* name */ name, /* parent */ null, /* fields */[new o.ClassField( @@ -113,5 +113,7 @@ export function compilePipeFromRender2( /* initializer */ res.expression)], /* getters */[], /* constructorMethod */ new o.ClassMethod(null, [], []), - /* methods */[])); + /* methods */[]); + + outputCtx.statements.push(ngFactoryDefStatement, pipeDefStatement); } diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index dd3f89fab7..44ad40ef1b 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -237,7 +237,6 @@ export interface R3QueryMetadata { export interface R3DirectiveDef { expression: o.Expression; type: o.Type; - statements: o.Statement[]; } /** @@ -246,7 +245,6 @@ export interface R3DirectiveDef { export interface R3ComponentDef { expression: o.Expression; type: o.Type; - statements: o.Statement[]; } /** diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 619abc0739..eb4245b661 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -22,7 +22,7 @@ import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler'; import {BindingParser} from '../../template_parser/binding_parser'; import {OutputContext, error} from '../../util'; import {BoundEvent} from '../r3_ast'; -import {compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory'; +import {compileFactoryFromMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory'; import {Identifiers as R3} from '../r3_identifiers'; import {Render3ParseResult} from '../r3_template_transform'; import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util'; @@ -44,7 +44,7 @@ function getStylingPrefix(name: string): string { function baseDirectiveFields( meta: R3DirectiveMetadata, constantPool: ConstantPool, - bindingParser: BindingParser): {definitionMap: DefinitionMap, statements: o.Statement[]} { + bindingParser: BindingParser): DefinitionMap { const definitionMap = new DefinitionMap(); // e.g. `type: MyDirective` @@ -53,16 +53,6 @@ function baseDirectiveFields( // e.g. `selectors: [['', 'someDir', '']]` definitionMap.set('selectors', createDirectiveSelector(meta.selector)); - - // e.g. `factory: () => new MyApp(directiveInject(ElementRef))` - const result = compileFactoryFunction({ - name: meta.name, - type: meta.type, - deps: meta.deps, - injectFn: R3.directiveInject, - }); - definitionMap.set('factory', result.factory); - if (meta.queries.length > 0) { // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... } definitionMap.set( @@ -90,7 +80,7 @@ function baseDirectiveFields( definitionMap.set('exportAs', o.literalArr(meta.exportAs.map(e => o.literal(e)))); } - return {definitionMap, statements: result.statements}; + return definitionMap; } /** @@ -128,12 +118,12 @@ function addFeatures( export function compileDirectiveFromMetadata( meta: R3DirectiveMetadata, constantPool: ConstantPool, bindingParser: BindingParser): R3DirectiveDef { - const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser); + const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser); addFeatures(definitionMap, meta); const expression = o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()]); const type = createTypeForDef(meta, R3.DirectiveDefWithMeta); - return {expression, type, statements}; + return {expression, type}; } export interface R3BaseRefMetaData { @@ -197,7 +187,7 @@ export function compileBaseDefFromMetadata( export function compileComponentFromMetadata( meta: R3ComponentMetadata, constantPool: ConstantPool, bindingParser: BindingParser): R3ComponentDef { - const {definitionMap, statements} = baseDirectiveFields(meta, constantPool, bindingParser); + const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser); addFeatures(definitionMap, meta); const selector = meta.selector && CssSelector.parse(meta.selector); @@ -315,7 +305,7 @@ export function compileComponentFromMetadata( const expression = o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()]); const type = createTypeForDef(meta, R3.ComponentDefWithMeta); - return {expression, type, statements}; + return {expression, type}; } /** @@ -335,12 +325,19 @@ export function compileDirectiveFromRender2( const meta = directiveMetadataFromGlobalMetadata(directive, outputCtx, reflector); const res = compileDirectiveFromMetadata(meta, outputCtx.constantPool, bindingParser); - - // Create the partial class to be merged with the actual class. - outputCtx.statements.push(new o.ClassStmt( + const factoryRes = compileFactoryFromMetadata(meta); + const ngFactoryDefStatement = new o.ClassStmt( + name, null, + [new o.ClassField( + 'ngFactoryDef', o.INFERRED_TYPE, [o.StmtModifier.Static], factoryRes.factory)], + [], new o.ClassMethod(null, [], []), []); + const directiveDefStatement = new o.ClassStmt( name, null, [new o.ClassField(definitionField, o.INFERRED_TYPE, [o.StmtModifier.Static], res.expression)], - [], new o.ClassMethod(null, [], []), [])); + [], new o.ClassMethod(null, [], []), []); + + // Create the partial class to be merged with the actual class. + outputCtx.statements.push(ngFactoryDefStatement, directiveDefStatement); } /** @@ -381,12 +378,19 @@ export function compileComponentFromRender2( i18nUseExternalIds: true, }; const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser); - - // Create the partial class to be merged with the actual class. - outputCtx.statements.push(new o.ClassStmt( + const factoryRes = compileFactoryFromMetadata(meta); + const ngFactoryDefStatement = new o.ClassStmt( + name, null, + [new o.ClassField( + 'ngFactoryDef', o.INFERRED_TYPE, [o.StmtModifier.Static], factoryRes.factory)], + [], new o.ClassMethod(null, [], []), []); + const componentDefStatement = new o.ClassStmt( name, null, [new o.ClassField(definitionField, o.INFERRED_TYPE, [o.StmtModifier.Static], res.expression)], - [], new o.ClassMethod(null, [], []), [])); + [], new o.ClassMethod(null, [], []), []); + + // Create the partial class to be merged with the actual class. + outputCtx.statements.push(ngFactoryDefStatement, componentDefStatement); } /** diff --git a/packages/core/src/compiler/compiler_facade_interface.ts b/packages/core/src/compiler/compiler_facade_interface.ts index 6f6a0099b6..b95c8c2115 100644 --- a/packages/core/src/compiler/compiler_facade_interface.ts +++ b/packages/core/src/compiler/compiler_facade_interface.ts @@ -39,6 +39,10 @@ export interface CompilerFacade { angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade): any; + compileFactory( + angularCoreEnv: CoreEnvironment, sourceMapUrl: string, + meta: R3PipeMetadataFacade|R3DirectiveMetadataFacade|R3ComponentMetadataFacade, + isPipe?: boolean): any; createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan; diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 5185c256d8..b739d20dc4 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -156,6 +156,7 @@ export { ɵɵBaseDef, ComponentDef as ɵComponentDef, ɵɵComponentDefWithMeta, + ɵɵFactoryDef, DirectiveDef as ɵDirectiveDef, ɵɵDirectiveDefWithMeta, PipeDef as ɵPipeDef, diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index f3271c2b98..0629d0bc5f 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -10,6 +10,7 @@ import '../util/ng_dev_mode'; import {OnDestroy} from '../interface/lifecycle_hooks'; import {Type} from '../interface/type'; +import {getFactoryDef} from '../render3/definition'; import {throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError} from '../render3/errors'; import {deepForEach, newArray} from '../util/array_utils'; import {stringify} from '../util/stringify'; @@ -398,8 +399,10 @@ export class R3Injector { function injectableDefOrInjectorDefFactory(token: Type| InjectionToken): () => any { // Most tokens will have an ngInjectableDef directly on them, which specifies a factory directly. const injectableDef = getInjectableDef(token); - if (injectableDef !== null) { - return injectableDef.factory; + const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token); + + if (factory !== null) { + return factory; } // If the token is an NgModule, it's also injectable but the factory is on its ngInjectorDef. diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 1c0e753653..99672e8507 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -7,6 +7,7 @@ */ import '../util/ng_dev_mode'; + import {ChangeDetectionStrategy} from '../change_detection/constants'; import {NG_INJECTABLE_DEF, ɵɵdefineInjectable} from '../di/interface/defs'; import {Mutable, Type} from '../interface/type'; @@ -15,8 +16,9 @@ import {SchemaMetadata} from '../metadata/schema'; import {ViewEncapsulation} from '../metadata/view'; import {noSideEffects} from '../util/closure'; import {stringify} from '../util/stringify'; + import {EMPTY_ARRAY, EMPTY_OBJ} from './empty'; -import {NG_BASE_DEF, NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_LOCALE_ID_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields'; +import {NG_BASE_DEF, NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_FACTORY_DEF, NG_LOCALE_ID_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields'; import {ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveType, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction, ɵɵBaseDef} from './interfaces/definition'; // while SelectorFlags is unused here, it's required so that types don't get resolved lazily // see: https://github.com/Microsoft/web-build-tools/issues/1050 @@ -49,11 +51,6 @@ export function ɵɵdefineComponent(componentDefinition: { /** The selectors that will be used to match nodes to this component. */ selectors: CssSelectorList; - /** - * Factory method used to create an instance of directive. - */ - factory: FactoryFn; - /** * The number of nodes, local refs, and pipes in this component template. * @@ -251,7 +248,7 @@ export function ɵɵdefineComponent(componentDefinition: { providersResolver: null, consts: componentDefinition.consts, vars: componentDefinition.vars, - factory: componentDefinition.factory, + factory: null, template: componentDefinition.template || null !, ngContentSelectors: componentDefinition.ngContentSelectors, hostBindings: componentDefinition.hostBindings || null, @@ -300,15 +297,6 @@ export function ɵɵdefineComponent(componentDefinition: { def.pipeDefs = pipeTypes ? () => (typeof pipeTypes === 'function' ? pipeTypes() : pipeTypes).map(extractPipeDef) : null; - - // Add ngInjectableDef so components are reachable through the module injector by default - // (unless it has already been set by the @Injectable decorator). This is mostly to - // support injecting components in tests. In real application code, components should - // be retrieved through the node injector, so this isn't a problem. - if (!type.hasOwnProperty(NG_INJECTABLE_DEF)) { - (type as any)[NG_INJECTABLE_DEF] = - ɵɵdefineInjectable({token: type, factory: componentDefinition.factory as() => T}); - } }) as never; return def as never; @@ -615,11 +603,6 @@ export const ɵɵdefineDirective = ɵɵdefineComponent as any as(directiveDef /** The selectors that will be used to match nodes to this directive. */ selectors: CssSelectorList; - /** - * Factory method used to create an instance of directive. - */ - factory: FactoryFn; - /** * A map of input names. * @@ -731,15 +714,13 @@ export function ɵɵdefinePipe(pipeDef: { /** Pipe class reference. Needed to extract pipe lifecycle hooks. */ type: Type, - /** A factory for creating a pipe instance. */ - factory: FactoryFn, - /** Whether the pipe is pure. */ pure?: boolean }): never { return (>{ + type: pipeDef.type, name: pipeDef.name, - factory: pipeDef.factory, + factory: null, pure: pipeDef.pure !== false, onDestroy: pipeDef.type.prototype.ngOnDestroy || null }) as never; @@ -752,25 +733,35 @@ export function ɵɵdefinePipe(pipeDef: { */ export function getComponentDef(type: any): ComponentDef|null { - return (type as any)[NG_COMPONENT_DEF] || null; + return type[NG_COMPONENT_DEF] || null; } export function getDirectiveDef(type: any): DirectiveDef|null { - return (type as any)[NG_DIRECTIVE_DEF] || null; + return type[NG_DIRECTIVE_DEF] || null; } export function getPipeDef(type: any): PipeDef|null { - return (type as any)[NG_PIPE_DEF] || null; + return type[NG_PIPE_DEF] || null; } export function getBaseDef(type: any): ɵɵBaseDef|null { - return (type as any)[NG_BASE_DEF] || null; + return type[NG_BASE_DEF] || null; +} + +export function getFactoryDef(type: any, throwNotFound: true): FactoryFn; +export function getFactoryDef(type: any): FactoryFn|null; +export function getFactoryDef(type: any, throwNotFound?: boolean): FactoryFn|null { + const factoryFn = type[NG_FACTORY_DEF] || null; + if (!factoryFn && throwNotFound === true && ngDevMode) { + throw new Error(`Type ${stringify(type)} does not have 'ngFactoryDef' property.`); + } + return factoryFn; } export function getNgModuleDef(type: any, throwNotFound: true): NgModuleDef; export function getNgModuleDef(type: any): NgModuleDef|null; export function getNgModuleDef(type: any, throwNotFound?: boolean): NgModuleDef|null { - const ngModuleDef = (type as any)[NG_MODULE_DEF] || null; + const ngModuleDef = type[NG_MODULE_DEF] || null; if (!ngModuleDef && throwNotFound === true) { throw new Error(`Type ${stringify(type)} does not have 'ngModuleDef' property.`); } diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index ec754f7dd0..9fd74c251c 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -15,7 +15,7 @@ import {InjectFlags} from '../di/interface/injector'; import {Type} from '../interface/type'; import {assertDefined, assertEqual} from '../util/assert'; -import {getComponentDef, getDirectiveDef, getPipeDef} from './definition'; +import {getFactoryDef} from './definition'; import {NG_ELEMENT_ID} from './fields'; import {DirectiveDef, FactoryFn} from './interfaces/definition'; import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; @@ -642,12 +642,10 @@ export function ɵɵgetFactoryOf(type: Type): FactoryFn|null { }) as any; } - const def = getComponentDef(typeAny) || getDirectiveDef(typeAny) || - getPipeDef(typeAny) || getInjectableDef(typeAny) || getInjectorDef(typeAny); - if (!def || def.factory === undefined) { - return null; - } - return def.factory; + // TODO(crisbeto): unify injectable factories with getFactory. + const def = getInjectableDef(typeAny) || getInjectorDef(typeAny); + const factory = def && def.factory || getFactoryDef(typeAny); + return factory || null; } /** diff --git a/packages/core/src/render3/fields.ts b/packages/core/src/render3/fields.ts index 92642b417f..54799295ef 100644 --- a/packages/core/src/render3/fields.ts +++ b/packages/core/src/render3/fields.ts @@ -14,6 +14,7 @@ export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: getClosureSafeProp export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: getClosureSafeProperty}); export const NG_LOCALE_ID_DEF = getClosureSafeProperty({ngLocaleIdDef: getClosureSafeProperty}); export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProperty}); +export const NG_FACTORY_DEF = getClosureSafeProperty({ngFactoryDef: getClosureSafeProperty}); /** * If a directive is diPublic, bloomAdd sets a property on the type with this constant as diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 842ecbc781..007b8fe282 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -10,11 +10,12 @@ import {ɵɵdefineBase, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineNgMo import {ɵɵInheritDefinitionFeature} from './features/inherit_definition_feature'; import {ɵɵNgOnChangesFeature} from './features/ng_onchanges_feature'; import {ɵɵProvidersFeature} from './features/providers_feature'; -import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef, ɵɵBaseDef, ɵɵComponentDefWithMeta, ɵɵDirectiveDefWithMeta, ɵɵPipeDefWithMeta} from './interfaces/definition'; +import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef, ɵɵBaseDef, ɵɵComponentDefWithMeta, ɵɵDirectiveDefWithMeta, ɵɵFactoryDef, ɵɵPipeDefWithMeta} from './interfaces/definition'; import {getComponent, getDirectives, getHostElement, getRenderedText} from './util/discovery_utils'; export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref'; export {ɵɵgetFactoryOf, ɵɵgetInheritedFactory} from './di'; + // clang-format off export { detectChanges, @@ -205,6 +206,7 @@ export { ɵɵBaseDef, ComponentDef, ɵɵComponentDefWithMeta, + ɵɵFactoryDef, ComponentTemplate, ComponentType, DirectiveDef, diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index c9f958cf6c..dc8587c41d 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -15,6 +15,7 @@ import {createNamedArrayType} from '../../util/named_array_type'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect'; import {assertFirstTemplatePass, assertLView} from '../assert'; import {attachPatchData, getComponentViewByInstance} from '../context_discovery'; +import {getFactoryDef} from '../definition'; import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from '../di'; import {throwMultipleComponentError} from '../errors'; import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags, registerPreOrderHooks} from '../hooks'; @@ -1028,7 +1029,7 @@ export function instantiateRootComponent( if (tView.firstTemplatePass) { if (def.providersResolver) def.providersResolver(def); generateExpandoInstructionBlock(tView, rootTNode, 1); - baseResolveDirective(tView, viewData, def, def.factory); + baseResolveDirective(tView, viewData, def); } const directive = getNodeInjectable(tView.data, viewData, viewData.length - 1, rootTNode as TElementNode); @@ -1072,7 +1073,7 @@ export function resolveDirectives( const def = directives[i] as DirectiveDef; const directiveDefIdx = tView.data.length; - baseResolveDirective(tView, lView, def, def.factory); + baseResolveDirective(tView, lView, def); saveNameToExportMap(tView.data !.length - 1, def, exportsMap); @@ -1311,9 +1312,9 @@ export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: n tNode.providerIndexes = index; } -function baseResolveDirective( - tView: TView, viewData: LView, def: DirectiveDef, directiveFactory: FactoryFn) { +function baseResolveDirective(tView: TView, viewData: LView, def: DirectiveDef) { tView.data.push(def); + const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true)); const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); tView.blueprint.push(nodeInjectorFactory); viewData.push(nodeInjectorFactory); diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index bbebd0a748..9d5f6b9e74 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -76,7 +76,10 @@ export interface ComponentType extends Type { ngComponentDef: never; } * A subclass of `Type` which has a static `ngDirectiveDef`:`DirectiveDef` field making it * consumable for rendering. */ -export interface DirectiveType extends Type { ngDirectiveDef: never; } +export interface DirectiveType extends Type { + ngDirectiveDef: never; + ngFactoryDef: () => T; +} export const enum DirectiveDefFlags {ContentQuery = 0b10} @@ -175,9 +178,10 @@ export interface DirectiveDef extends ɵɵBaseDef { readonly exportAs: string[]|null; /** - * Factory function used to create a new directive instance. + * Factory function used to create a new directive instance. Will be null initially. + * Populated when the factory is first requested by directive instantiation logic. */ - factory: FactoryFn; + factory: FactoryFn|null; /* The following are lifecycle hooks for this component */ onChanges: (() => void)|null; @@ -207,6 +211,11 @@ export type ɵɵComponentDefWithMeta< T, Selector extends String, ExportAs extends string[], InputMap extends{[key: string]: string}, OutputMap extends{[key: string]: string}, QueryFields extends string[]> = ComponentDef; +/** + * @codeGenApi + */ +export type ɵɵFactoryDef = () => T; + /** * Runtime link information for Components. * @@ -329,6 +338,9 @@ export interface ComponentDef extends DirectiveDef { * See: {@link definePipe} */ export interface PipeDef { + /** Token representing the pipe. */ + type: Type; + /** * Pipe name. * @@ -337,9 +349,10 @@ export interface PipeDef { readonly name: string; /** - * Factory function used to create a new pipe instance. + * Factory function used to create a new pipe instance. Will be null initially. + * Populated when the factory is first requested by pipe instantiation logic. */ - factory: FactoryFn; + factory: FactoryFn|null; /** * Whether or not the pipe is pure. diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 48b9312479..334f937088 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -7,7 +7,7 @@ */ import {R3DirectiveMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; -import {R3BaseMetadataFacade, R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface'; +import {CompilerFacade, R3BaseMetadataFacade, R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface'; import {resolveForwardRef} from '../../di/forward_ref'; import {compileInjectable} from '../../di/jit/injectable'; import {getReflect, reflectDependencies} from '../../di/jit/util'; @@ -18,7 +18,7 @@ import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from import {ViewEncapsulation} from '../../metadata/view'; import {getBaseDef, getComponentDef, getDirectiveDef} from '../definition'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; -import {NG_BASE_DEF, NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields'; +import {NG_BASE_DEF, NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_FACTORY_DEF} from '../fields'; import {ComponentType} from '../interfaces/definition'; import {stringifyForError} from '../util/misc_utils'; @@ -38,43 +38,31 @@ import {flushModuleScopingQueueAsMuchAsPossible, patchComponentDefWithScope, tra */ export function compileComponent(type: Type, metadata: Component): void { let ngComponentDef: any = null; + let ngFactoryDef: any = null; + // Metadata may have resources which need to be resolved. maybeQueueResolutionOfComponentResources(type, metadata); + + Object.defineProperty(type, NG_FACTORY_DEF, { + get: () => { + if (ngFactoryDef === null) { + const compiler = getCompilerFacade(); + const meta = getComponentMetadata(compiler, type, metadata); + ngFactoryDef = compiler.compileFactory( + angularCoreEnv, `ng:///${type.name}/ngFactory.js`, meta.metadata); + } + return ngFactoryDef; + }, + // Make the property configurable in dev mode to allow overriding in tests + configurable: !!ngDevMode, + }); + Object.defineProperty(type, NG_COMPONENT_DEF, { get: () => { - const compiler = getCompilerFacade(); if (ngComponentDef === null) { - if (componentNeedsResolution(metadata)) { - const error = [`Component '${type.name}' is not resolved:`]; - if (metadata.templateUrl) { - error.push(` - templateUrl: ${metadata.templateUrl}`); - } - if (metadata.styleUrls && metadata.styleUrls.length) { - error.push(` - styleUrls: ${JSON.stringify(metadata.styleUrls)}`); - } - error.push(`Did you run and wait for 'resolveComponentResources()'?`); - throw new Error(error.join('\n')); - } - - const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`; - const meta: R3ComponentMetadataFacade = { - ...directiveMetadata(type, metadata), - typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), - template: metadata.template || '', - preserveWhitespaces: metadata.preserveWhitespaces || false, - styles: metadata.styles || EMPTY_ARRAY, - animations: metadata.animations, - directives: [], - changeDetection: metadata.changeDetection, - pipes: new Map(), - encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, - interpolation: metadata.interpolation, - viewProviders: metadata.viewProviders || null, - }; - if (meta.usesInheritance) { - addBaseDefToUndecoratedParents(type); - } - ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta); + const compiler = getCompilerFacade(); + const meta = getComponentMetadata(compiler, type, metadata); + ngComponentDef = compiler.compileComponent(angularCoreEnv, meta.templateUrl, meta.metadata); // When NgModule decorator executed, we enqueued the module definition such that // it would only dequeue and add itself as module scope to all of its declarations, @@ -98,13 +86,46 @@ export function compileComponent(type: Type, metadata: Component): void { configurable: !!ngDevMode, }); - // Add ngInjectableDef so components are reachable through the module injector by default // This is mostly to support injecting components in tests. In real application code, // components should be retrieved through the node injector, so this isn't a problem. compileInjectable(type); } +function getComponentMetadata(compiler: CompilerFacade, type: Type, metadata: Component) { + if (componentNeedsResolution(metadata)) { + const error = [`Component '${type.name}' is not resolved:`]; + if (metadata.templateUrl) { + error.push(` - templateUrl: ${metadata.templateUrl}`); + } + if (metadata.styleUrls && metadata.styleUrls.length) { + error.push(` - styleUrls: ${JSON.stringify(metadata.styleUrls)}`); + } + error.push(`Did you run and wait for 'resolveComponentResources()'?`); + throw new Error(error.join('\n')); + } + + const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`; + const meta: R3ComponentMetadataFacade = { + ...directiveMetadata(type, metadata), + typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), + template: metadata.template || '', + preserveWhitespaces: metadata.preserveWhitespaces || false, + styles: metadata.styles || EMPTY_ARRAY, + animations: metadata.animations, + directives: [], + changeDetection: metadata.changeDetection, + pipes: new Map(), + encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, + interpolation: metadata.interpolation, + viewProviders: metadata.viewProviders || null, + }; + if (meta.usesInheritance) { + addBaseDefToUndecoratedParents(type); + } + return {metadata: meta, templateUrl}; +} + function hasSelectorScope(component: Type): component is Type& {ngSelectorScope: Type} { return (component as{ngSelectorScope?: any}).ngSelectorScope !== undefined; @@ -119,21 +140,33 @@ function hasSelectorScope(component: Type): component is Type& */ export function compileDirective(type: Type, directive: Directive | null): void { let ngDirectiveDef: any = null; - Object.defineProperty(type, NG_DIRECTIVE_DEF, { + let ngFactoryDef: any = null; + + Object.defineProperty(type, NG_FACTORY_DEF, { get: () => { - if (ngDirectiveDef === null) { - const name = type && type.name; - const sourceMapUrl = `ng:///${name}/ngDirectiveDef.js`; - const compiler = getCompilerFacade(); + if (ngFactoryDef === null) { // `directive` can be null in the case of abstract directives as a base class // that use `@Directive()` with no selector. In that case, pass empty object to the // `directiveMetadata` function instead of null. - const facade = directiveMetadata(type as ComponentType, directive || {}); - facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl); - if (facade.usesInheritance) { - addBaseDefToUndecoratedParents(type); - } - ngDirectiveDef = compiler.compileDirective(angularCoreEnv, sourceMapUrl, facade); + const meta = getDirectiveMetadata(type, directive || {}); + ngFactoryDef = getCompilerFacade().compileFactory( + angularCoreEnv, `ng:///${type.name}/ngFactory.js`, meta.metadata); + } + return ngFactoryDef; + }, + // Make the property configurable in dev mode to allow overriding in tests + configurable: !!ngDevMode, + }); + + Object.defineProperty(type, NG_DIRECTIVE_DEF, { + get: () => { + if (ngDirectiveDef === null) { + // `directive` can be null in the case of abstract directives as a base class + // that use `@Directive()` with no selector. In that case, pass empty object to the + // `directiveMetadata` function instead of null. + const meta = getDirectiveMetadata(type, directive || {}); + ngDirectiveDef = + getCompilerFacade().compileDirective(angularCoreEnv, meta.sourceMapUrl, meta.metadata); } return ngDirectiveDef; }, @@ -147,6 +180,18 @@ export function compileDirective(type: Type, directive: Directive | null): compileInjectable(type); } +function getDirectiveMetadata(type: Type, metadata: Directive) { + const name = type && type.name; + const sourceMapUrl = `ng:///${name}/ngDirectiveDef.js`; + const compiler = getCompilerFacade(); + const facade = directiveMetadata(type as ComponentType, metadata); + facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name, sourceMapUrl); + if (facade.usesInheritance) { + addBaseDefToUndecoratedParents(type); + } + return {metadata: facade, sourceMapUrl}; +} + export function extendsDirectlyFromObject(type: Type): boolean { return Object.getPrototypeOf(type.prototype) === Object.prototype; } diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index 702160bf11..bc08f1f50c 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -10,25 +10,33 @@ import {getCompilerFacade} from '../../compiler/compiler_facade'; import {reflectDependencies} from '../../di/jit/util'; import {Type} from '../../interface/type'; import {Pipe} from '../../metadata/directives'; -import {NG_PIPE_DEF} from '../fields'; +import {NG_FACTORY_DEF, NG_PIPE_DEF} from '../fields'; import {angularCoreEnv} from './environment'; export function compilePipe(type: Type, meta: Pipe): void { let ngPipeDef: any = null; + let ngFactoryDef: any = null; + + Object.defineProperty(type, NG_FACTORY_DEF, { + get: () => { + if (ngFactoryDef === null) { + const metadata = getPipeMetadata(type, meta); + ngFactoryDef = getCompilerFacade().compileFactory( + angularCoreEnv, `ng:///${metadata.name}/ngFactory.js`, metadata, true); + } + return ngFactoryDef; + }, + // Make the property configurable in dev mode to allow overriding in tests + configurable: !!ngDevMode, + }); + Object.defineProperty(type, NG_PIPE_DEF, { get: () => { if (ngPipeDef === null) { - const typeName = type.name; - ngPipeDef = - getCompilerFacade().compilePipe(angularCoreEnv, `ng:///${typeName}/ngPipeDef.js`, { - type: type, - typeArgumentCount: 0, - name: typeName, - deps: reflectDependencies(type), - pipeName: meta.name, - pure: meta.pure !== undefined ? meta.pure : true - }); + const metadata = getPipeMetadata(type, meta); + ngPipeDef = getCompilerFacade().compilePipe( + angularCoreEnv, `ng:///${metadata.name}/ngPipeDef.js`, metadata); } return ngPipeDef; }, @@ -36,3 +44,14 @@ export function compilePipe(type: Type, meta: Pipe): void { configurable: !!ngDevMode, }); } + +function getPipeMetadata(type: Type, meta: Pipe) { + return { + type: type, + typeArgumentCount: 0, + name: type.name, + deps: reflectDependencies(type), + pipeName: meta.name, + pure: meta.pure !== undefined ? meta.pure : true + }; +} diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index 1caa0794d3..3b9d8bcbcb 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -9,6 +9,7 @@ import {WrappedValue} from '../change_detection/change_detection_util'; import {PipeTransform} from '../change_detection/pipe_transform'; +import {getFactoryDef} from './definition'; import {store} from './instructions/all'; import {PipeDef, PipeDefList} from './interfaces/definition'; import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view'; @@ -43,7 +44,8 @@ export function ɵɵpipe(index: number, pipeName: string): any { pipeDef = tView.data[adjustedIndex] as PipeDef; } - const pipeInstance = pipeDef.factory(); + const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true)); + const pipeInstance = pipeFactory(); store(index, pipeInstance); return pipeInstance; } diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 4e6c137884..52d861d5c2 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -81,7 +81,7 @@ "name": "NG_ELEMENT_ID" }, { - "name": "NG_INJECTABLE_DEF" + "name": "NG_FACTORY_DEF" }, { "name": "NG_PIPE_DEF" @@ -311,6 +311,9 @@ { "name": "getElementDepthCount" }, + { + "name": "getFactoryDef" + }, { "name": "getHostNative" }, @@ -674,9 +677,6 @@ { "name": "ɵɵdefineComponent" }, - { - "name": "ɵɵdefineInjectable" - }, { "name": "ɵɵdefineInjector" }, @@ -698,4 +698,4 @@ { "name": "ɵɵtext" } -] \ No newline at end of file +] diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index c1b02adcf8..7d312207b7 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -72,7 +72,7 @@ "name": "NG_ELEMENT_ID" }, { - "name": "NG_INJECTABLE_DEF" + "name": "NG_FACTORY_DEF" }, { "name": "NG_PIPE_DEF" @@ -248,6 +248,9 @@ { "name": "getDirectiveDef" }, + { + "name": "getFactoryDef" + }, { "name": "getHostNative" }, @@ -485,10 +488,7 @@ { "name": "ɵɵdefineComponent" }, - { - "name": "ɵɵdefineInjectable" - }, { "name": "ɵɵtext" } -] \ No newline at end of file +] diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index b76b2d0f03..9898bc02bb 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -26,6 +26,9 @@ { "name": "NEW_LINE" }, + { + "name": "NG_FACTORY_DEF" + }, { "name": "NG_INJECTABLE_DEF" }, @@ -116,6 +119,9 @@ { "name": "getClosureSafeProperty" }, + { + "name": "getFactoryDef" + }, { "name": "getInheritedInjectableDef" }, @@ -209,4 +215,4 @@ { "name": "ɵɵinject" } -] \ No newline at end of file +] diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 9416886463..82bc7b0319 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -134,6 +134,9 @@ { "name": "NG_ELEMENT_ID" }, + { + "name": "NG_FACTORY_DEF" + }, { "name": "NG_INJECTABLE_DEF" }, @@ -758,6 +761,9 @@ { "name": "getErrorLogger" }, + { + "name": "getFactoryDef" + }, { "name": "getGuardMask" }, @@ -1451,4 +1457,4 @@ { "name": "ɵɵtextInterpolate1" } -] \ No newline at end of file +] diff --git a/packages/core/test/render3/basic_perf.ts b/packages/core/test/render3/basic_perf.ts index b0595447dc..c1c9d55081 100644 --- a/packages/core/test/render3/basic_perf.ts +++ b/packages/core/test/render3/basic_perf.ts @@ -33,6 +33,7 @@ describe('iv perf test', () => { it(`${iteration}. create ${count} divs in Render3`, () => { class Component { + static ngFactoryDef = () => new Component; static ngComponentDef = ɵɵdefineComponent({ type: Component, selectors: [['div']], @@ -59,8 +60,7 @@ describe('iv perf test', () => { } ɵɵcontainerRefreshEnd(); } - }, - factory: () => new Component + } }); } diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts index 4fc04fdda0..d5214e7a85 100644 --- a/packages/core/test/render3/change_detection_spec.ts +++ b/packages/core/test/render3/change_detection_spec.ts @@ -25,10 +25,10 @@ describe('change detection', () => { doCheckCount = 0; ngDoCheck(): void { this.doCheckCount++; } + static ngFactoryDef = () => new MyComponent(); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], - factory: () => new MyComponent(), consts: 2, vars: 1, template: (rf: RenderFlags, ctx: MyComponent) => { @@ -101,10 +101,10 @@ describe('change detection', () => { onClick() {} + static ngFactoryDef = () => comp = new MyComponent(); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], - factory: () => comp = new MyComponent(), consts: 2, vars: 2, /** @@ -140,10 +140,10 @@ describe('change detection', () => { onClick() {} + static ngFactoryDef = () => comp = new ManualComponent(); static ngComponentDef = ɵɵdefineComponent({ type: ManualComponent, selectors: [['manual-comp']], - factory: () => comp = new ManualComponent(), consts: 2, vars: 2, /** @@ -177,10 +177,10 @@ describe('change detection', () => { class ManualApp { name: string = 'Nancy'; + static ngFactoryDef = () => new ManualApp(); static ngComponentDef = ɵɵdefineComponent({ type: ManualApp, selectors: [['manual-app']], - factory: () => new ManualApp(), consts: 1, vars: 1, /** */ @@ -233,10 +233,10 @@ describe('change detection', () => { doCheckCount = 0; ngDoCheck(): void { this.doCheckCount++; } + static ngFactoryDef = () => parent = new ButtonParent(); static ngComponentDef = ɵɵdefineComponent({ type: ButtonParent, selectors: [['button-parent']], - factory: () => parent = new ButtonParent(), consts: 2, vars: 1, /** {{ doCheckCount }} - */ @@ -311,10 +311,10 @@ describe('change detection', () => { return 'works'; } + static ngFactoryDef = () => new MyComponent(); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], - factory: () => new MyComponent(), consts: 1, vars: 1, template: (rf: RenderFlags, ctx: MyComponent) => { diff --git a/packages/core/test/render3/common_with_def.ts b/packages/core/test/render3/common_with_def.ts index 6e08c7ef43..e77c2970a0 100644 --- a/packages/core/test/render3/common_with_def.ts +++ b/packages/core/test/render3/common_with_def.ts @@ -18,9 +18,6 @@ export const NgTemplateOutlet: DirectiveType = NgTemplateOu NgForOf.ngDirectiveDef = ɵɵdefineDirective({ type: NgForOfDef, selectors: [['', 'ngForOf', '']], - factory: () => new NgForOfDef( - ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any), - ɵɵdirectiveInject(IterableDiffers)), inputs: { ngForOf: 'ngForOf', ngForTrackBy: 'ngForTrackBy', @@ -28,19 +25,26 @@ NgForOf.ngDirectiveDef = ɵɵdefineDirective({ } }); -(NgIf as any).ngDirectiveDef = ɵɵdefineDirective({ +NgForOf.ngFactoryDef = () => new NgForOfDef( + ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any), + ɵɵdirectiveInject(IterableDiffers)); + +NgIf.ngDirectiveDef = ɵɵdefineDirective({ type: NgIfDef, selectors: [['', 'ngIf', '']], - factory: () => new NgIfDef( - ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any)), inputs: {ngIf: 'ngIf', ngIfThen: 'ngIfThen', ngIfElse: 'ngIfElse'} }); -(NgTemplateOutlet as any).ngDirectiveDef = ɵɵdefineDirective({ +NgIf.ngFactoryDef = () => + new NgIfDef(ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any)); + +NgTemplateOutlet.ngDirectiveDef = ɵɵdefineDirective({ type: NgTemplateOutletDef, selectors: [['', 'ngTemplateOutlet', '']], - factory: () => new NgTemplateOutletDef(ɵɵdirectiveInject(ViewContainerRef as any)), features: [ɵɵNgOnChangesFeature()], inputs: {ngTemplateOutlet: 'ngTemplateOutlet', ngTemplateOutletContext: 'ngTemplateOutletContext'} }); + +NgTemplateOutlet.ngFactoryDef = () => + new NgTemplateOutletDef(ɵɵdirectiveInject(ViewContainerRef as any)); diff --git a/packages/core/test/render3/component_ref_spec.ts b/packages/core/test/render3/component_ref_spec.ts index cf85556cf2..10894f2f4d 100644 --- a/packages/core/test/render3/component_ref_spec.ts +++ b/packages/core/test/render3/component_ref_spec.ts @@ -20,13 +20,13 @@ describe('ComponentFactory', () => { describe('constructor()', () => { it('should correctly populate default properties', () => { class TestComponent { + static ngFactoryDef = () => new TestComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestComponent, selectors: [['test', 'foo'], ['bar']], consts: 0, vars: 0, template: () => undefined, - factory: () => new TestComponent(), }); } @@ -41,6 +41,7 @@ describe('ComponentFactory', () => { it('should correctly populate defined properties', () => { class TestComponent { + static ngFactoryDef = () => new TestComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestComponent, encapsulation: ViewEncapsulation.None, @@ -49,7 +50,6 @@ describe('ComponentFactory', () => { vars: 0, template: () => undefined, ngContentSelectors: ['*', 'a', 'b'], - factory: () => new TestComponent(), inputs: { in1: 'in1', in2: ['input-attr-2', 'in2'], @@ -89,6 +89,7 @@ describe('ComponentFactory', () => { createRenderer3Spy = spyOn(domRendererFactory3, 'createRenderer').and.callThrough(); class TestComponent { + static ngFactoryDef = () => new TestComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestComponent, encapsulation: ViewEncapsulation.None, @@ -96,7 +97,6 @@ describe('ComponentFactory', () => { consts: 0, vars: 0, template: () => undefined, - factory: () => new TestComponent(), }); } diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index 945524057a..267ebd2dda 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -21,6 +21,7 @@ describe('component', () => { increment() { this.count++; } + static ngFactoryDef = () => new CounterComponent; static ngComponentDef = ɵɵdefineComponent({ type: CounterComponent, encapsulation: ViewEncapsulation.None, @@ -36,7 +37,6 @@ describe('component', () => { ɵɵtextBinding(ctx.count); } }, - factory: () => new CounterComponent, inputs: {count: 'count'}, }); } @@ -72,11 +72,11 @@ describe('component', () => { } class MyComponent { constructor(public myService: MyService) {} + static ngFactoryDef = () => new MyComponent(ɵɵdirectiveInject(MyService)); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, encapsulation: ViewEncapsulation.None, selectors: [['my-component']], - factory: () => new MyComponent(ɵɵdirectiveInject(MyService)), consts: 1, vars: 1, template: function(fs: RenderFlags, ctx: MyComponent) { @@ -117,10 +117,10 @@ describe('component', () => { // @Input name = ''; + static ngFactoryDef = () => new Comp(); static ngComponentDef = ɵɵdefineComponent({ type: Comp, selectors: [['comp']], - factory: () => new Comp(), consts: 1, vars: 1, template: (rf: RenderFlags, ctx: Comp) => { @@ -172,15 +172,17 @@ it('should not invoke renderer destroy method for embedded views', () => { class Comp { visible = true; + static ngFactoryDef = + () => { + comp = new Comp(); + return comp; + } + static ngComponentDef = ɵɵdefineComponent({ type: Comp, selectors: [['comp']], consts: 3, vars: 1, - factory: () => { - comp = new Comp(); - return comp; - }, directives: [NgIf], /** *
Root view
@@ -248,6 +250,7 @@ describe('component with a container', () => { class WrapperComponent { // TODO(issue/24571): remove '!'. items !: string[]; + static ngFactoryDef = () => new WrapperComponent; static ngComponentDef = ɵɵdefineComponent({ type: WrapperComponent, encapsulation: ViewEncapsulation.None, @@ -268,7 +271,6 @@ describe('component with a container', () => { ɵɵcontainerRefreshEnd(); } }, - factory: () => new WrapperComponent, inputs: {items: 'items'} }); } @@ -326,11 +328,11 @@ describe('recursive components', () => { ngOnDestroy() { events.push('destroy' + this.data.value); } + static ngFactoryDef = () => new TreeComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TreeComponent, encapsulation: ViewEncapsulation.None, selectors: [['tree-comp']], - factory: () => new TreeComponent(), consts: 3, vars: 1, template: (rf: RenderFlags, ctx: TreeComponent) => { @@ -393,11 +395,11 @@ describe('recursive components', () => { ngOnDestroy() { events.push('destroy' + this.data.value); } + static ngFactoryDef = () => new NgIfTree(); static ngComponentDef = ɵɵdefineComponent({ type: NgIfTree, encapsulation: ViewEncapsulation.None, selectors: [['ng-if-tree']], - factory: () => new NgIfTree(), consts: 3, vars: 3, template: (rf: RenderFlags, ctx: NgIfTree) => { @@ -543,6 +545,7 @@ describe('recursive components', () => { class TestInputsComponent { // TODO(issue/24571): remove '!'. minifiedName !: string; + static ngFactoryDef = () => new TestInputsComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestInputsComponent, encapsulation: ViewEncapsulation.None, @@ -550,7 +553,6 @@ describe('recursive components', () => { inputs: {minifiedName: 'unminifiedName'}, consts: 0, vars: 0, - factory: () => new TestInputsComponent(), template: function(rf: RenderFlags, ctx: TestInputsComponent): void { // Template not needed for this test } diff --git a/packages/core/test/render3/control_flow_spec.ts b/packages/core/test/render3/control_flow_spec.ts index 7e3257e1c1..98d25fb990 100644 --- a/packages/core/test/render3/control_flow_spec.ts +++ b/packages/core/test/render3/control_flow_spec.ts @@ -692,15 +692,17 @@ describe('JS control flow', () => { // Intentionally duplicating the templates in test below so we are // testing the behavior on firstTemplatePass for each of these tests class Comp { + static ngFactoryDef = + () => { + log.push('comp!'); + return new Comp(); + } + static ngComponentDef = ɵɵdefineComponent({ type: Comp, selectors: [['comp']], consts: 0, vars: 0, - factory: () => { - log.push('comp!'); - return new Comp(); - }, template: function(rf: RenderFlags, ctx: Comp) {} }); } @@ -709,10 +711,10 @@ describe('JS control flow', () => { condition = true; condition2 = true; + static ngFactoryDef = () => new App(); static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], - factory: () => new App(), consts: 3, vars: 0, template: function(rf: RenderFlags, ctx: any) { @@ -760,15 +762,17 @@ describe('JS control flow', () => { // Intentionally duplicating the templates from above so we are // testing the behavior on firstTemplatePass for each of these tests class Comp { + static ngFactoryDef = + () => { + log.push('comp!'); + return new Comp(); + } + static ngComponentDef = ɵɵdefineComponent({ type: Comp, selectors: [['comp']], consts: 0, vars: 0, - factory: () => { - log.push('comp!'); - return new Comp(); - }, template: function(rf: RenderFlags, ctx: Comp) {} }); } @@ -777,10 +781,10 @@ describe('JS control flow', () => { condition = false; condition2 = true; + static ngFactoryDef = () => new App(); static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], - factory: () => new App(), consts: 3, vars: 0, template: function(rf: RenderFlags, ctx: any) { diff --git a/packages/core/test/render3/debug_spec.ts b/packages/core/test/render3/debug_spec.ts index 35937c0c61..e636486736 100644 --- a/packages/core/test/render3/debug_spec.ts +++ b/packages/core/test/render3/debug_spec.ts @@ -15,12 +15,12 @@ import {ComponentFixture} from './render_util'; describe('Debug Representation', () => { it('should generate a human readable version', () => { class MyComponent { + static ngFactoryDef = () => new MyComponent(); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], vars: 0, consts: 2, - factory: () => new MyComponent(), template: function(rf: RenderFlags, ctx: MyComponent) { if (rf == RenderFlags.Create) { ɵɵelementStart(0, 'div', ['id', '123']); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 7910eab2b5..b9e825aae5 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -31,12 +31,9 @@ describe('di', () => { value = 'DirB'; constructor() { log.push(this.value); } - static ngDirectiveDef = ɵɵdefineDirective({ - selectors: [['', 'dirB', '']], - type: DirB, - factory: () => new DirB(), - inputs: {value: 'value'} - }); + static ngFactoryDef = () => new DirB(); + static ngDirectiveDef = + ɵɵdefineDirective({selectors: [['', 'dirB', '']], type: DirB, inputs: {value: 'value'}}); } beforeEach(() => log = []); @@ -49,11 +46,8 @@ describe('di', () => { class DirA { constructor(dir: DirB) { log.push(`DirA (dep: ${dir.value})`); } - static ngDirectiveDef = ɵɵdefineDirective({ - selectors: [['', 'dirA', '']], - type: DirA, - factory: () => new DirA(ɵɵdirectiveInject(DirB)) - }); + static ngFactoryDef = () => new DirA(ɵɵdirectiveInject(DirB)); + static ngDirectiveDef = ɵɵdefineDirective({selectors: [['', 'dirA', '']], type: DirA}); } /** @@ -92,13 +86,11 @@ describe('di', () => { this.injector = vcr.injector; } - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirA, - selectors: [['', 'dirA', '']], - factory: - () => new DirA(ɵɵdirectiveInject(DirB), ɵɵdirectiveInject(ViewContainerRef as any)), - exportAs: ['dirA'] - }); + static ngFactoryDef = () => new DirA( + ɵɵdirectiveInject(DirB), ɵɵdirectiveInject(ViewContainerRef as any)) + + static ngDirectiveDef = + ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']], exportAs: ['dirA']}); } /** @@ -171,12 +163,9 @@ describe('di', () => { // TODO(issue/24571): remove '!'. value !: string; - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirB, - selectors: [['', 'dirB', '']], - factory: () => new DirB(), - inputs: {value: 'dirB'} - }); + static ngFactoryDef = () => new DirB(); + static ngDirectiveDef = + ɵɵdefineDirective({type: DirB, selectors: [['', 'dirB', '']], inputs: {value: 'dirB'}}); } describe('Optional', () => { @@ -185,11 +174,13 @@ describe('di', () => { class DirA { constructor(@Optional() public dirB: DirB|null) {} - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirA, - selectors: [['', 'dirA', '']], - factory: () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Optional)) - }); + static ngFactoryDef = + () => { + dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Optional)); + return dirA; + } + + static ngDirectiveDef = ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']]}); } beforeEach(() => dirA = null); @@ -214,11 +205,8 @@ describe('di', () => { class DirA { constructor(@Self() public dirB: DirB) {} - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirA, - selectors: [['', 'dirA', '']], - factory: () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Self)) - }); + static ngFactoryDef = () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Self)); + static ngDirectiveDef = ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']]}); } const DirC = createDirective('dirC'); @@ -251,11 +239,8 @@ describe('di', () => { class DirA { constructor(@Host() public dirB: DirB) {} - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirA, - selectors: [['', 'dirA', '']], - factory: () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Host)) - }); + static ngFactoryDef = () => dirA = new DirA(ɵɵdirectiveInject(DirB, InjectFlags.Host)); + static ngDirectiveDef = ɵɵdefineDirective({type: DirA, selectors: [['', 'dirA', '']]}); } /** @@ -319,10 +304,10 @@ describe('di', () => { class MyComp { constructor(public cdr: ChangeDetectorRef) {} + static ngFactoryDef = () => comp = new MyComp(ɵɵdirectiveInject(ChangeDetectorRef as any)); static ngComponentDef = ɵɵdefineComponent({ type: MyComp, selectors: [['my-comp']], - factory: () => comp = new MyComp(ɵɵdirectiveInject(ChangeDetectorRef as any)), consts: 1, vars: 0, template: function(rf: RenderFlags, ctx: MyComp) { @@ -339,23 +324,24 @@ describe('di', () => { constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; } - static ngDirectiveDef = ɵɵdefineDirective({ - type: Directive, - selectors: [['', 'dir', '']], - factory: () => dir = new Directive(ɵɵdirectiveInject(ChangeDetectorRef as any)), - exportAs: ['dir'] - }); + static ngFactoryDef = + () => { + dir = new Directive(ɵɵdirectiveInject(ChangeDetectorRef as any)); + return dir; + } + + static ngDirectiveDef = + ɵɵdefineDirective({type: Directive, selectors: [['', 'dir', '']], exportAs: ['dir']}); } class DirectiveSameInstance { constructor(public cdr: ChangeDetectorRef) {} - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirectiveSameInstance, - selectors: [['', 'dirSame', '']], - factory: () => dirSameInstance = - new DirectiveSameInstance(ɵɵdirectiveInject(ChangeDetectorRef as any)) - }); + static ngFactoryDef = () => dirSameInstance = + new DirectiveSameInstance(ɵɵdirectiveInject(ChangeDetectorRef as any)) + + static ngDirectiveDef = ɵɵdefineDirective( + {type: DirectiveSameInstance, selectors: [['', 'dirSame', '']]}); } const directives = [MyComp, Directive, DirectiveSameInstance]; @@ -371,10 +357,10 @@ describe('di', () => { constructor(public cdr: ChangeDetectorRef) {} + static ngFactoryDef = () => new MyApp(ɵɵdirectiveInject(ChangeDetectorRef as any)); static ngComponentDef = ɵɵdefineComponent({ type: MyApp, selectors: [['my-app']], - factory: () => new MyApp(ɵɵdirectiveInject(ChangeDetectorRef as any)), consts: 1, vars: 0, /** @@ -426,10 +412,10 @@ describe('di', () => { class MyComp { constructor(public renderer: Renderer2) {} + static ngFactoryDef = () => new MyComp(ɵɵdirectiveInject(Renderer2 as any)); static ngComponentDef = ɵɵdefineComponent({ type: MyComp, selectors: [['my-comp']], - factory: () => new MyComp(ɵɵdirectiveInject(Renderer2 as any)), consts: 1, vars: 0, template: function(rf: RenderFlags, ctx: MyComp) { @@ -537,24 +523,22 @@ describe('di', () => { class ChildDirective { value: string; constructor(public parent: any) { this.value = (parent.constructor as any).name; } - static ngDirectiveDef = ɵɵdefineDirective({ - type: ChildDirective, - selectors: [['', 'childDir', '']], - factory: () => new ChildDirective(ɵɵdirectiveInject(ParentDirective)), - exportAs: ['childDir'] - }); + static ngFactoryDef = () => new ChildDirective(ɵɵdirectiveInject(ParentDirective)); + static ngDirectiveDef = ɵɵdefineDirective( + {type: ChildDirective, selectors: [['', 'childDir', '']], exportAs: ['childDir']}); } class Child2Directive { value: boolean; constructor(parent: any, child: ChildDirective) { this.value = parent === child.parent; } - static ngDirectiveDef = ɵɵdefineDirective({ - selectors: [['', 'child2Dir', '']], - type: Child2Directive, - factory: () => new Child2Directive( - ɵɵdirectiveInject(ParentDirective), ɵɵdirectiveInject(ChildDirective)), - exportAs: ['child2Dir'] - }); + static ngFactoryDef = () => new Child2Directive( + ɵɵdirectiveInject(ParentDirective), ɵɵdirectiveInject(ChildDirective)) + + static ngDirectiveDef = ɵɵdefineDirective({ + selectors: [['', 'child2Dir', '']], + type: Child2Directive, + exportAs: ['child2Dir'] + }); } /** diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index 7f7da03ece..27da6ea68e 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -272,10 +272,10 @@ describe('instructions', () => { class NestedLoops { rows = [['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B']]; + static ngFactoryDef = function ToDoAppComponent_Factory() { return new NestedLoops(); }; static ngComponentDef = ɵɵdefineComponent({ type: NestedLoops, selectors: [['nested-loops']], - factory: function ToDoAppComponent_Factory() { return new NestedLoops(); }, consts: 1, vars: 1, template: function ToDoAppComponent_Template(rf: RenderFlags, ctx: NestedLoops) { diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index a4bf661d4c..a5ac1b3703 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -117,6 +117,8 @@ describe('render3 integration test', () => { beforeTree !: Tree; // TODO(issue/24571): remove '!'. afterTree !: Tree; + + static ngFactoryDef = () => new ChildComponent; static ngComponentDef = ɵɵdefineComponent({ selectors: [['child']], type: ChildComponent, @@ -147,7 +149,6 @@ describe('render3 integration test', () => { ɵɵcontainerRefreshEnd(); } }, - factory: () => new ChildComponent, inputs: {beforeTree: 'beforeTree', afterTree: 'afterTree'} }); } @@ -200,6 +201,7 @@ describe('render3 integration test', () => { describe('component styles', () => { it('should pass in the component styles directly into the underlying renderer', () => { class StyledComp { + static ngFactoryDef = () => new StyledComp(); static ngComponentDef = ɵɵdefineComponent({ type: StyledComp, styles: ['div { color: red; }'], @@ -207,7 +209,6 @@ describe('component styles', () => { vars: 0, encapsulation: 100, selectors: [['foo']], - factory: () => new StyledComp(), template: (rf: RenderFlags, ctx: StyledComp) => { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div'); @@ -228,6 +229,7 @@ describe('component animations', () => { const animB = {name: 'b'}; class AnimComp { + static ngFactoryDef = () => new AnimComp(); static ngComponentDef = ɵɵdefineComponent({ type: AnimComp, consts: 0, @@ -239,7 +241,6 @@ describe('component animations', () => { ], }, selectors: [['foo']], - factory: () => new AnimComp(), template: (rf: RenderFlags, ctx: AnimComp) => {} }); } @@ -255,6 +256,7 @@ describe('component animations', () => { it('should include animations in the renderType data array even if the array is empty', () => { class AnimComp { + static ngFactoryDef = () => new AnimComp(); static ngComponentDef = ɵɵdefineComponent({ type: AnimComp, consts: 0, @@ -263,7 +265,6 @@ describe('component animations', () => { animation: [], }, selectors: [['foo']], - factory: () => new AnimComp(), template: (rf: RenderFlags, ctx: AnimComp) => {} }); } @@ -275,12 +276,12 @@ describe('component animations', () => { it('should allow [@trigger] bindings to be picked up by the underlying renderer', () => { class AnimComp { + static ngFactoryDef = () => new AnimComp(); static ngComponentDef = ɵɵdefineComponent({ type: AnimComp, consts: 1, vars: 1, selectors: [['foo']], - factory: () => new AnimComp(), template: (rf: RenderFlags, ctx: AnimComp) => { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', [AttributeMarker.Bindings, '@fooAnimation']); @@ -312,12 +313,12 @@ describe('component animations', () => { it('should allow creation-level [@trigger] properties to be picked up by the underlying renderer', () => { class AnimComp { + static ngFactoryDef = () => new AnimComp(); static ngComponentDef = ɵɵdefineComponent({ type: AnimComp, consts: 1, vars: 1, selectors: [['foo']], - factory: () => new AnimComp(), template: (rf: RenderFlags, ctx: AnimComp) => { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', ['@fooAnimation', '']); @@ -345,9 +346,9 @@ describe('component animations', () => { // it('should allow host binding animations to be picked up and rendered', () => { // class ChildCompWithAnim { + // static ngFactoryDef = () => new ChildCompWithAnim(); // static ngDirectiveDef = ɵɵdefineDirective({ // type: ChildCompWithAnim, - // factory: () => new ChildCompWithAnim(), // selectors: [['child-comp-with-anim']], // hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void { // if (rf & RenderFlags.Update) { @@ -360,12 +361,12 @@ describe('component animations', () => { // } // class ParentComp { + // static ngFactoryDef = () => new ParentComp(); // static ngComponentDef = ɵɵdefineComponent({ // type: ParentComp, // consts: 1, // vars: 1, // selectors: [['foo']], - // factory: () => new ParentComp(), // template: (rf: RenderFlags, ctx: ParentComp) => { // if (rf & RenderFlags.Create) { // ɵɵelement(0, 'child-comp-with-anim'); @@ -390,10 +391,10 @@ describe('component animations', () => { describe('element discovery', () => { it('should only monkey-patch immediate child nodes in a component', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -422,10 +423,10 @@ describe('element discovery', () => { it('should only monkey-patch immediate child nodes in a sub component', () => { class ChildComp { + static ngFactoryDef = () => new ChildComp(); static ngComponentDef = ɵɵdefineComponent({ type: ChildComp, selectors: [['child-comp']], - factory: () => new ChildComp(), consts: 3, vars: 0, template: (rf: RenderFlags, ctx: ChildComp) => { @@ -439,11 +440,11 @@ describe('element discovery', () => { } class ParentComp { + static ngFactoryDef = () => new ParentComp(); static ngComponentDef = ɵɵdefineComponent({ type: ParentComp, selectors: [['parent-comp']], directives: [ChildComp], - factory: () => new ParentComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: ParentComp) => { @@ -472,11 +473,11 @@ describe('element discovery', () => { it('should only monkey-patch immediate child nodes in an embedded template container', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], directives: [NgIf], - factory: () => new StructuredComp(), consts: 2, vars: 1, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -521,11 +522,11 @@ describe('element discovery', () => { it('should return a context object from a given dom node', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], directives: [NgIf], - factory: () => new StructuredComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -559,10 +560,10 @@ describe('element discovery', () => { it('should cache the element context on a element was pre-emptively monkey-patched', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -591,10 +592,10 @@ describe('element discovery', () => { it('should cache the element context on an intermediate element that isn\'t pre-emptively monkey-patched', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -624,10 +625,10 @@ describe('element discovery', () => { it('should be able to pull in element context data even if the element is decorated using styling', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -677,10 +678,10 @@ describe('element discovery', () => { */ class ProjectorComp { + static ngFactoryDef = () => new ProjectorComp(); static ngComponentDef = ɵɵdefineComponent({ type: ProjectorComp, selectors: [['projector-comp']], - factory: () => new ProjectorComp(), consts: 4, vars: 0, template: (rf: RenderFlags, ctx: ProjectorComp) => { @@ -700,11 +701,11 @@ describe('element discovery', () => { } class ParentComp { + static ngFactoryDef = () => new ParentComp(); static ngComponentDef = ɵɵdefineComponent({ type: ParentComp, selectors: [['parent-comp']], directives: [ProjectorComp], - factory: () => new ParentComp(), consts: 5, vars: 0, template: (rf: RenderFlags, ctx: ParentComp) => { @@ -774,10 +775,10 @@ describe('element discovery', () => { it('should return `null` when an element context is retrieved that is a DOM node that was not created by Angular', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -801,10 +802,10 @@ describe('element discovery', () => { it('should by default monkey-patch the bootstrap component with context details', () => { class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], - factory: () => new StructuredComp(), consts: 0, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => {} @@ -840,35 +841,29 @@ describe('element discovery', () => { let myDir3Instance: MyDir2|null = null; class MyDir1 { - static ngDirectiveDef = ɵɵdefineDirective({ - type: MyDir1, - selectors: [['', 'my-dir-1', '']], - factory: () => myDir1Instance = new MyDir1() - }); + static ngFactoryDef = () => myDir1Instance = new MyDir1(); + static ngDirectiveDef = + ɵɵdefineDirective({type: MyDir1, selectors: [['', 'my-dir-1', '']]}); } class MyDir2 { - static ngDirectiveDef = ɵɵdefineDirective({ - type: MyDir2, - selectors: [['', 'my-dir-2', '']], - factory: () => myDir2Instance = new MyDir2() - }); + static ngFactoryDef = () => myDir2Instance = new MyDir2(); + static ngDirectiveDef = + ɵɵdefineDirective({type: MyDir2, selectors: [['', 'my-dir-2', '']]}); } class MyDir3 { - static ngDirectiveDef = ɵɵdefineDirective({ - type: MyDir3, - selectors: [['', 'my-dir-3', '']], - factory: () => myDir3Instance = new MyDir2() - }); + static ngFactoryDef = () => myDir3Instance = new MyDir2(); + static ngDirectiveDef = + ɵɵdefineDirective({type: MyDir3, selectors: [['', 'my-dir-3', '']]}); } class StructuredComp { + static ngFactoryDef = () => new StructuredComp(); static ngComponentDef = ɵɵdefineComponent({ type: StructuredComp, selectors: [['structured-comp']], directives: [MyDir1, MyDir2, MyDir3], - factory: () => new StructuredComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: StructuredComp) => { @@ -929,26 +924,22 @@ describe('element discovery', () => { let childComponentInstance: ChildComp|null = null; class MyDir1 { - static ngDirectiveDef = ɵɵdefineDirective({ - type: MyDir1, - selectors: [['', 'my-dir-1', '']], - factory: () => myDir1Instance = new MyDir1() - }); + static ngFactoryDef = () => myDir1Instance = new MyDir1(); + static ngDirectiveDef = + ɵɵdefineDirective({type: MyDir1, selectors: [['', 'my-dir-1', '']]}); } class MyDir2 { - static ngDirectiveDef = ɵɵdefineDirective({ - type: MyDir2, - selectors: [['', 'my-dir-2', '']], - factory: () => myDir2Instance = new MyDir2() - }); + static ngFactoryDef = () => myDir2Instance = new MyDir2(); + static ngDirectiveDef = + ɵɵdefineDirective({type: MyDir2, selectors: [['', 'my-dir-2', '']]}); } class ChildComp { + static ngFactoryDef = () => childComponentInstance = new ChildComp(); static ngComponentDef = ɵɵdefineComponent({ type: ChildComp, selectors: [['child-comp']], - factory: () => childComponentInstance = new ChildComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: ChildComp) => { @@ -960,11 +951,11 @@ describe('element discovery', () => { } class ParentComp { + static ngFactoryDef = () => new ParentComp(); static ngComponentDef = ɵɵdefineComponent({ type: ParentComp, selectors: [['parent-comp']], directives: [ChildComp, MyDir1, MyDir2], - factory: () => new ParentComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: ParentComp) => { @@ -1022,10 +1013,10 @@ describe('element discovery', () => { it('should monkey-patch sub components with the view data and then replace them with the context result once a lookup occurs', () => { class ChildComp { + static ngFactoryDef = () => new ChildComp(); static ngComponentDef = ɵɵdefineComponent({ type: ChildComp, selectors: [['child-comp']], - factory: () => new ChildComp(), consts: 3, vars: 0, template: (rf: RenderFlags, ctx: ChildComp) => { @@ -1039,11 +1030,11 @@ describe('element discovery', () => { } class ParentComp { + static ngFactoryDef = () => new ParentComp(); static ngComponentDef = ɵɵdefineComponent({ type: ParentComp, selectors: [['parent-comp']], directives: [ChildComp], - factory: () => new ParentComp(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: ParentComp) => { @@ -1083,10 +1074,10 @@ describe('element discovery', () => { describe('sanitization', () => { it('should sanitize data using the provided sanitization interface', () => { class SanitizationComp { + static ngFactoryDef = () => new SanitizationComp(); static ngComponentDef = ɵɵdefineComponent({ type: SanitizationComp, selectors: [['sanitize-this']], - factory: () => new SanitizationComp(), consts: 1, vars: 1, template: (rf: RenderFlags, ctx: SanitizationComp) => { @@ -1126,10 +1117,10 @@ describe('sanitization', () => { // @HostBinding() cite: any = 'http://cite-dir-value'; + static ngFactoryDef = () => hostBindingDir = new UnsafeUrlHostBindingDir(); static ngDirectiveDef = ɵɵdefineDirective({ type: UnsafeUrlHostBindingDir, selectors: [['', 'unsafeUrlHostBindingDir', '']], - factory: () => hostBindingDir = new UnsafeUrlHostBindingDir(), hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => { if (rf & RenderFlags.Create) { ɵɵallocHostVars(1); @@ -1143,10 +1134,10 @@ describe('sanitization', () => { } class SimpleComp { + static ngFactoryDef = () => new SimpleComp(); static ngComponentDef = ɵɵdefineComponent({ type: SimpleComp, selectors: [['sanitize-this']], - factory: () => new SimpleComp(), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: SimpleComp) => { diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index c9280808e6..874cfe4549 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -15,7 +15,7 @@ import {ivyEnabled} from '@angular/core/src/ivy_switch'; import {ContentChild, ContentChildren, ViewChild, ViewChildren} from '@angular/core/src/metadata/di'; import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives'; import {NgModule, NgModuleDef} from '@angular/core/src/metadata/ng_module'; -import {ComponentDef, PipeDef} from '@angular/core/src/render3/interfaces/definition'; +import {ComponentDef, FactoryFn, PipeDef} from '@angular/core/src/render3/interfaces/definition'; ivyEnabled && describe('render3 jit', () => { @@ -34,7 +34,7 @@ ivyEnabled && describe('render3 jit', () => { const SomeCmpAny = SomeCmp as any; expect(SomeCmpAny.ngComponentDef).toBeDefined(); - expect(SomeCmpAny.ngComponentDef.factory() instanceof SomeCmp).toBe(true); + expect(SomeCmpAny.ngFactoryDef() instanceof SomeCmp).toBe(true); }); it('compiles an injectable with a type provider', () => { @@ -242,9 +242,10 @@ ivyEnabled && describe('render3 jit', () => { } const pipeDef = (P as any).ngPipeDef as PipeDef

; + const pipeFactory = (P as any).ngFactoryDef as FactoryFn

; expect(pipeDef.name).toBe('test-pipe'); expect(pipeDef.pure).toBe(false, 'pipe should not be pure'); - expect(pipeDef.factory() instanceof P) + expect(pipeFactory() instanceof P) .toBe(true, 'factory() should create an instance of the pipe'); }); diff --git a/packages/core/test/render3/jit_environment_spec.ts b/packages/core/test/render3/jit_environment_spec.ts index 659066d30f..22af48df27 100644 --- a/packages/core/test/render3/jit_environment_spec.ts +++ b/packages/core/test/render3/jit_environment_spec.ts @@ -18,6 +18,7 @@ const INTERFACE_EXCEPTIONS = new Set([ 'ɵɵInjectorDef', 'ɵɵNgModuleDefWithMeta', 'ɵɵPipeDefWithMeta', + 'ɵɵFactoryDef', ]); describe('r3 jit environment', () => { diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index ad363512bd..377e1d6fe6 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -56,12 +56,12 @@ describe('lifecycles', () => { events.push(`${name}${this.val}`); } + static ngFactoryDef = () => new Component(); static ngComponentDef = ɵɵdefineComponent({ type: Component, selectors: [[name]], consts: consts, vars: vars, - factory: () => new Component(), inputs: {val: 'val'}, template, directives: directives }); @@ -71,8 +71,8 @@ describe('lifecycles', () => { class Directive { ngOnInit() { events.push('dir'); } - static ngDirectiveDef = ɵɵdefineDirective( - {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); + static ngFactoryDef = () => new Directive(); + static ngDirectiveDef = ɵɵdefineDirective({type: Directive, selectors: [['', 'dir', '']]}); } const directives = [Comp, Parent, ProjectedComp, Directive, NgIf]; diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index 2dab1a3acc..e71e6c9830 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -27,6 +27,13 @@ describe('event listeners', () => { onClick() { this.counter++; } + static ngFactoryDef = + () => { + let comp = new MyComp(); + comps.push(comp); + return comp; + } + static ngComponentDef = ɵɵdefineComponent({ type: MyComp, selectors: [['comp']], @@ -42,11 +49,6 @@ describe('event listeners', () => { } ɵɵelementEnd(); } - }, - factory: () => { - let comp = new MyComp(); - comps.push(comp); - return comp; } }); } @@ -58,6 +60,13 @@ describe('event listeners', () => { /* @HostListener('body:click') */ onBodyClick() { events.push('component - body:click'); } + static ngFactoryDef = + () => { + let comp = new MyCompWithGlobalListeners(); + comps.push(comp); + return comp; + } + static ngComponentDef = ɵɵdefineComponent({ type: MyCompWithGlobalListeners, selectors: [['comp']], @@ -68,11 +77,6 @@ describe('event listeners', () => { ɵɵtext(0, 'Some text'); } }, - factory: () => { - let comp = new MyCompWithGlobalListeners(); - comps.push(comp); - return comp; - }, hostBindings: function HostListenerDir_HostBindings( rf: RenderFlags, ctx: any, elIndex: number) { if (rf & RenderFlags.Create) { @@ -94,10 +98,12 @@ describe('event listeners', () => { /* @HostListener('body:click') */ onBodyClick() { events.push('directive - body:click'); } + static ngFactoryDef = function HostListenerDir_Factory() { + return new GlobalHostListenerDir(); + }; static ngDirectiveDef = ɵɵdefineDirective({ type: GlobalHostListenerDir, selectors: [['', 'hostListenerDir', '']], - factory: function HostListenerDir_Factory() { return new GlobalHostListenerDir(); }, hostBindings: function HostListenerDir_HostBindings( rf: RenderFlags, ctx: any, elIndex: number) { if (rf & RenderFlags.Create) { @@ -128,10 +134,10 @@ describe('event listeners', () => { return this.handlerReturnValue; } + static ngFactoryDef = () => new PreventDefaultComp(); static ngComponentDef = ɵɵdefineComponent({ type: PreventDefaultComp, selectors: [['prevent-default-comp']], - factory: () => new PreventDefaultComp(), consts: 2, vars: 0, /** */ @@ -319,10 +325,10 @@ describe('event listeners', () => { onClick() { this.counter++; } + static ngFactoryDef = () => new AppComp(); static ngComponentDef = ɵɵdefineComponent({ type: AppComp, selectors: [['app-comp']], - factory: () => new AppComp(), consts: 1, vars: 0, template: function(rf: RenderFlags, ctx: any) { @@ -380,10 +386,10 @@ describe('event listeners', () => { onClick(index: number) { this.counters[index]++; } + static ngFactoryDef = () => new AppComp(); static ngComponentDef = ɵɵdefineComponent({ type: AppComp, selectors: [['app-comp']], - factory: () => new AppComp(), consts: 1, vars: 0, template: function(rf: RenderFlags, ctx: any) { @@ -444,10 +450,10 @@ describe('event listeners', () => { onClick(index: number) { this.counters[index]++; } + static ngFactoryDef = () => new AppComp(); static ngComponentDef = ɵɵdefineComponent({ type: AppComp, selectors: [['app-comp']], - factory: () => new AppComp(), consts: 1, vars: 0, template: function(rf: RenderFlags, ctx: any) { @@ -523,6 +529,7 @@ describe('event listeners', () => { /* @HostListener('click') */ onClick() { events.push('click!'); } + static ngFactoryDef = () => { return new MyComp(); }; static ngComponentDef = ɵɵdefineComponent({ type: MyComp, selectors: [['comp']], @@ -533,7 +540,6 @@ describe('event listeners', () => { ɵɵtext(0, 'Some text'); } }, - factory: () => { return new MyComp(); }, hostBindings: function HostListenerDir_HostBindings( rf: RenderFlags, ctx: any, elIndex: number) { if (rf & RenderFlags.Create) { @@ -574,10 +580,10 @@ describe('event listeners', () => { /* @HostListener('click') */ onClick() { events.push('click!'); } + static ngFactoryDef = function HostListenerDir_Factory() { return new HostListenerDir(); }; static ngDirectiveDef = ɵɵdefineDirective({ type: HostListenerDir, selectors: [['', 'hostListenerDir', '']], - factory: function HostListenerDir_Factory() { return new HostListenerDir(); }, hostBindings: function HostListenerDir_HostBindings( rf: RenderFlags, ctx: any, elIndex: number) { if (rf & RenderFlags.Create) { @@ -626,6 +632,7 @@ describe('event listeners', () => { onClick(a: any, b: any) { this.counter += a + b; } + static ngFactoryDef = () => new MyComp(); static ngComponentDef = ɵɵdefineComponent({ type: MyComp, selectors: [['comp']], @@ -641,8 +648,7 @@ describe('event listeners', () => { } ɵɵelementEnd(); } - }, - factory: () => new MyComp() + } }); } @@ -907,10 +913,10 @@ describe('event listeners', () => { onClick(comp: any) { this.comp = comp; } + static ngFactoryDef = () => new App(); static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], - factory: () => new App(), consts: 3, vars: 0, template: (rf: RenderFlags, ctx: App) => { diff --git a/packages/core/test/render3/outputs_spec.ts b/packages/core/test/render3/outputs_spec.ts index 58607ea713..c1065caadf 100644 --- a/packages/core/test/render3/outputs_spec.ts +++ b/packages/core/test/render3/outputs_spec.ts @@ -21,13 +21,13 @@ describe('outputs', () => { change = new EventEmitter(); resetStream = new EventEmitter(); + static ngFactoryDef = () => buttonToggle = new ButtonToggle(); static ngComponentDef = ɵɵdefineComponent({ type: ButtonToggle, selectors: [['button-toggle']], template: function(rf: RenderFlags, ctx: any) {}, consts: 0, vars: 0, - factory: () => buttonToggle = new ButtonToggle(), outputs: {change: 'change', resetStream: 'reset'} }); } @@ -37,12 +37,9 @@ describe('outputs', () => { class OtherDir { changeStream = new EventEmitter(); - static ngDirectiveDef = ɵɵdefineDirective({ - type: OtherDir, - selectors: [['', 'otherDir', '']], - factory: () => otherDir = new OtherDir, - outputs: {changeStream: 'change'} - }); + static ngFactoryDef = () => otherDir = new OtherDir; + static ngDirectiveDef = ɵɵdefineDirective( + {type: OtherDir, selectors: [['', 'otherDir', '']], outputs: {changeStream: 'change'}}); } diff --git a/packages/core/test/render3/pipe_spec.ts b/packages/core/test/render3/pipe_spec.ts index 2decde3f74..8e01333287 100644 --- a/packages/core/test/render3/pipe_spec.ts +++ b/packages/core/test/render3/pipe_spec.ts @@ -29,12 +29,8 @@ describe('pipe', () => { class WrappingPipe implements PipeTransform { transform(value: any) { return new WrappedValue('Bar'); } - static ngPipeDef = ɵɵdefinePipe({ - name: 'wrappingPipe', - type: WrappingPipe, - factory: function WrappingPipe_Factory() { return new WrappingPipe(); }, - pure: false - }); + static ngFactoryDef = function WrappingPipe_Factory() { return new WrappingPipe(); }; + static ngPipeDef = ɵɵdefinePipe({name: 'wrappingPipe', type: WrappingPipe, pure: false}); } function createTemplate() { diff --git a/packages/core/test/render3/providers_spec.ts b/packages/core/test/render3/providers_spec.ts index 8c8d2a6131..ca5f1b8703 100644 --- a/packages/core/test/render3/providers_spec.ts +++ b/packages/core/test/render3/providers_spec.ts @@ -866,10 +866,12 @@ describe('providers', () => { class Repeated { constructor(private s: String, private n: Number) {} + static ngFactoryDef = + () => { return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); } + static ngComponentDef = ɵɵdefineComponent({ type: Repeated, selectors: [['repeated']], - factory: () => new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)), consts: 2, vars: 2, template: function(fs: RenderFlags, ctx: Repeated) { @@ -898,10 +900,10 @@ describe('providers', () => { [{provide: String, useValue: 'foo'}, {provide: Number, useValue: 2, multi: true}], }) class ComponentWithProviders { + static ngFactoryDef = () => new ComponentWithProviders(); static ngComponentDef = ɵɵdefineComponent({ type: ComponentWithProviders, selectors: [['component-with-providers']], - factory: () => new ComponentWithProviders(), consts: 2, vars: 0, template: function(fs: RenderFlags, ctx: ComponentWithProviders) { @@ -951,10 +953,12 @@ describe('providers', () => { class Repeated { constructor(private s: String, private n: Number) {} + static ngFactoryDef = + () => { return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); } + static ngComponentDef = ɵɵdefineComponent({ type: Repeated, selectors: [['repeated']], - factory: () => new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)), consts: 2, vars: 2, template: function(fs: RenderFlags, ctx: Repeated) { @@ -986,10 +990,10 @@ describe('providers', () => { viewProviders: [{provide: toString, useValue: 'foo'}], }) class ComponentWithProviders { + static ngFactoryDef = () => new ComponentWithProviders(); static ngComponentDef = ɵɵdefineComponent({ type: ComponentWithProviders, selectors: [['component-with-providers']], - factory: () => new ComponentWithProviders(), consts: 2, vars: 0, template: function(fs: RenderFlags, ctx: ComponentWithProviders) { @@ -1035,10 +1039,10 @@ describe('providers', () => { class EmbeddedComponent { constructor(private s: String) {} + static ngFactoryDef = () => new EmbeddedComponent(ɵɵdirectiveInject(String)); static ngComponentDef = ɵɵdefineComponent({ type: EmbeddedComponent, selectors: [['embedded-cmp']], - factory: () => new EmbeddedComponent(ɵɵdirectiveInject(String)), consts: 1, vars: 1, template: (rf: RenderFlags, cmp: EmbeddedComponent) => { @@ -1057,22 +1061,23 @@ describe('providers', () => { class HostComponent { constructor(public vcref: ViewContainerRef, public cfr: ComponentFactoryResolver) {} - static ngComponentDef = ɵɵdefineComponent({ - type: HostComponent, - selectors: [['host-cmp']], - factory: () => hostComponent = new HostComponent( - ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()), - consts: 1, - vars: 0, - template: (rf: RenderFlags, cmp: HostComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'foo'); - } - }, - features: [ - ɵɵProvidersFeature([{provide: String, useValue: 'From host component'}]), - ], - }); + static ngFactoryDef = () => hostComponent = new HostComponent( + ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()) + + static ngComponentDef = ɵɵdefineComponent({ + type: HostComponent, + selectors: [['host-cmp']], + consts: 1, + vars: 0, + template: (rf: RenderFlags, cmp: HostComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'foo'); + } + }, + features: [ + ɵɵProvidersFeature([{provide: String, useValue: 'From host component'}]), + ], + }); } @Component({ @@ -1082,10 +1087,10 @@ describe('providers', () => { class AppComponent { constructor() {} + static ngFactoryDef = () => new AppComponent(); static ngComponentDef = ɵɵdefineComponent({ type: AppComponent, selectors: [['app-cmp']], - factory: () => new AppComponent(), consts: 1, vars: 0, template: (rf: RenderFlags, cmp: AppComponent) => { @@ -1244,10 +1249,10 @@ describe('providers', () => { class MyComponent { constructor() {} + static ngFactoryDef = () => new MyComponent(); static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-cmp']], - factory: () => new MyComponent(), consts: 1, vars: 0, template: (rf: RenderFlags, cmp: MyComponent) => { @@ -1271,10 +1276,10 @@ describe('providers', () => { class AppComponent { constructor() {} + static ngFactoryDef = () => new AppComponent(); static ngComponentDef = ɵɵdefineComponent({ type: AppComponent, selectors: [['app-cmp']], - factory: () => new AppComponent(), consts: 1, vars: 0, template: (rf: RenderFlags, cmp: AppComponent) => { @@ -1334,10 +1339,12 @@ describe('providers', () => { class MyComponent { constructor(foo: InjectableWithLifeCycleHooks) {} + static ngFactoryDef = + () => { return new MyComponent(ɵɵdirectiveInject(InjectableWithLifeCycleHooks)); } + static ngComponentDef = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], - factory: () => new MyComponent(ɵɵdirectiveInject(InjectableWithLifeCycleHooks)), consts: 1, vars: 0, template: (rf: RenderFlags, ctx: MyComponent) => { @@ -1361,10 +1368,10 @@ describe('providers', () => { class App { public condition = true; + static ngFactoryDef = () => new App(); static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app-cmp']], - factory: () => new App(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: App) => { @@ -1436,40 +1443,40 @@ function expectProvidersScenario(defs: { } class ViewChildComponent { + static ngFactoryDef = () => testComponentInjection(defs.viewChild, new ViewChildComponent()); static ngComponentDef = ɵɵdefineComponent({ type: ViewChildComponent, selectors: [['view-child']], consts: 1, vars: 0, - factory: () => testComponentInjection(defs.viewChild, new ViewChildComponent()), template: function(fs: RenderFlags, ctx: ViewChildComponent) { if (fs & RenderFlags.Create) { ɵɵtext(0, 'view-child'); } }, features: defs.viewChild && - [ - ɵɵProvidersFeature(defs.viewChild.providers || [], defs.viewChild.viewProviders || []), - ], + [ɵɵProvidersFeature(defs.viewChild.providers || [], defs.viewChild.viewProviders || [])] }); } class ViewChildDirective { + static ngFactoryDef = () => testDirectiveInjection(defs.viewChild, new ViewChildDirective()); static ngDirectiveDef = ɵɵdefineDirective({ type: ViewChildDirective, selectors: [['view-child']], - factory: () => testDirectiveInjection(defs.viewChild, new ViewChildDirective()), features: defs.viewChild && [ɵɵProvidersFeature(defs.viewChild.directiveProviders || [])], }); } class ContentChildComponent { + static ngFactoryDef = + () => { return testComponentInjection(defs.contentChild, new ContentChildComponent()); } + static ngComponentDef = ɵɵdefineComponent({ type: ContentChildComponent, selectors: [['content-child']], consts: 1, vars: 0, - factory: () => testComponentInjection(defs.contentChild, new ContentChildComponent()), template: function(fs: RenderFlags, ctx: ParentComponent) { if (fs & RenderFlags.Create) { ɵɵtext(0, 'content-child'); @@ -1482,10 +1489,12 @@ function expectProvidersScenario(defs: { } class ContentChildDirective { + static ngFactoryDef = + () => { return testDirectiveInjection(defs.contentChild, new ContentChildDirective()); } + static ngDirectiveDef = ɵɵdefineDirective({ type: ContentChildDirective, selectors: [['content-child']], - factory: () => testDirectiveInjection(defs.contentChild, new ContentChildDirective()), features: defs.contentChild && [ɵɵProvidersFeature(defs.contentChild.directiveProviders || [])], }); @@ -1493,12 +1502,12 @@ function expectProvidersScenario(defs: { class ParentComponent { + static ngFactoryDef = () => testComponentInjection(defs.parent, new ParentComponent()); static ngComponentDef = ɵɵdefineComponent({ type: ParentComponent, selectors: [['parent']], consts: 1, vars: 0, - factory: () => testComponentInjection(defs.parent, new ParentComponent()), template: function(fs: RenderFlags, ctx: ParentComponent) { if (fs & RenderFlags.Create) { ɵɵelement(0, 'view-child'); @@ -1511,31 +1520,31 @@ function expectProvidersScenario(defs: { } class ParentDirective { + static ngFactoryDef = () => testDirectiveInjection(defs.parent, new ParentDirective()); static ngDirectiveDef = ɵɵdefineDirective({ type: ParentDirective, selectors: [['parent']], - factory: () => testDirectiveInjection(defs.parent, new ParentDirective()), features: defs.parent && [ɵɵProvidersFeature(defs.parent.directiveProviders || [])], }); } class ParentDirective2 { + static ngFactoryDef = () => testDirectiveInjection(defs.parent, new ParentDirective2()); static ngDirectiveDef = ɵɵdefineDirective({ type: ParentDirective2, selectors: [['parent']], - factory: () => testDirectiveInjection(defs.parent, new ParentDirective2()), features: defs.parent && [ɵɵProvidersFeature(defs.parent.directive2Providers || [])], }); } class App { + static ngFactoryDef = () => testComponentInjection(defs.app, new App()); static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], consts: 2, vars: 0, - factory: () => testComponentInjection(defs.app, new App()), template: function(fs: RenderFlags, ctx: App) { if (fs & RenderFlags.Create) { ɵɵelementStart(0, 'parent'); diff --git a/packages/core/test/render3/pure_function_spec.ts b/packages/core/test/render3/pure_function_spec.ts index 669b3b1050..615f6f9a64 100644 --- a/packages/core/test/render3/pure_function_spec.ts +++ b/packages/core/test/render3/pure_function_spec.ts @@ -19,10 +19,10 @@ describe('object literals', () => { // TODO(issue/24571): remove '!'. config !: {[key: string]: any}; + static ngFactoryDef = function ObjectComp_Factory() { return objectComp = new ObjectComp(); }; static ngComponentDef = ɵɵdefineComponent({ type: ObjectComp, selectors: [['object-comp']], - factory: function ObjectComp_Factory() { return objectComp = new ObjectComp(); }, consts: 0, vars: 1, template: function ObjectComp_Template() {}, diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 1fa1fc016c..0bfc516aa8 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -217,12 +217,12 @@ describe('query', () => { class MyDirective { constructor(public service: Service) {} + static ngFactoryDef = function MyDirective_Factory() { + return directive = new MyDirective(ɵɵdirectiveInject(Service)); + }; static ngDirectiveDef = ɵɵdefineDirective({ type: MyDirective, selectors: [['', 'myDir', '']], - factory: function MyDirective_Factory() { - return directive = new MyDirective(ɵɵdirectiveInject(Service)); - }, features: [ɵɵProvidersFeature([Service, {provide: Alias, useExisting: Service}])], }); } @@ -245,12 +245,12 @@ describe('query', () => { service?: Service; alias?: Alias; + static ngFactoryDef = function App_Factory() { return new App(); }; static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], consts: 1, vars: 0, - factory: function App_Factory() { return new App(); }, template: function App_Template(rf: RenderFlags, ctx: App) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', ['myDir']); @@ -290,12 +290,12 @@ describe('query', () => { class App { service?: Service; + static ngFactoryDef = function App_Factory() { return new App(); }; static ngComponentDef = ɵɵdefineComponent({ type: App, selectors: [['app']], consts: 1, vars: 0, - factory: function App_Factory() { return new App(); }, template: function App_Template(rf: RenderFlags, ctx: App) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'div', ['myDir']); @@ -833,10 +833,10 @@ describe('query', () => { let childInstance: Child; class Child { + static ngFactoryDef = () => childInstance = new Child(); static ngComponentDef = ɵɵdefineComponent({ type: Child, selectors: [['child']], - factory: () => childInstance = new Child(), consts: 0, vars: 0, template: (rf: RenderFlags, ctx: Child) => {}, @@ -1406,13 +1406,13 @@ describe('query', () => { this.vcr.createEmbeddedView(this.temp); } - static ngDirectiveDef = ɵɵdefineDirective({ - type: SomeDir, - selectors: [['', 'someDir', '']], - factory: - () => new SomeDir( - ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any)) - }); + static ngFactoryDef = () => new SomeDir( + ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any)) + + static ngDirectiveDef = ɵɵdefineDirective({ + type: SomeDir, + selectors: [['', 'someDir', '']], + }); } function AppComponent_Template_1(rf: RenderFlags, ctx: any) { @@ -1467,10 +1467,10 @@ describe('query', () => { this.contentCheckedQuerySnapshot = this.foos ? this.foos.length : 0; } + static ngFactoryDef = () => withContentInstance = new WithContentDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: WithContentDirective, selectors: [['', 'with-content', '']], - factory: () => withContentInstance = new WithContentDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { if (rf & RenderFlags.Create) { ɵɵcontentQuery(dirIndex, ['foo'], true); @@ -1655,11 +1655,11 @@ describe('query', () => { it('should report results to appropriate queries where deep content queries are nested', () => { class QueryDirective { fooBars: any; + static ngFactoryDef = () => new QueryDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - factory: () => new QueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren('foo, bar, baz', {descendants: true}) // fooBars: QueryList; @@ -1720,11 +1720,11 @@ describe('query', () => { class QueryDirective { fooBars: any; + static ngFactoryDef = () => new QueryDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - factory: () => new QueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren('foo', {descendants: true}) // fooBars: QueryList; @@ -1777,11 +1777,11 @@ describe('query', () => { class QueryDirective { fooBars: any; + static ngFactoryDef = () => new QueryDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - factory: () => new QueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren('foo', {descendants: true}) // fooBars: QueryList; @@ -1838,11 +1838,11 @@ describe('query', () => { () => { class ShallowQueryDirective { foos: any; + static ngFactoryDef = () => new ShallowQueryDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: ShallowQueryDirective, selectors: [['', 'shallow-query', '']], exportAs: ['shallow-query'], - factory: () => new ShallowQueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren('foo', {descendants: false}) // foos: QueryList; @@ -1859,11 +1859,11 @@ describe('query', () => { class DeepQueryDirective { foos: any; + static ngFactoryDef = () => new DeepQueryDirective(); static ngDirectiveDef = ɵɵdefineDirective({ type: DeepQueryDirective, selectors: [['', 'deep-query', '']], exportAs: ['deep-query'], - factory: () => new DeepQueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren('foo', {descendants: true}) // foos: QueryList; @@ -1922,12 +1922,9 @@ describe('query', () => { class TextDirective { value !: string; - static ngDirectiveDef = ɵɵdefineDirective({ - type: TextDirective, - selectors: [['', 'text', '']], - factory: () => new TextDirective(), - inputs: {value: 'text'} - }); + static ngFactoryDef = () => new TextDirective(); + static ngDirectiveDef = ɵɵdefineDirective( + {type: TextDirective, selectors: [['', 'text', '']], inputs: {value: 'text'}}); } it('should register content matches from top to bottom', () => { @@ -1937,10 +1934,10 @@ describe('query', () => { // @ContentChildren(TextDirective) texts !: QueryList; + static ngFactoryDef = () => contentQueryDirective = new ContentQueryDirective(); static ngComponentDef = ɵɵdefineDirective({ type: ContentQueryDirective, selectors: [['', 'content-query', '']], - factory: () => contentQueryDirective = new ContentQueryDirective(), contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { // @ContentChildren(TextDirective, {descendants: true}) // texts: QueryList; @@ -2005,10 +2002,10 @@ describe('query', () => { // @ViewChildren(TextDirective) texts !: QueryList; + static ngFactoryDef = () => new ViewQueryComponent(); static ngComponentDef = ɵɵdefineComponent({ type: ViewQueryComponent, selectors: [['view-query']], - factory: () => new ViewQueryComponent(), template: function(rf: RenderFlags, ctx: ViewQueryComponent) { if (rf & RenderFlags.Create) { ɵɵelement(0, 'span', ['text', 'A']); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 30af7ef15a..904ef954a6 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -260,7 +260,6 @@ export function renderTemplate( selectView(hostLView, null); // SUSPECT! why do we need to enter the View? const def: ComponentDef = ɵɵdefineComponent({ - factory: () => null, selectors: [], type: Object, template: templateFn, @@ -369,12 +368,12 @@ export function createComponent( viewProviders: Provider[] = [], hostBindings?: HostBindingsFunction): ComponentType { return class Component { value: any; + static ngFactoryDef = () => new Component; static ngComponentDef = ɵɵdefineComponent({ type: Component, selectors: [[name]], consts: consts, vars: vars, - factory: () => new Component, template: template, viewQuery: viewQuery, directives: directives, hostBindings, @@ -388,10 +387,10 @@ export function createComponent( export function createDirective( name: string, {exportAs}: {exportAs?: string[]} = {}): DirectiveType { return class Directive { + static ngFactoryDef = () => new Directive(); static ngDirectiveDef = ɵɵdefineDirective({ type: Directive, selectors: [['', name, '']], - factory: () => new Directive(), exportAs: exportAs, }); }; diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts index 1e7473bdbd..3570ed6c6c 100644 --- a/packages/core/test/render3/renderer_factory_spec.ts +++ b/packages/core/test/render3/renderer_factory_spec.ts @@ -26,6 +26,7 @@ describe('renderer factory lifecycle', () => { rendererFactory.end = () => logs.push('end'); class SomeComponent { + static ngFactoryDef = () => new SomeComponent; static ngComponentDef = ɵɵdefineComponent({ type: SomeComponent, encapsulation: ViewEncapsulation.None, @@ -40,12 +41,12 @@ describe('renderer factory lifecycle', () => { if (rf & RenderFlags.Update) { logs.push('component update'); } - }, - factory: () => new SomeComponent + } }); } class SomeComponentWhichThrows { + static ngFactoryDef = () => new SomeComponentWhichThrows; static ngComponentDef = ɵɵdefineComponent({ type: SomeComponentWhichThrows, encapsulation: ViewEncapsulation.None, @@ -54,8 +55,7 @@ describe('renderer factory lifecycle', () => { vars: 0, template: function(rf: RenderFlags, ctx: SomeComponentWhichThrows) { throw(new Error('SomeComponentWhichThrows threw')); - }, - factory: () => new SomeComponentWhichThrows + } }); } @@ -150,6 +150,7 @@ describe('Renderer2 destruction hooks', () => { it('should call renderer.destroy for each component destroyed', () => { class SimpleComponent { + static ngFactoryDef = () => new SimpleComponent; static ngComponentDef = ɵɵdefineComponent({ type: SimpleComponent, encapsulation: ViewEncapsulation.None, @@ -161,7 +162,6 @@ describe('Renderer2 destruction hooks', () => { ɵɵelement(0, 'span'); } }, - factory: () => new SimpleComponent, }); } diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index f331f3897f..c713f4d97e 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -29,14 +29,14 @@ describe('ViewContainerRef', () => { beforeEach(() => directiveInstance = null); class DirectiveWithVCRef { - static ngDirectiveDef = ɵɵdefineDirective({ - type: DirectiveWithVCRef, - selectors: [['', 'vcref', '']], - factory: () => directiveInstance = new DirectiveWithVCRef( + static ngFactoryDef = () => directiveInstance = new DirectiveWithVCRef( + ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()) - ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()), - inputs: {tplRef: 'tplRef', name: 'name'} - }); + static ngDirectiveDef = ɵɵdefineDirective({ + type: DirectiveWithVCRef, + selectors: [['', 'vcref', '']], + inputs: {tplRef: 'tplRef', name: 'name'} + }); // TODO(issue/24571): remove '!'. tplRef !: TemplateRef<{}>; @@ -57,18 +57,20 @@ describe('ViewContainerRef', () => { let directiveInstances: TestDirective[] = []; class TestDirective { + static ngFactoryDef = + () => { + const instance = new TestDirective( + ɵɵdirectiveInject(ViewContainerRef as any), + ɵɵdirectiveInject(TemplateRef as any)); + + directiveInstances.push(instance); + + return instance; + } + static ngDirectiveDef = ɵɵdefineDirective({ type: TestDirective, selectors: [['', 'testdir', '']], - factory: () => { - const instance = new TestDirective( - ɵɵdirectiveInject(ViewContainerRef as any), - ɵɵdirectiveInject(TemplateRef as any)); - - directiveInstances.push(instance); - - return instance; - } }); constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} @@ -99,11 +101,11 @@ describe('ViewContainerRef', () => { class TestComponent { // TODO(issue/24571): remove '!'. testDir !: TestDirective; + static ngFactoryDef = () => new TestComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestComponent, encapsulation: ViewEncapsulation.None, selectors: [['test-cmp']], - factory: () => new TestComponent(), consts: 4, vars: 0, template: (rf: RenderFlags, cmp: TestComponent) => { @@ -134,13 +136,11 @@ describe('ViewContainerRef', () => { let directiveInstance: TestDirective; class TestDirective { - static ngDirectiveDef = ɵɵdefineDirective({ - type: TestDirective, - selectors: [['', 'testdir', '']], - factory: () => directiveInstance = new TestDirective( - ɵɵdirectiveInject(ViewContainerRef as any), - ɵɵdirectiveInject(TemplateRef as any)) - }); + static ngFactoryDef = () => directiveInstance = new TestDirective( + ɵɵdirectiveInject(ViewContainerRef as any), ɵɵdirectiveInject(TemplateRef as any)) + + static ngDirectiveDef = + ɵɵdefineDirective({type: TestDirective, selectors: [['', 'testdir', '']]}); constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} @@ -172,13 +172,13 @@ describe('ViewContainerRef', () => { condition = false; // TODO(issue/24571): remove '!'. testDir !: TestDirective; + static ngFactoryDef = () => new TestComponent(); static ngComponentDef = ɵɵdefineComponent({ type: TestComponent, encapsulation: ViewEncapsulation.None, selectors: [['test-cmp']], consts: 4, vars: 0, - factory: () => new TestComponent(), template: (rf: RenderFlags, cmp: TestComponent) => { if (rf & RenderFlags.Create) { ɵɵtext(0, 'before|'); @@ -239,12 +239,15 @@ describe('ViewContainerRef', () => { class AppComp { constructor(public vcr: ViewContainerRef, public cfr: ComponentFactoryResolver) {} + static ngFactoryDef = + () => { + return new AppComp( + ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()); + } + static ngComponentDef = ɵɵdefineComponent({ type: AppComp, selectors: [['app-comp']], - factory: - () => new AppComp( - ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()), consts: 0, vars: 0, template: (rf: RenderFlags, cmp: AppComp) => {} @@ -256,10 +259,11 @@ describe('ViewContainerRef', () => { ngDoCheck() { this.doCheckCount++; } + static ngFactoryDef = () => dynamicComp = new DynamicComp(); + static ngComponentDef = ɵɵdefineComponent({ type: DynamicComp, selectors: [['dynamic-comp']], - factory: () => dynamicComp = new DynamicComp(), consts: 0, vars: 0, template: (rf: RenderFlags, cmp: DynamicComp) => {} @@ -355,15 +359,16 @@ describe('ViewContainerRef', () => { @Component({selector: 'app', template: ''}) class AppCmpt { - static ngComponentDef = ɵɵdefineComponent({ - type: AppCmpt, - selectors: [['app']], - factory: () => new AppCmpt( - ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()), - consts: 0, - vars: 0, - template: (rf: RenderFlags, cmp: AppCmpt) => {} - }); + static ngFactoryDef = () => + new AppCmpt(ɵɵdirectiveInject(ViewContainerRef as any), injectComponentFactoryResolver()) + + static ngComponentDef = ɵɵdefineComponent({ + type: AppCmpt, + selectors: [['app']], + consts: 0, + vars: 0, + template: (rf: RenderFlags, cmp: AppCmpt) => {} + }); constructor(private _vcRef: ViewContainerRef, private _cfResolver: ComponentFactoryResolver) { } @@ -424,10 +429,10 @@ describe('ViewContainerRef', () => { // @ViewChildren('foo') foo !: QueryList; + static ngFactoryDef = () => dynamicComp = new DynamicCompWithViewQueries(); static ngComponentDef = ɵɵdefineComponent({ type: DynamicCompWithViewQueries, selectors: [['dynamic-cmpt-with-view-queries']], - factory: () => dynamicComp = new DynamicCompWithViewQueries(), consts: 2, vars: 0, template: (rf: RenderFlags, ctx: DynamicCompWithViewQueries) => { @@ -468,27 +473,28 @@ describe('ViewContainerRef', () => { ngOnDestroy() { this.viewRef.destroy(); } - static ngComponentDef = ɵɵdefineComponent({ - type: CompWithListenerThatDestroysItself, - selectors: [['comp-with-listener-and-on-destroy']], - consts: 2, - vars: 0, - /** */ - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(); }); - ɵɵtext(1, 'Click me'); - } - ɵɵelementEnd(); - } - }, - // We want the ViewRef, so we rely on the knowledge that `ViewRef` is actually given - // when injecting `ChangeDetectorRef`. - factory: () => new CompWithListenerThatDestroysItself( - ɵɵdirectiveInject(ChangeDetectorRef as any)), - }); + // We want the ViewRef, so we rely on the knowledge that `ViewRef` is actually given + // when injecting `ChangeDetectorRef`. + static ngFactoryDef = () => + new CompWithListenerThatDestroysItself(ɵɵdirectiveInject(ChangeDetectorRef as any)) + + static ngComponentDef = ɵɵdefineComponent({ + type: CompWithListenerThatDestroysItself, + selectors: [['comp-with-listener-and-on-destroy']], + consts: 2, + vars: 0, + /** */ + template: function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { return ctx.onClick(); }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } + }, + }); } diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 8fc4d85295..57bb9c8685 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -503,10 +503,10 @@ describe('TestBed', () => { */ const getAOTCompiledComponent = () => { class ComponentClass { + static ngFactoryDef = () => new ComponentClass(); static ngComponentDef = defineComponent({ type: ComponentClass, selectors: [['comp']], - factory: () => new ComponentClass(), consts: 1, vars: 0, template: (rf: any, ctx: any) => { diff --git a/tools/public_api_guard/common/common.d.ts b/tools/public_api_guard/common/common.d.ts index 2606601215..98ea978376 100644 --- a/tools/public_api_guard/common/common.d.ts +++ b/tools/public_api_guard/common/common.d.ts @@ -225,6 +225,7 @@ export declare class NgClassBase { [key: string]: any; } | null; static ngDirectiveDef: any; + static ngFactoryDef: any; } export declare class NgComponentOutlet implements OnChanges, OnDestroy { @@ -309,6 +310,7 @@ export declare class NgStyleBase { [key: string]: any; } | null; static ngDirectiveDef: any; + static ngFactory: any; } export declare class NgSwitch { diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 4caac6b04e..75f77ba707 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -771,7 +771,6 @@ export declare function ɵɵdefineBase(baseDefinition: { export declare function ɵɵdefineComponent(componentDefinition: { type: Type; selectors: CssSelectorList; - factory: FactoryFn; consts: number; vars: number; inputs?: { @@ -801,7 +800,6 @@ export declare function ɵɵdefineComponent(componentDefinition: { export declare const ɵɵdefineDirective: (directiveDefinition: { type: Type; selectors: (string | SelectorFlags)[][]; - factory: FactoryFn; inputs?: { [P in keyof T]?: string | [string, string] | undefined; } | undefined; outputs?: { [P in keyof T]?: string | undefined; } | undefined; features?: DirectiveDefFeature[] | undefined; @@ -836,7 +834,6 @@ export declare function ɵɵdefineNgModule(def: { export declare function ɵɵdefinePipe(pipeDef: { name: string; type: Type; - factory: FactoryFn; pure?: boolean; }): never; @@ -871,6 +868,8 @@ export declare function ɵɵembeddedViewStart(viewBlockId: number, consts: numbe export declare function ɵɵenableBindings(): void; +export declare type ɵɵFactoryDef = () => T; + export declare function ɵɵgetCurrentView(): OpaqueViewState; export declare function ɵɵgetFactoryOf(type: Type): FactoryFn | null;