diff --git a/schematics/src/lazy-component/factory_spec.ts b/schematics/src/lazy-component/factory_spec.ts index c83e9b9480..c8d8eadde4 100644 --- a/schematics/src/lazy-component/factory_spec.ts +++ b/schematics/src/lazy-component/factory_spec.ts @@ -100,14 +100,23 @@ describe('Lazy Component Schematic', () => { expect(componentContent).toContain("@ViewChild('anchor'"); }); - it('should import component which is lazy loaded', async () => { - expect(componentContent).toMatch(/import.*from '.*\/shared\/dummy\/dummy.component'/); + it('should dynamically import component which is lazy loaded', async () => { + expect(componentContent).toContain("await import('../../shared/dummy/dummy.component');"); + }); + + it('should load component via module', async () => { + // tslint:disable-next-line: no-invalid-template-strings + expect(componentContent).toContain('import(`../../${extension}.module`)'); }); it('should load component using ivy', async () => { expect(componentContent).toContain('.resolveComponentFactory(DummyComponent)'); }); + it('should have extension in variable to fool cyclic dependency detection', async () => { + expect(componentContent).toContain("const extension = 'ext';"); + }); + it('should check if extension is enabled', async () => { expect(componentContent).toContain(".enabled('ext')"); }); diff --git a/schematics/src/lazy-component/files/__name@dasherize__/__name@dasherize__.component.ts.template b/schematics/src/lazy-component/files/__name@dasherize__/__name@dasherize__.component.ts.template index 45c2c7d401..4aa728e09a 100644 --- a/schematics/src/lazy-component/files/__name@dasherize__/__name@dasherize__.component.ts.template +++ b/schematics/src/lazy-component/files/__name@dasherize__/__name@dasherize__.component.ts.template @@ -1,17 +1,14 @@ import { - ChangeDetectionStrategy, Component, ComponentFactoryResolver, + ChangeDetectionStrategy, Component, OnInit, ViewChild, ViewContainerRef, + Compiler, Injector, NgModuleFactory, <% if (bindings.length) { %>ComponentRef, Input, OnChanges, <% } %> - OnInit, <% if (onChanges === 'complex') { %>SimpleChange, SimpleChanges, <% } %> - ViewChild, ViewContainerRef, } from '@angular/core'; import { FeatureToggleService } from 'ish-core/feature-toggle.module'; <% if (imports.length) { %><%= imports.map(i => `import { ${i.types.join(', ')} } from ${i.from};`).join('\n') %><% } %> -import { <%= classify(originalName) %>Component } from '../../shared/<%= dasherize(originalName) %>/<%= dasherize(originalName) %>.component'; - @Component({ selector: '<%= selector %>', templateUrl: './<%= dasherize(name) %>.component.html', @@ -32,20 +29,37 @@ export class <%= classify(name) %>Component implements OnInit <% if (bindings.le @ViewChild('anchor', { read: ViewContainerRef, static: true }) anchor: ViewContainerRef; <% if (bindings.length) { %><%= bindings.map(b => b.declaration).join('\n ') %><% } %> - <% if (bindings.length) { %>private component: ComponentRef<<%= classify(originalName) %>Component>;<% } %> + <% if (bindings.length) { %>// tslint:disable-next-line: no-any + private component: ComponentRef;<% } %> constructor( - private componentFactoryResolver: ComponentFactoryResolver, - private featureToggleService: FeatureToggleService + private featureToggleService: FeatureToggleService, + private compiler: Compiler, + private injector: Injector ) {} - ngOnInit() { + async ngOnInit() { if (this.featureToggleService.enabled('<%= camelize(extension) %>')) { - const factory = this.componentFactoryResolver.resolveComponentFactory(<%= classify(originalName) %>Component); - <% if (bindings.length) { %>this.component = <% } %>this.anchor.createComponent(factory); - <% if (bindings.length) { %>this.ngOnChanges(<% if (onChanges === 'complex') { %>{ + // prevent cyclic dependency warnings + const extension = '<%= dasherize(extension) %>'; + const moduleObj = await import(`../../${extension}.module`); + const module = moduleObj[Object.keys(moduleObj)[0]]; + + const { <%= classify(originalName) %>Component } = await import('../../shared/<%= dasherize(originalName) %>/<%= dasherize(originalName) %>.component'); + + const moduleFactory = await this.loadModuleFactory(module); + const moduleRef = moduleFactory.create(this.injector); + const factory = moduleRef.componentFactoryResolver.resolveComponentFactory(<%= classify(originalName) %>Component); + + <% if (bindings.length) { %> + this.component = this.anchor.createComponent(factory); + this.ngOnChanges(<% if (onChanges === 'complex') { %>{ <%= bindings.map(b => `${b.name}: new SimpleChange(undefined, this.${b.name}, true),`).join('\n ') %> - }<% } %>);<% } %> + }<% } %>); + this.component.changeDetectorRef.markForCheck(); + <% } else { %> + this.anchor.createComponent(factory).changeDetectorRef.markForCheck(); + <% } %> } } @@ -57,4 +71,12 @@ export class <%= classify(name) %>Component implements OnInit <% if (bindings.le } } <% } %> + + private async loadModuleFactory(t) { + if (t instanceof NgModuleFactory) { + return t; + } else { + return await this.compiler.compileModuleAsync(t); + } + } }