简体   繁体   English

如何手动延迟加载模块?

[英]How to manually lazy load a module?

I've tried loading modules without router using SystemJsNgModuleLoader , but couldn't get it to work:我试过使用SystemJsNgModuleLoader没有路由器的情况下加载模块,但无法让它工作:

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).对于我用于 URL 的任何字符串,我都Cannot find module xxx (绝对/相对 url/路径...尝试了很多选项)。 I looked through Router source code and couldn't find anything other then this SystemJsNgModuleLoader .我查看了路由器源代码,除了这个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:昨天在ng-europe 2016会议上提出了这个问题 - Miško & Matias 回答:

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. Miško Hevery:你只需要掌握模块,从那里你可以掌握组件工厂,你可以在应用程序中的任何地方动态加载组件工厂。 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. Matias Niemelä唯一需要特别注意的是,在 [Ng]Module 上有一个叫做entryComponents的东西,它标识可以延迟加载的组件——这是该组件集的入口。 So when you have modules that are lazy loaded, please put the stuff into entryComponents .所以当你有延迟加载的模块时,请将这些东西放入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 ?任何人都知道如何在不使用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)?如何获取模块以及应该进入entryComponents的内容到底是什么(我阅读了FAQ ,但不能在不实际加载模块的情况下尝试)?

Anyone knows how to load modules manually, without using Route.loadChildren?任何人都知道如何在不使用 Route.loadChildren 的情况下手动加载模块?

You can use SystemJsNgModuleLoader to get module's factory:您可以使用SystemJsNgModuleLoader来获取模块的工厂:

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

For Angular 8 see Lazy load module in angular 8对于 Angular 8,请参阅 Angular 8 中的延迟加载模块

Here is how it can look like:这是它的样子:

lazy.module.ts懒惰.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 ExamplePlunker 示例

There are two options to precompile module for AOT :有两个选项可以为AOT预编译模块:

1) Angular CLI lazyModules options (since Angular 6) 1) Angular CLI lazyModules 选项(自 Angular 6 起)

Use angular/cli build-in feature:使用 angular/cli 内置功能:

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

See

2) Using provideRoutes from RouterModule 2) 使用来自 RouterModule 的 provideRoutes

app.module.ts app.module.ts

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

app.component.ts 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 Github 仓库 angular-cli-lazy


Lazy loading with webpack and AOT使用 webpack 和 AOT 延迟加载

Compilation using ngc使用 ngc 编译

Initialization Compiler by using the following factory使用以下工厂初始化编译器

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

Github repo Github 仓库

[Angular 6] [角6]

Hello,你好,

I share my solution here because I didn't find how to lazyload without router on stackoverflow .我在这里分享我的解决方案,因为我没有找到如何在 stackoverflow 上没有路由器的情况下延迟加载

The Yurzui 's way works but he uses the Router module to compile the lazy module while I didn't want to use it. Yurzui的方式有效,但他使用 Router 模块来编译惰性模块,而我不想使用它。

In our src/angular.json file we can ask to the @angular/cli to compile a module apart.在我们的src/angular.json文件中,我们可以要求@angular/cli编译一个模块。

For that we add the lazyModules key in "project" > "your-app-name" > "architect" > "build" > "options".为此,我们在“project”>“your-app-name”>“architect”>“build”>“options”中添加lazyModules键。

Like this :像这样 :

  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects", 
  "projects": {
    "lazy-load-app": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/lazy-custom-element-app",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": [],
            "lazyModules": [
              "src/app/lazy-load/lazy-load.module",
              "src/app/another-lazy-load/another-lazy-load.module"
            ]

then we can call and load our compiled module.然后我们可以调用并加载我们编译的模块。

Like this :像这样 :

export class LoaderComponent implements OnInit {

      // tag where we gonna inject the lazyload module and his default compononent "entry"
      @ViewChild('container', { read: ViewContainerRef }) viewRef: ViewContainerRef;

      constructor(
        private loader:     NgModuleFactoryLoader,
        private injector:   Injector,
        private moduleRef:  NgModuleRef<any>,) {
      }

      ngOnInit(): void {
       this.loader.load(this.pathModuleTemplate).then((moduleFactory: NgModuleFactory<any>) => {
          // our module had a static property 'entry' that references the component that  want to load by default with the module
          const entryComponent = (<any>moduleFactory.moduleType).entry;
          const moduleRef = moduleFactory.create(this.injector);
          const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);
          this.viewRef.createComponent(compFactory);
        });
      }
}

source: https://github.com/angular/angular-cli/blob/9107f3cc4e66b25721311b5c9272ec00c2dea46f/packages/angular_devkit/build_angular/src/server/schema.json来源: https : //github.com/angular/angular-cli/blob/9107f3cc4e66b25721311b5c9272ec00c2dea46f/packages/angular_devkit/build_angular/src/server/schema.json

Hoping it can help someone :)希望它可以帮助某人:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM