Skip to content

Commit

Permalink
refactor: load lazy components via extension modules
Browse files Browse the repository at this point in the history
  • Loading branch information
dhhyi committed Sep 4, 2020
1 parent 932aa01 commit 7336b37
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 15 deletions.
13 changes: 11 additions & 2 deletions schematics/src/lazy-component/factory_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')");
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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<any>;<% } %>

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();
<% } %>
}
}

Expand All @@ -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);
}
}
}

1 comment on commit 7336b37

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Azure Demo Servers are available:

Please sign in to comment.