Angular 惰性加載特性模塊

2022-07-14 09:45 更新

惰性加載特性模塊

默認情況下,NgModule 都是急性加載的,也就是說它會在應用加載時盡快加載,所有模塊都是如此,無論是否立即要用。對于帶有很多路由的大型應用,考慮使用惰性加載 —— 一種按需加載 NgModule 的模式。惰性加載可以減小初始包的尺寸,從而減少加載時間。

如果需要本頁描述的具有兩個惰性加載模塊的范例應用,參閱現(xiàn)場演練 / 下載范例。

惰性加載入門

本節(jié)會介紹配置惰性加載路由的基本過程。 想要一個分步的范例,參閱本頁的分步設置部分。

要惰性加載 Angular 模塊,請在 ?AppRoutingModule ??routes ?中使用 ?loadChildren ?代替 ?component ?進行配置,代碼如下。

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  }
];

在惰性加載模塊的路由模塊中,添加一個指向該組件的路由。

const routes: Routes = [
  {
    path: '',
    component: ItemsComponent
  }
];

還要確保從 ?AppModule ?中移除了 ?ItemsModule?。想要一個關于惰性加載模塊的分步操作指南,請繼續(xù)查看本頁的后續(xù)章節(jié)。

分步設置

建立惰性加載的特性模塊有兩個主要步驟:

  1. 使用 ?--route? 標志,用 CLI 創(chuàng)建特性模塊。
  2. 配置相關路由。

建立應用

如果你還沒有應用,可以遵循下面的步驟使用 CLI 創(chuàng)建一個。如果已經有了,可以直接跳到導入與路由配置部分。 輸入下列命令,其中的 ?customer-app? 表示你的應用名稱:

ng new customer-app --routing

這會創(chuàng)建一個名叫 ?customer-app? 的應用,而 ?--routing? 標識生成了一個名叫 ?app-routing.module.ts? 的文件,它是你建立惰性加載的特性模塊時所必須的。輸入命令 ?cd customer-app? 進入該項目。

?--routing? 選項需要 Angular/CLI 8.1 或更高版本。

創(chuàng)建一個帶路由的特性模塊

接下來,你將需要一個包含路由的目標組件的特性模塊。要創(chuàng)建它,在終端中輸入如下命令,其中 ?customers ?是特性模塊的名稱。加載 ?customers ?特性模塊的路徑也是 ?customers?,因為它是通過 ?--route? 選項指定的:

ng generate module customers --route customers --module app.module

這將創(chuàng)建一個 ?customers ?文件夾,在其 ?customers.module.ts? 文件中定義了新的可惰性加載模塊 ?CustomersModule?。該命令會自動在新特性模塊中聲明 ?CustomersComponent?。

因為這個新模塊想要惰性加載,所以該命令不會在應用的根模塊 ?app.module.ts? 中添加對新特性模塊的引用。相反,它將聲明的路由 ?customers ?添加到以 ?--module? 選項指定的模塊中聲明的 ?routes ?數(shù)組中。

const routes: Routes = [
  {
    path: 'customers',
    loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  }
];

注意,惰性加載語法使用 ?loadChildren?,其后是一個使用瀏覽器內置的 ?import('...')? 語法進行動態(tài)導入的函數(shù)。其導入路徑是到當前模塊的相對路徑。

基于字符串的惰性加載
在 Angular 版本 8 中,?loadChildren? 路由規(guī)范的字符串語法已棄用,建議改用 ?import()? 語法。不過,你仍然可以通過在 ?tsconfig ?文件中包含惰性加載的路由來選擇使用基于字符串的惰性加載(?loadChildren: './path/to/module#Module'?),這樣它就會在編譯時包含惰性加載的文件。
默認情況下,會用 CLI 生成項目,這些項目將更嚴格地包含旨在與 ?import()? 語法一起使用的文件。

添加另一個特性模塊

使用同樣的命令創(chuàng)建第二個帶路由的惰性加載特性模塊及其樁組件。

ng generate module orders --route orders --module app.module

這將創(chuàng)建一個名為 ?orders ?的新文件夾,其中包含 ?OrdersModule ?和 ?OrdersRoutingModule ?以及新的 ?OrdersComponent ?源文件。使用 ?--route? 選項指定的 ?orders ?路由,用惰性加載語法添加到了 ?app-routing.module.ts? 文件內的 ?routes ?數(shù)組中。

