typescript 使用库中的单个组件会导致延迟加载的模块在主包中结束

lqfhib0f  于 2022-11-26  发布在  TypeScript
关注(0)|答案(1)|浏览(184)

我已经创建了一个Bootstrap component library for angular沿着一个演示应用程序。然而,在构建应用程序时,主包的大小非常大。更值得注意的是,向库中添加组件,并向加载这些模块的应用程序中添加页面(延迟加载),最近将我的主包大小从650 kB增加到840 kB。
我已经检查了其他问题,如this one,但它没有给予我一个答案。

编辑5

I recreated the project in an angular workspace,用dist/lib-name参于tsconfig.json.即使在这里我也可以得出一个非常简单的结论:

  • 由于没有引用AppModule中的库组件,主包如预期的那样简单明了(328 kB):

  • 从我在应用程序中使用一个组件的那一刻起,库中的大量javascript块就被捆绑在主包(928 kB)中。

编辑4

我在一个有Angular 的工作空间中重新创建了我的项目,并得到了预期的结果:

总主束尺寸(js):509 kB。主束仅包含navbar
对于具有单个库的NX工作空间:

总主束尺寸(js):695 kB。注意所有不必要的块。我很确定在我的项目中没有索引导入(import {} from '../navbar'而不是import {} from '../navbar/navbar.module')。

编辑3

我似乎发现了一个问题。在逐步重新创建我的工作区时,我看到了以下内容:
当组件x1c4d 1x上没有动画时
这是我的主包

这是通用软件包(延迟加载)*

包含BsListGroup和BsCard
main.xxx.js包中的lib/components块如下所示:

仅包含导航栏
现在让我们在BsAlertComponent上放一个动画:

指令集
这是我的主包

我的公共包(包含BsListGroup和BsCard)看起来与*完全相同
然而,main包中的components块看起来像

,并且明显包含整个BsAlertComponent(我不需要)和项目中其他组件的大量垃圾...
PS.请修复SO文件上传器...

编辑2

created a minimal angular workspace(即使没有库),我可以看到所有与我在旧问题中描述的相同的行为(见下文)。
该应用包含3个组件,每个组件都有各自的模块,2*2个页面。BsNavbarModule加载在AppModule上,因为我在根目录中使用BsNavbarComponent

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BsNavbarModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

每个页面加载各自的组件。
转盘1页:

@NgModule({
  declarations: [
    CarouselOneComponent
  ],
  imports: [
    CommonModule,
    BsCarouselModule,
    CarouselOneRoutingModule
  ]
})
export class CarouselOneModule { }

画布外1页:

@NgModule({
  declarations: [
    OffcanvasOneComponent
  ],
  imports: [
    CommonModule,
    BsOffcanvasModule,
    OffcanvasOneRoutingModule
  ]
})
export class OffcanvasOneModule { }

你希望在这里看到什么?

  • 主束
  • 应用模块-〉应用组件
  • 导航栏模块-〉BsNavbar组件
  • 转盘一丛
  • 转盘一个模块
  • 转盘-双管束
  • 转盘双模块
  • bs-carousel捆绑包-〉bsCarousel模块
  • 帆布单束
  • 非平面单模块
  • 帆布双束
  • 非画布双模块
  • bs-offcanvas包-〉bsoffcanvas模块

我们得到了什么?

  • 主包-〉导航栏模块

  • 与转盘捆绑销售1第页
  • 与转盘捆绑销售2第页
  • 与Offcanvas捆绑销售1第页
  • 与Offcanvas 2捆绑销售第
  • BsCarouselModuleBsOffcanvasModule得一个大通用捆绑包(这不是我所期望得)

  • 主要,多边形填充,运行时,样式

为什么所有这些组件都捆绑在一起成为一个单一的捆绑包?当用户访问一个页面时,没有必要下载所有这些组件的js...在这个例子中,它只有大约2个组件,但在我的实际应用程序中,有像30个组件,其中大多数是捆绑在一起没有任何原因。

旧问题

换句话说,页面显然是惰性加载的:

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

const routes: Routes = [
  ...
  { path: 'range', loadChildren: () => import('./range/range.module').then(m => m.RangeModule) },
  { path: 'select', loadChildren: () => import('./select/select.module').then(m => m.SelectModule) }
];

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

我在主包上运行了webpack包分析器,注意到我的库中的所有模块都捆绑在我的主包中,只是因为我在AppModule中加载了BsNavbarModule

npm run build:wba
npm run analyze:wba

红色的Stuff都是主包的一部分,尽管我从来没有在AppModule中使用import组件的模块,只在延迟加载的模块中使用。BsNavbarComponentAppComponent上使用,所以另一方面,BsNavbarModule需要在主包中。我也有这样的印象,因为所有这些,@angular/core@angular/common软件包比实际需要的要大得多。
另一个问题是,我在一些延迟加载的页面中使用了ngx-highlighjs,而这个库要求您在根级别指定HIGHLIGHT_OPTIONS。因此,您还可以看到整个ngx-highlightjs库打包在主包中,即使我只在另一个延迟加载的页面上加载模块...

我的库的module被指定为"esnext"
我尝试将"sideEffects": false添加到package.json,结果如下:

但还是不能解决我的问题...
如何解决这个问题?为什么AppModule中没有加载的角模块捆绑在主包中?

编辑

我创建了一个空白的Angular 应用程序:

已安装我的库并添加了全局样式:

并创建了一个页面(ng g module demo --module app --route demo),并在上面添加了BsNavbarComponent

这立即增加了我的主要捆绑大小与50 kB...

dsekswqp

dsekswqp1#

根据编辑2的答案,而不是旧问题。

为什么将所有这些组件捆绑到一个包中?(common.js块)

  • 一个包含BsCarouselModule和BsOffcanvasModule的大型通用包(这不是我所期望的)

这种行为是一种默认的优化技术,您可以通过在angular.json中指定commonChunk: false来关闭它。但是,通常最好保持打开,因为通过将跨多个bundle使用的代码放在一个地方(common.js块),可以消除共享代码的重复。

"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      ...
      "commonChunk": false,
    ...

我已使用您的minimal angular workspace比较了以下ng build --source-map输出:

公用块:true(预设值)

ng构建输出(common.js块、更快的后续延迟加载、更小的延迟块)

公用块:假的

ng构建输出(无common.js块、较慢的延迟加载、较大的延迟块)

那么,什么时候在UI中加载公共块呢?

这取决于你的导入。在我看来,如果你在你的主包中导入了一个模块,而这个模块最终出现在了公共块中(因为你也在懒惰模块中导入了这个模块),那么在初始渲染过程中,公共块就会被加载,这可能会影响性能。
基本上,为了防止在初始呈现中加载公共块,您希望尽可能避免在主块和惰性块中导入相同的模块。
这不是你提供的最小工作空间的问题,但我高度怀疑这是你的老问题的情况。
网络选项卡(最小工作空间,commonChunk: true)显示初始渲染时未加载公共块:

commonChunk: false在最终发送到客户端的js数量上也有一个小小的折衷。但可以通过实现预加载策略来缓解这种情况(无论如何,您都应该对延迟加载执行此操作,但这超出了本问题的范围)。

相关问题