Angular 中的路由级代码拆分

通过使用路由级代码拆分来提升应用的性能!

这篇文章解释了如何在 Angular 应用中设置路由级代码拆分,这可以减小 JavaScript 包大小并显著提升可交互时间 (TTI)

您可以在 GitHub 上找到本文的代码示例。急切加载路由示例位于 eager 分支中。路由级代码拆分示例位于 lazy 分支中。

为什么代码拆分很重要

Web 应用日益增长的复杂性导致发送给用户的 JavaScript 代码量显著增加。大型 JavaScript 文件会明显延迟交互性,因此它可能成为一种代价高昂的资源,尤其是在移动设备上。

在不牺牲应用功能的前提下,缩减 JavaScript 包的最有效方法是引入积极的代码拆分。

代码拆分 让您可以将应用的 JavaScript 代码划分为与不同路由或功能关联的多个代码块。这种方法仅在初始应用加载期间向用户发送他们需要的 JavaScript 代码,从而保持较低的加载时间。

代码拆分技术

代码拆分可以在两个级别完成:组件级别路由级别

  • 在组件级代码拆分中,您可以将组件移动到它们自己的 JavaScript 代码块中,并在需要时延迟加载它们。
  • 在路由级代码拆分中,您可以将每个路由的功能封装到一个单独的代码块中。当用户导航您的应用时,他们会获取与各个路由关联的代码块,并在需要时获得关联的功能。

本文重点介绍如何在 Angular 中设置路由级拆分。

示例应用

在深入探讨如何在 Angular 中使用路由级代码拆分之前,让我们先看一下示例应用

查看应用模块的实现。在 AppModule 内部,定义了两个路由:与 HomeComponent 关联的默认路由和与 NyanComponent 关联的 nyan 路由

@NgModule({
  ...
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: '',
        component: HomeComponent,
        pathMatch: 'full'
      },
      {
        path: 'nyan',
        component: NyanComponent
      }
    ])
  ],
  ...
})
export class AppModule {}

路由级代码拆分

要设置代码拆分,需要重构 nyan 急切加载路由。

Angular CLI 的 8.1.0 版本可以使用以下命令为您完成所有操作

ng g module nyan --module app --route nyan

这将生成: - 一个名为 NyanModule 的新路由模块 - AppModule 中名为 nyan 的路由,该路由将动态加载 NyanModule - NyanModule 中的默认路由 - 一个名为 NyanComponent 的组件,当用户访问默认路由时将呈现该组件

让我们手动完成这些步骤,以便更好地理解如何使用 Angular 实现代码拆分!

当用户导航到 nyan 路由时,路由器将在路由器出口中呈现 NyanComponent

要在 Angular 中使用路由级代码拆分,请设置路由声明的 loadChildren 属性,并将其与动态导入结合使用

{
  path: 'nyan',
  loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}

与急切加载路由相比,有两个关键区别

  1. 您设置 loadChildren 而不是 component。当使用路由级代码拆分时,您需要指向动态加载的模块,而不是组件。
  2. loadChildren 中,一旦 Promise 被解析,您将返回 NyanModule 而不是指向 NyanComponent

上面的代码段指定,当用户导航到 nyan 时,Angular 应该从 nyan 目录动态加载 nyan.module,并呈现与模块中声明的默认路由关联的组件。

您可以使用以下声明将默认路由与组件关联

import { NgModule } from '@angular/core';
import { NyanComponent } from './nyan.component';
import { RouterModule } from '@angular/router';

@NgModule({
  declarations: [NyanComponent],
  imports: [
    RouterModule.forChild([{
      path: '',
      pathMatch: 'full',
      component: NyanComponent
    }])
  ]
})
export class NyanModule {}

当用户导航到 https://example.com/nyan 时,此代码将呈现 NyanComponent

要检查 Angular 路由器是否在本地环境中延迟下载 nyan.module

  1. 按 `Control+Shift+J`(或 Mac 上的 `Command+Option+J`)打开开发者工具。
  2. 点击 Network 选项卡。

  3. 在示例应用中点击 NYAN

  4. 请注意,nyan-nyan-module.js 文件出现在 Network 选项卡中。

Lazy-loading of JavaScript bundles with route-level code splitting

GitHub 上查找此示例。

显示微调器

现在,当用户点击 NYAN 按钮时,应用不会指示它正在后台加载 JavaScript。为了在加载脚本时给用户反馈,您可能需要添加一个微调器。

为此,首先在 app.component.htmlrouter-outlet 元素内部添加指示器的标记

<router-outlet>
  <span class="loader" *ngIf="loading"></span>
</router-outlet>

然后添加一个 AppComponent 类来处理路由事件。当此类听到 RouteConfigLoadStart 事件时,它会将 loading 标志设置为 true,当它听到 RouteConfigLoadEnd 事件时,会将该标志设置为 false

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  loading: boolean;
  constructor(router: Router) {
    this.loading = false;
    router.events.subscribe(
      (event: RouterEvent): void => {
        if (event instanceof NavigationStart) {
          this.loading = true;
        } else if (event instanceof NavigationEnd) {
          this.loading = false;
        }
      }
    );
  }
}

在下面的示例中,我们引入了 500 毫秒的人为延迟,以便您可以看到微调器在运行。

结论

您可以通过应用路由级代码拆分来缩小 Angular 应用的包大小

  1. 使用 Angular CLI 延迟加载模块生成器来自动搭建动态加载的路由。
  2. 当用户导航到延迟加载路由时,添加加载指示器以显示正在进行的操作。