const routes: Routes = [
  {
    path: 'customers',
    loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  },
  {
    path: 'orders',
    loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
  }
];

建立 UI

雖然你也可以在地址欄中輸入 URL,不過導航 UI 會更好用,也更常見。把 ?app.component.html? 中的占位腳本替換成一個自定義的導航,以便你在瀏覽器中能在模塊之間導航。

<h1>
  {{title}}
</h1>

<button type="button" routerLink="/customers">Customers</button>
<button type="button" routerLink="/orders">Orders</button>
<button type="button" routerLink="">Home</button>

<router-outlet></router-outlet>

要想在瀏覽器中看到你的應用,就在終端窗口中輸入下列命令:

ng serve

然后,跳轉到 ?localhost:4200?,這時你應該看到 "customer-app" 和三個按鈕。


這些按鈕生效了,因為 CLI 會自動將特性模塊的路由添加到 ?app-routing.module.ts? 中的 ?routes ?數(shù)組中。

導入與路由配置

CLI 會將每個特性模塊自動添加到應用級的路由映射表中。通過添加默認路由來最終完成這些步驟。在 ?app-routing.module.ts? 文件中,使用如下命令更新 ?routes ?數(shù)組:

const routes: Routes = [
  {
    path: 'customers',
    loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
  },
  {
    path: 'orders',
    loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
  },
  {
    path: '',
    redirectTo: '',
    pathMatch: 'full'
  }
];

前兩個路徑是到 ?CustomersModule ?和 ?OrdersModule ?的路由。最后一個條目則定義了默認路由??章窂狡ヅ渌胁黄ヅ湎惹奥窂降膬热?。

特性模塊內部

接下來,仔細看看 ?customers.module.ts? 文件。如果你使用的是 CLI,并按照此頁面中的步驟進行操作,則無需在此處執(zhí)行任何操作。

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomersRoutingModule } from './customers-routing.module';
import { CustomersComponent } from './customers.component';

@NgModule({
  imports: [
    CommonModule,
    CustomersRoutingModule
  ],
  declarations: [CustomersComponent]
})
export class CustomersModule { }

?customers.module.ts? 文件導入了 ?customers-routing.module.ts? 和 ?customers.component.ts? 文件。?@NgModule? 的 ?imports ?數(shù)組中列出了 ?CustomersRoutingModule?,讓 ?CustomersModule ?可以訪問它自己的路由模塊。?CustomersComponent ?位于 ?declarations? 數(shù)組中,這意味著 ?CustomersComponent ?屬于 ?CustomersModule?。

然后,?app-routing.module.ts? 會使用 JavaScript 的動態(tài)導入功能來導入特性模塊 ?customers.module.ts?。

專屬于特性模塊的路由定義文件 ?customers-routing.module.ts? 將導入在 ?customers.component.ts? 文件中定義的自有特性組件,以及其它 JavaScript 導入語句。然后將空路徑映射到 ?CustomersComponent?。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { CustomersComponent } from './customers.component';


