Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

angular - How to manually lazy load a module?

I've tried loading modules without router using SystemJsNgModuleLoader, but couldn't get it to work:

this.loader.load(url).then(console.info);

I'm getting Cannot find module xxx for whatever string I use for URL (aboslute/relative urls/paths... tried many options). I looked through Router source code and couldn't find anything other then this SystemJsNgModuleLoader. I'm not even sure I should be using this...


This question was asked just yesterday at ng-europe 2016 conference - Mi?ko & Matias answered:

Mi?ko Hevery: One just has to get hold of the module, from there you can get the hold of component factory and you can dynamically load component factory anywhere you want in the application. This is exactly what the router does internally. So it's quite strait forward for you to do that as well.

Matias Niemel? The only special thing to note is that on the [Ng]Module there's something called entryComponents and that identifies components that could be lazy loaded - that's the entry into that component set. So when you have modules that are lazy loaded, please put the stuff into entryComponents.

...but it's not that strait forward without examples and poor docs on the subject (;

Anyone knows how to load modules manually, without using Route.loadChildren? How to get hold of the module and what exactly is the stuff that should go into entryComponents (I read FAQ, but can't try without actually loading module)?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Anyone knows how to load modules manually, without using Route.loadChildren?

You can use SystemJsNgModuleLoader to get module's factory:

this.loader.load('./src/lazy.module#TestModule').then((factory: NgModuleFactory<any>) => {
  console.log(factory);
});

For Angular 8 see Lazy load module in angular 8

Here is how it can look like:

lazy.module.ts

@Component({
  selector: 'test',
  template: `I'm lazy module`,
})
export class Test {}

@NgModule({
  imports: [CommonModule],
  declarations: [Test],
  entryComponents: [Test]
})
export class LazyModule {
  static entry = Test;
}

app.ts

import {
  Component, NgModule, ViewContainerRef,
  SystemJsNgModuleLoader, NgModuleFactory,
  Injector} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `<h2>Test lazy loading module</h2>`,
})
export class AppComponent {
  constructor(
    private loader: SystemJsNgModuleLoader, 
    private inj: Injector, 
    private vcRef: ViewContainerRef) {}

  ngOnInit() {
     this.loader.load('./src/lazy.module#LazyModule')
       .then((moduleFactory: NgModuleFactory<any>) => {
         const moduleRef = moduleFactory.create(this.inj);
         const entryComponent = (<any>moduleFactory.moduleType).entry;
         const compFactory = 
               moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
         this.vcRef.createComponent(compFactory);
      });
  }
} 

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent ],
  providers: [SystemJsNgModuleLoader],
  bootstrap: [ AppComponent ]
})
export class AppModule {} 
this.loader.load('./src/test.module#TestModule').then((factory: NgModuleFactory<any>) => {
  console.log(factory);
});

Plunker Example

There are two options to precompile module for AOT:

1) Angular CLI lazyModules options (since Angular 6)

Use angular/cli build-in feature:

{
  "projects": {
    "app": {
      "architect": {
        "build": {
          "options": {
            "lazyModules": [  <====== add here all your lazy modules
              "src/path-to.module"
            ]
          }
        }
      }
    }
  }
} 

See

2) Using provideRoutes from RouterModule

app.module.ts

providers: [
  SystemJsNgModuleLoader,
  provideRoutes([
     { loadChildren: 'app/lazy/lazy.module#LazyModule' }
  ])
],

app.component.ts

export class AppComponent implements  OnInit {
    title = 'Angular cli Example SystemJsNgModuleLoader.load';

    @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

    constructor(private loader: SystemJsNgModuleLoader, private inj: Injector) {}

    ngOnInit() {
        this.loader.load('app/lazy/lazy.module#LazyModule').then((moduleFactory: NgModuleFactory<any>) => {
            const entryComponent = (<any>moduleFactory.moduleType).entry;
            const moduleRef = moduleFactory.create(this.inj);

            const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
            this.container.createComponent(compFactory);
        });
    }
}

Github repo angular-cli-lazy


Lazy loading with webpack and AOT

Compilation using ngc

Initialization Compiler by using the following factory

export function createJitCompiler () {
    return new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler();
}

Github repo


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...