如何在 Angular 应用程序中以编程方式加载“惰性”模块?

问题描述 投票:0回答:1

我有一个单一的 Angular 15 应用程序,不使用路由器。它内部的组件数量在增加,我想将大部分组件分解成一个单独的模块并单独加载它们。

我的应用程序已经有一个带有“加载”进度条的初始屏幕,该进度条随着从服务器获取数据而前进。我希望主 AppModule 包含一组最小的组件来启动,然后我将加载其余组件作为进度条监控的启动任务之一。

现状……

app.module.ts:

import {NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from "@angular/forms";
import {MatProgressBarModule} from '@angular/material/progress-bar';
import {MatSidenavModule} from "@angular/material/sidenav";

import {SharedModule} from "./shared.module";

import {AppComponent} from './app.component';
import {ResizeableSidenavDirective} from "../components/resizeable-sidenav.directive";
import {SplashScreenComponent} from "../components/splash-screen/splash-screen.component";

@NgModule({
    declarations: [
        AppComponent,
        SplashScreenComponent,
        ResizeableSidenavDirective,
    ],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        FormsModule,
        MatProgressBarModule,
        MatSidenavModule,
        SharedModule
    ],
    providers: [],
    bootstrap: [AppComponent],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }

shared.module.ts:

import {NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {CommonModule} from "@angular/common";
import {LeafletModule} from "@asymmetrik/ngx-leaflet";

import {AppComponent} from './app.component';
import {MapViewComponent} from "../components/map-view/map-view.component";
import {Toaster} from "../components/toaster";

@NgModule({
    declarations: [
        MapViewComponent,
        Toaster,
    ],
    imports: [
        BrowserAnimationsModule,
        CommonModule,
        LeafletModule,
    ],
    exports: [
        MapViewComponent,
        Toaster,
    ],
    providers: [],
    bootstrap: [AppComponent],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SharedModule { }

lazy.modules.ts:

import {NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {CommonModule} from "@angular/common";
import {FormsModule} from "@angular/forms";
import {MatDialogModule} from "@angular/material/dialog";
import {MatSliderModule} from "@angular/material/slider";

import {SharedModule} from "./shared.module";

... big list of component imports ...

@NgModule({
    declarations: [
        MyFirstComponent,
        MySecondComponent,
        MyThirdComponent,
        ...
    ],
    imports: [
        CommonModule,
        FormsModule,
        MatDialogModule,
        MatSliderModule,
        SharedModule
    ],
    exports: [
        MyFirstComponent,
        MySecondComponent,
        MyThirdComponent,
        ...
    ],
    providers: [],
    bootstrap: [],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class LazyModule { }

虽然我想问的问题是如何从启动画面中进行延迟加载,但我什至无法构建上面的内容。

LazyModule
组件有很多构建错误,比如:

'mat-slider' 不是已知元素

(但 MatSliderModule 是 LazyModule 的一个包含进口)

找不到名称为“number”的管道。

(但 CommonModule 也是一个包含的导入)

无法绑定到“ngModel”,因为它不是“输入”的已知属性。

(但 FormsModule 是包含的导入)

'my-second' 不是已知元素:

(惰性组件 MyFirstComponent 的 HTML 引用 MySecondComponent)

如果我在

LazyModule
导入中的
SharedModule
之后添加
AppModule
,上述所有问题都会消失。奇怪的是,即使不将
./lazy.module
添加到“导入”列表,它也会仅通过导入
LazyModule
来构建。但是,当然,这会使我返回到我试图分解的单个整体
main.js
文件。所以两个问题:

如何从

LazyModule
中分离出
AppModule
并构建它?

我在初始化时调用什么来加载 LazyModule,我如何收到加载完成的通知?

Update1: 我设法通过将

mat-slider
的导入从
MatSliderModule
移动到
lazy.module
来修复第一个错误(
shared.module
未知)。这对我来说毫无意义,因为
mat-slider
只被一个惰性组件使用。这种技术对“找不到数字管道”(
CommonModule
)或“无法绑定 ngModel”(
FormsModule
)没有帮助。

angular lazy-loading
1个回答
1
投票
  1. 没有路由的延迟加载。

您可以在没有路由的情况下延迟加载所有组件。 您只需要手动解析组件工厂并编译组件即可。 对于 angular 13,它更自动,代码看起来像:

export class AppComponent {
  @ViewChild("formComponent", { read: ViewContainerRef })
  formComponent!: ViewContainerRef;

  constructor(private compiler: Compiler, private injector: Injector) {}

  async loadForm() {
    const { LazyFormModule } = await import("./lazy-form.component");
    const moduleFactory = await this.compiler.compileModuleAsync(
      LazyFormModule
    );
    const moduleRef = moduleFactory.create(this.injector);
    const componentFactory = moduleRef.instance.getComponent();
    this.formComponent.clear();
    this.formComponent.createComponent(componentFactory, {ngModuleRef: moduleRef});
  }
}

export class LazyFormModule {
  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  getComponent() {
    return LazyFormComponent
  }
}

有关更多示例,请查看 https://www.wittyprogramming.dev/articles/lazy-load-component-angular-without-routing/https://medium.com/@ckyidr9/lazy-load-feature -modules-without-routing-in-angular-9-ivy-220851cc7751

  1. 管理您的延迟加载逻辑。

为了让事情正常进行,我建议你只留下带有启动画面的空白应用程序并删除所有依赖模块(例如,评论它们)。然后使用第 1 部分中的技术一个接一个地添加惰性加载模块。所有必需的模块都应该转到惰性模块,而不是应用程序模块。

  1. 共享模块。

只有当你看到一些重复的模块时,你才应该为公共逻辑添加惰性共享模块(不要在应用程序中也使用它)。

© www.soinside.com 2019 - 2024. All rights reserved.