const routes: Routes = [
  {
    path: '',
    component: CustomersComponent
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class CustomersRoutingModule { }

這里的 ?path ?設置為空字符串,因為 ?AppRoutingModule ?中的路徑已經設置為 ?customers?,因此,?CustomersRoutingModule ?中的此路由已經位于 ?customers ?這個上下文中。此路由模塊中的每個路由都是其子路由。

另一個特性模塊中路由模塊的配置也類似。

import { OrdersComponent } from './orders.component';

const routes: Routes = [
  {
    path: '',
    component: OrdersComponent
  }
];

確認它工作正常

你可以使用 Chrome 開發(fā)者工具來確認一下這些模塊真的是惰性加載的。在 Chrome 中,按 ?Cmd+Option+i?(Mac)或 ?Ctrl+Shift+j?(PC),并選中 ?Network ?頁標簽。


點擊 Orders 或 Customers 按鈕。如果你看到某個 chunk 文件出現(xiàn)了,就表示一切就緒,特性模塊被惰性加載成功了。Orders 和 Customers 都應該出現(xiàn)一次 chunk,并且它們各自只應該出現(xiàn)一次。


要想再次查看它或測試本項目后面的行為,只要點擊 Network 頁左上放的 清除 圖標即可。


然后,使用 ?Cmd+r?(Mac)或 ?Ctrl+r?(PC)重新加載頁面。

forRoot() 與 forChild()

你可能已經注意到了,CLI 會把 ?RouterModule.forRoot(routes)? 添加到 ?AppRoutingModule ?的 ?imports ?數(shù)組中。這會讓 Angular 知道 ?AppRoutingModule ?是一個路由模塊,而 ?forRoot()? 表示這是一個根路由模塊。它會配置你傳入的所有路由、讓你能訪問路由器指令并注冊 ?Router?。?forRoot()? 在應用中只應該使用一次,也就是這個 ?AppRoutingModule ?中。

CLI 還會把 ?RouterModule.forChild(routes)? 添加到各個特性模塊中。這種方式下 Angular 就會知道這個路由列表只負責提供額外的路由并且其設計意圖是作為特性模塊使用。你可以在多個模塊中使用 ?forChild()?。

?forRoot()? 方法為路由器管理全局性的注入器配置。?forChild()? 方法中沒有注入器配置,只有像 ?RouterOutlet ?和 ?RouterLink ?這樣的指令。

預加載

預加載通過在后臺加載部分應用來改進用戶體驗。你可以預加載模塊或組件數(shù)據。

預加載模塊

預加載模塊通過在后臺加載部分應用來改善用戶體驗,這樣用戶在激活路由時就無需等待下載這些元素。

要啟用所有惰性加載模塊的預加載,請從 Angular 的 ?router ?導入 ?PreloadAllModules ?令牌。

import { PreloadAllModules } from '@angular/router';

還是在 ?AppRoutingModule ?中,通過 ?forRoot()? 指定你的預加載策略。

RouterModule.forRoot(
  appRoutes,
  {
    preloadingStrategy: PreloadAllModules
  }
)

預加載組件數(shù)據

要預加載組件數(shù)據,可以用 ?resolver ?守衛(wèi)。解析器通過阻止頁面加載來改進用戶體驗,直到顯示頁面時的全部必要數(shù)據都可用。

解析器

創(chuàng)建一個解析器服務。通過 CLI,生成服務的命令如下:

ng generate service <service-name>

在新創(chuàng)建的服務中,實現(xiàn)由 ?@angular/router? 包提供的 ?Resolve ?接口:

import { Resolve } from '@angular/router';

…

/* An interface that represents your data model */
export interface Crisis {
  id: number;
  name: string;
}

export class CrisisDetailResolverService implements Resolve<Crisis> {
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> {
    // your logic goes here
  }
}

把這個解析器導入此模塊的路由模塊。

import { CrisisDetailResolverService } from './crisis-detail-resolver.service';

在組件的 ?route ?配置中添加一個 ?resolve ?對象。

{
  path: '/your-path',
  component: YourComponent,
  resolve: {
    crisis: CrisisDetailResolverService
  }
}

在此組件的構造函數(shù)中,注入一個 ?ActivatedRoute ?實例,它可以表示當前路由。

import { ActivatedRoute } from '@angular/router';

@Component({ … })
class YourComponent {
  constructor(private route: ActivatedRoute) {}
}

使用注入進來的 ?ActivatedRoute ?類實例來訪問與指定路由關聯(lián)的 ?data ?值。

import { ActivatedRoute } from '@angular/router';

@Component({ … })
class YourComponent {
  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.data
      .subscribe(data => {
        const crisis: Crisis = data.crisis;
        // …
      });
  }
}

對惰性加載模塊進行故障排除

惰性加載模塊時常見的錯誤之一,就是在應用程序中的多個位置導入通用模塊??梢韵扔?nbsp;Angular CLI 生成模塊并包括 ?--route route-name? 參數(shù),來測試這種情況,其中 ?route-name? 是模塊的名稱。接下來,生成不帶 ?--route? 參數(shù)的模塊。如果你用了 ?--route? 參數(shù),Angular CLI 就會生成錯誤,但如果不使用它便可以正確運行,則可能是在多個位置導入了相同的模塊。

請記住,許多常見的 Angular 模塊都應該導入應用的基礎模塊中。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號