Angular 15无路由应用按需加载模块及构建错误解决
一、先解决LazyModule的依赖缺失问题
懒加载模块是完全独立的模块,不会继承AppModule的任何导入,所有用到的依赖必须自己显式导入或通过SharedModule复用:
内置管道(如number)未识别
内置管道属于CommonModule,必须在LazyModule或SharedModule中导入。建议在SharedModule中统一导入并导出,这样所有懒加载模块只需导入SharedModule即可:// shared.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [CommonModule], exports: [CommonModule] }) export class SharedModule {}无法绑定ngModel
ngModel依赖FormsModule(模板驱动表单)或ReactiveFormsModule(响应式表单),同样在SharedModule中导入并导出:// shared.module.ts 补充 import { FormsModule } from '@angular/forms'; @NgModule({ imports: [CommonModule, FormsModule], exports: [CommonModule, FormsModule] })组件相互引用未识别
- 若组件属于同一个LazyModule,必须全部在LazyModule的
declarations数组中声明; - 若组件跨模块复用,将其移至SharedModule的
declarations并exports,再在LazyModule中导入SharedModule。
- 若组件属于同一个LazyModule,必须全部在LazyModule的
Material组件(如mat-slider)未识别
你已经将MatSliderModule移至SharedModule,确保SharedModule导出该模块,LazyModule导入SharedModule即可。
最终LazyModule的配置示例:
// lazy.module.ts import { NgModule } from '@angular/core'; import { SharedModule } from '../shared/shared.module'; // 导入当前模块下的所有组件 import { UserProfileComponent } from './user-profile.component'; import { DashboardComponent } from './dashboard.component'; @NgModule({ imports: [SharedModule], declarations: [UserProfileComponent, DashboardComponent], // 若需要在模块外部使用组件,添加到exports数组 exports: [UserProfileComponent, DashboardComponent] }) export class LazyModule {}
二、无Router场景下实现懒加载
Angular支持不依赖Router的动态模块加载,通过import()语法结合createNgModuleAPI实现,同时可结合你的启动屏进度条:
// app.component.ts import { Component, Injector, ViewChild, ViewContainerRef } from '@angular/core'; import { createNgModule } from '@angular/core'; // 提前声明组件类型(避免类型报错) import type { DashboardComponent } from './lazy/dashboard.component'; @Component({ selector: 'app-root', template: ` <div class="splash-screen" *ngIf="isLoading"> <div class="progress" [style.width.%]="loadProgress"></div> </div> <div #lazyHost></div> ` }) export class AppComponent { isLoading = true; loadProgress = 0; @ViewChild('lazyHost', { read: ViewContainerRef }) lazyHost!: ViewContainerRef; constructor(private injector: Injector) {} ngOnInit() { // 模拟进度条更新 const progressTimer = setInterval(() => { this.loadProgress += 15; if (this.loadProgress >= 90) clearInterval(progressTimer); }, 120); // 动态加载LazyModule import('./lazy/lazy.module').then((moduleBundle) => { // 创建模块实例 const moduleRef = createNgModule(moduleBundle.LazyModule, this.injector); // 获取组件工厂并挂载到指定容器 const dashboardFactory = moduleRef.componentFactoryResolver.resolveComponentFactory( moduleBundle.LazyModule.declarations.find(c => c.name === 'DashboardComponent') as typeof DashboardComponent ); this.lazyHost.createComponent(dashboardFactory, undefined, moduleRef.injector); // 完成加载 this.isLoading = false; this.loadProgress = 100; }).catch(err => { console.error('懒加载模块失败:', err); this.isLoading = false; }); } }
三、验证代码拆分效果
执行ng build --stats-json,生成的stats.json文件可通过webpack-bundle-analyzer查看,确认LazyModule被打包为独立的chunk文件(如src_app_lazy_lazy_module_ts.js),且主chunk未包含懒加载模块的代码。
注意:绝对不能在AppModule的imports数组中添加LazyModule,否则模块会被打包进主chunk,失去代码拆分的意义。
内容的提问来源于stack exchange,提问作者Brian White

