Angular懒加载模块:如何配置全局公共模块避免重复引入
Hey there! Let's figure out how to make modules like ToasterModule available across your entire Angular app—including lazy-loaded modules—without having to import them in every single sub-module. I’ve dealt with this exact scenario plenty of times, so let’s break it down step by step.
First, Understand the Core Issue
The key thing to know is that lazy-loaded modules have their own independent injectors in Angular. They don’t automatically inherit components, directives, or pipes from modules imported in AppModule. However, singleton services are shared across the global injector, so we can handle services and UI-focused module features differently.
1. For Service-First Modules (Like Most Toaster Libraries)
If your ToasterModule is primarily used via a service (e.g., calling toastr.success() to show notifications), you only need to set it up once in AppModule, and lazy-loaded modules can use the service without re-importing the module.
How to Implement:
- In
app.module.ts, use the module’sforRoot()method (almost all third-party modules provide this static method to configure singleton services):
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { ToasterModule } from 'your-toaster-library'; // e.g., ngx-toastr's ToastrModule import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AppRoutingModule, // Configure the singleton service once here ToasterModule.forRoot({ timeOut: 3000, positionClass: 'toast-top-right' }) ], bootstrap: [AppComponent] }) export class AppModule { }
- Now, in any lazy-loaded component, just inject the service directly—no need to import ToasterModule again:
// lazy-loaded.component.ts import { Component } from '@angular/core'; import { ToasterService } from 'your-toaster-library'; @Component({ selector: 'app-lazy', template: '<button (click)="showToast()">Show Toast</button>' }) export class LazyLoadedComponent { constructor(private toasterService: ToasterService) {} showToast() { this.toasterService.success('Hello from a lazy-loaded module! 🎉'); } }
2. For Modules With UI Components/Directives
If your ToasterModule includes UI elements you need to use in templates (like a <toaster-container> component or custom directives), we can create a SharedModule to wrap all common modules—so you only import one module per lazy-loaded sub-module instead of multiple.
Step-by-Step:
- Create a SharedModule: This module will import and export all your global dependencies, so other modules can access them easily.
// shared.module.ts import { NgModule, Optional, SkipSelf } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ToasterModule } from 'your-toaster-library'; @NgModule({ imports: [ CommonModule, // Import the ToasterModule here (no forRoot()—we already did that in AppModule) ToasterModule ], // Export the modules so they're available to any module that imports SharedModule exports: [ CommonModule, ToasterModule ] }) export class SharedModule { // Optional: Prevent accidental multiple imports of SharedModule constructor(@Optional() @SkipSelf() parentModule: SharedModule) { if (parentModule) { throw new Error('SharedModule is already loaded. Import it ONLY in AppModule.'); } } }
- Import SharedModule in AppModule: Do this once—this ensures the singleton service is configured globally.
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { SharedModule } from './shared/shared.module'; import { ToasterModule } from 'your-toaster-library'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AppRoutingModule, SharedModule, // Keep the forRoot() call here for singleton service config ToasterModule.forRoot({ timeOut: 3000 }) ], bootstrap: [AppComponent] }) export class AppModule { }
- Import SharedModule in Lazy-Loaded Modules: Now you only need to import this one module to access all your global dependencies, including ToasterModule's UI features:
// lazy.module.ts import { NgModule } from '@angular/core'; import { SharedModule } from '../shared/shared.module'; import { LazyRoutingModule } from './lazy-routing.module'; import { LazyLoadedComponent } from './lazy-loaded.component'; @NgModule({ declarations: [LazyLoadedComponent], imports: [ LazyRoutingModule, SharedModule // One import = access to all common modules ] }) export class LazyModule { }
3. Bonus: Angular 14+ Standalone Components
If you’re using Angular 14 or later, you can skip NgModules entirely with standalone components. Configure global services directly in main.ts, and all components (including lazy-loaded ones) can use the service without imports:
// main.ts import { bootstrapApplication } from '@angular/platform-browser'; import { importProvidersFrom } from '@angular/core'; import { ToasterModule } from 'your-toaster-library'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent, { providers: [ importProvidersFrom( ToasterModule.forRoot({ timeOut: 3000 }) ) ] });
内容的提问来源于stack exchange,提问作者Sameer

