首页 > 其他分享 >Angular 应用实现 Lazy Load(懒加载)的项目实战经验分享

Angular 应用实现 Lazy Load(懒加载)的项目实战经验分享

时间:2023-11-18 10:36:11浏览次数:29  
标签:Load Lazy module Module Angular 加载

笔者之前两篇掘金社区文章,分别介绍了企业级 Angular 应用开启 PWA 特性和服务器端渲染,从而提升用户体验的两种设计思路:

除了这两种 Angular 开发的最佳实践之外,将 Angular 应用进行庖丁解牛似的拆分,按照应用的业务逻辑,将代码块分离成若干个 Module,每个 Module 通过 Lazy Load 的方式按需加载,也是企业级 Angular 应用经常采取的一种优化手段。

从以上描述不难看出,Lazy Load 和代码拆分(Code Splitting)是相辅相成的。换句话说,代码拆分是 Lazy Load 机制工作的前提条件。代码拆分的结果是,当用户在浏览器地址栏里输入应用 url 时,不必一次性加载整个 Angular 应用程序,而是根据需要,动态加载特定部分的代码。Angular 代码拆分技术,有助于减少应用程序初始加载时间,和减小应用程序的整体大小。

这二者结合起来使用,无疑也是提升用户体验的另一种手段,因为用户可以更快速地开始使用应用,并且避免长时间的等待。

笔者所在的 Angular 开发团队,在开发 Spartacus 这个电商 Storefront 时,从语义化版本(Semantic Version) 的 Major 版本进行迭代时,也曾在项目代码重构过程中,对应用代码进行拆分和引入 Lazy Load 的支持。本文将笔者项目开发中的一些经验分享出来。

下面我们先以 Spartacus 6.0 为例,看看 Lazy Load 的直观效果。

Angular Lazy Load 的表现行为

我们首先在浏览器里打开 Spartacus 首页,在 Chrome 开发者工具 Network 面板观察首页渲染时,需要加载的 JavaScript 资源文件:

图1:Spartacus 首页渲染时加载的资源文件

可以看到包含了 storefinder.js, product.js, product-configurator.js 和 organization.js 等等。这些资源文件包含的都是 Spartacus 核心(Core)功能的实现。

我们首先点击 Clear 图标清除已经捕捉的 Network 请求,然后点击购物车图标,进入购物车页面:

图2:Spartacus 首页渲染所依赖的 core library 的加载行为

此时从 Network 面板能观察到一系列以 feature-libs 前缀开头的资源文件。这些资源文件就是以 Lazy Load 的方式被加载,解析和执行的。

图3:和购物车相关的 Modules 实现了 Lazy Load

显然,用户在访问首页时,只是浏览首页陈列的商品,这个业务行为同购物车的显示,逻辑上没有关联关系,因此将购物车的 UI 和服务,拆分成另一个单独的 Module,并对之施加以 Lazy Load,这是很自然并且合理的设计思路。

如何判断一个 Angular module 已经启用了 Lazy Load

最直接的办法,就是执行命令行 yarn start,在开发模式下查看 module 构建的情况。

如下图所示,Initial Chunk Files 列下的清单,就是使用 Eager Load 加载策略的 Angular module, 这也是 Angular module 缺省的加载方式。我们图 2 的 Network 面板里看到的 JavaScript 文件,都能在这个 Initial Chunk Files 下面找到。

而 Lazy Chunk Files 下给出的则是启用了 Lazy Load 的 module 清单。图3 罗列的点击了 Cart 图标之后出现在 Network 面板里的 JavaScript 文件,则会出现在这个列之下。

Angular module 启用 Lazy Load 的具体实现步骤

了解了 Angular module 启用了 Lazy Load 后的表现行为,以及判断标准,接下来我们就要学习如何启用 Lazy Load 了。

我们从图3 Network 面板里随便挑选一个被 Lazy Load 加载的 JavaScript 文件,比如 feature-libs_cart_quick-order_public_api_ts.js

然后在 Angular 项目里根据这个 public_api 文件,找到对应的 module 实现源代码,如下图所示:

图6:QuickOrderFeatureModule 实现 Lazy Load 的关键代码

@NgModule({
  imports: [QuickOrderRootModule],
  providers: [
    provideConfig({
      featureModules: {
        [CART_QUICK_ORDER_FEATURE]: {
          module: () =>
            import('@spartacus/cart/quick-order').then(
              (m) => m.QuickOrderModule
            ),
        },
      },
      i18n: {
        resources: quickOrderTranslations,
        chunks: quickOrderTranslationChunksConfig,
        fallbackLang: 'en',
      },
    }),
  ],
})
export class QuickOrderFeatureModule {}

其中的核心逻辑和奥妙,就在于第 25 行代码的 import('@spartacus/cart/quick-order').

代码第 22 行 featureModules 是一个映射,它将特性名称(在这里是 CART_QUICK_ORDER_FEATURE)映射到一个特性模块的加载函数。这个加载函数是一个返回 Promise 的函数,当这个 Promise 解析时,它将返回这个特性模块。在上面的源代码中,当用户点击了 Cart 图标需要加载 QuickOrderFeatureModule 功能模块时,Angular 将调用这个函数,动态地导入 QuickOrderModule。这就是 Angular 模块懒加载的关键部分:模块不会在应用启动时加载,而是在真正需要它们的时候才会动态加载

关于 import 关键字的更多详细介绍,可以查看 developer.mozilla.org 的官方文档:

图7:JavaScript 里实现 module 动态加载的 import 关键字

Lazy Load Angular module 的定制化支持

我们团队负责开发的 Spartacus 不仅包含了一个精简版的开箱即用的 Storefront,而且提供了一组 SDK,客户基于这组 SDK,能够快速开发出能够满足自己实际电商业务需求的 Storefront. 那么 Spartacus 标准的 Module,如果开启了 Lazy Load 机制,并且客户又希望对其进行定制,应该如何操作呢?

首先创建一个自定义 Feature Module,在这个 Feature Module 里,使用静态导入的方式,引入我们想要 Lazy Load 的 Spartacus 的标准 Module, 然后在 @NgModule 注解修饰的代码块里,在 providers 区域导入所有需要的 customizations.

下面是一个例子,在代码关键位置我加上了详尽的中文注释。

// 新建一个文件,取名为 custom-rulebased-configurator.module.ts,然后将下面源代码复制进去
import { RulebasedConfiguratorModule } from '@spartacus/product-configurator/rulebased';  // 使用静态导入,引入 Spartacus 标准的 Feature Module

@NgModule({
  imports: [RulebasedConfiguratorModule], // 将标准 Feature Module 导入到自定义 Module 的 imports 区域
  providers: [
    // 此处添加自定义 Module 实际的 Customization 开发
    { provide: ConfiguratorCartService, useClass: CustomConfiguratorCartService }
  ]
})
export class CustomRulebasedConfiguratorModule {}

最后,在 Storefront 应用的 app.module.ts 里,使用 import 关键字提供的动态导入功能,将上述代码里创建的自定义 Module,即 CustomRulebasedConfiguratorModule, 进行 Lazy Load 即可:

provideConfig({
  featureModules: {
    [RULEBASED_PRODUCT_CONFIGURATOR_FEATURE]: {
      module: () =>
        import('../custom-rulebased-configurator.module').then(
          (m) => m.CustomRulebasedConfiguratorModule
        ),
    },
  },
},

以上步骤完成之后,在构建阶段,Webpack 会自动将上述步骤创建的自定义 Module,构建成一个单独的 JavaScript Chunk 文件块, 这也再次印证了 Code Splitting 是发生在构建阶段,而非运行阶段

总结

本文首先介绍了 Angular Module Lazy Load 的基本概念和在企业级 Angular 应用中能给用户带来的价值,从最终用户视角给出了 Module 启用 Lazy Load 之后的表现行为,以及判断一个 Module 是否成功启用 Lazy Load 的标准。作为实战教程,本文也详细介绍了给定一个 Angular Module,如何针对其启用 Lazy Load,以及如何对一个已经启用了 Lazy Load 的 Module 进行定制化开发。

标签:Load,Lazy,module,Module,Angular,加载
From: https://www.cnblogs.com/sap-jerry/p/17840141.html

相关文章

  • Angular 应用的搜索引擎优化(SEO)实战指南
    笔者之前在掘金社区发表了两篇关于Angular开发的文章,分别介绍了Angular支持服务器端渲染和PWA的技术细节:基于AngularUniversal引擎进行服务器端渲染的前端应用StateTransfer故障排查案例Angular应用支持PWA(ProgressiveWebApplication)特性的开发步骤分享本......
  • 关于 Angular 项目里 ngsw-config.json 文件的作用
    ngsw-config.json文件是AngularServiceWorker的配置文件,用于配置AngularServiceWorker(ngsw)的行为。ServiceWorker是一个用于创建离线体验和缓存策略的技术,它允许您的应用在离线状态下继续运行,提高性能并实现“渐进式网络应用程序”(PWA)的特性。此文件允许开发者定义Service......
  • 关于 Angular Universal 应用渲染两次的问题
    AngularRepositoryurl:https://github.com/angular/angular-cli/issues/7477现象:Ibuiltasamplerepousingangular-cliandfollowedthestepsintheUniversalRenderingstorytoenableserversiderendering.Theapplicationloadswellonrunning,butIse......
  • 基于 Angular Universal 引擎进行服务器端渲染的前端应用 State Transfer 故障排查案
    笔者之前这篇掘金文章一个SAP开发工程师的2022年终总结:四十不惑提到,我目前的团队,负责开发一款基于Angular框架的电商Storefront应用。这个Storefront是一个开源的、基于Angular和Bootstrap并为SAPCommerceCloud构建的Angular应用程序。图1:SpartacusStore......
  • 关于 Angular 构建之后生成的 dist 目录和 esm2020, fesm2015 等等
    在Angular应用中,dist目录是构建应用后的输出目录,其中包含了已编译、打包和优化的应用文件。assets文件夹通常用于存放应用所需的静态资源,如图片、字体、配置文件等。esm2020、fesm2015和fesm2020是Angular构建过程中生成的文件夹,它们主要与Angular的模块加载系统和代码优化有关。......
  • 超大文件上传 WebUploader 断点续传,分片上传
    你只需要把这个HTML创建就能用,我这是从网上结合多个写的案例所改<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>文件上传</title><scriptsrc="https://code.jquery.com/jquery-3.4.1.slim.min.js"......
  • 编写loader 和 plugin
    编写一个loader在平时自己由零搭建项目时,虽然基础配置都比较熟悉,比如配置file-loader,url-loader,css-loader等,配置不难,但究竟是怎么起作用的呢,如何编写一个WebpackLoader。loader通常指打包的方案,即按什么方式来处理打包,打包的时候它可以拿到模块源代码,经过特定loader......
  • Microservice - Load Balancing (LB)
        ......
  • 关于 Angular SSR 应用 index.html 中的 serverApp-state script 元素
    首先,我们需要了解AngularSSR(Server-SideRendering)以及SSRTransferState。AngularSSR是Angular应用程序的服务端渲染技术,它允许Angular应用程序在服务器上渲染其组件,并生成静态HTML页面,再发送给客户端。这种方法可以提高首次加载速度,提升SEO效果。而SSRTransfe......
  • 单文件WebUploader做大文件的分块和断点续传
    前言:WebUploader是由BaiduWebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS6+,android4+。两套运行时,同样的调用方式,可供用户任意选用。 上面......