【问题标题】:Angular Tree Shaking: How exactly does it work?Angular Tree Shaking:它究竟是如何工作的?
【发布时间】:2020-06-04 20:30:50
【问题描述】:

我们目前正在尝试优化复杂的 Angular 应用程序(性能和包大小)。

我们发现我们有部分未使用的组件,但我们不能 100% 确定它们。无论如何......我们目前要问的问题是,摇树在 Angular 中究竟是如何工作的。

问题 1) 如果一个模块的声明、导入或提供程序数组中有条目,但该模块没有在任何地方使用,它们是否也被树摇晃删除了,或者它们是否包含在最终捆绑包?

例子:

@NgModule({
  imports: [
    FirstModule,
    SecondModule  // Is not used anymore (probably) but imported here
  ],
  declarations: [SampleComponent] // Is not used anymore (probably) but imported here
})
export class SampleModule {
}

信息:该模块/组件的路由已被删除。

问题 2) 仅从路由模块中移除这些组件是否足以使摇树过程成功?

问题 3) 应该具备哪些条件才能使 treeshaking 过程以最佳方式工作?

使用 Angular 8.2 版

【问题讨论】:

  • 取决于您是否使用 Ivy。你在用 Ivy 吗?
  • 不,我们目前使用的是 Angular 8.2.x 版本
  • @kvetis 有同样的问题,但我们使用的是 Ivy,它会删除模板和控制器中未使用但包含在声明组件中的吗?

标签: angular typescript angular-cli angular8 tree-shaking


【解决方案1】:

关于 Angular 中的 tree-shaking 工作原理

Tree-shaking 主要在缩小阶段完成,并不特定于 Angular。 terser 是他们在 Angular CLI 中使用的缩小器,它是 Uglify 的一个分支,支持 ES6 语法。

terser 读取您的代码,如果它没有在其他地方引用,并且可以确定删除某些代码不会有副作用,那么它将删除该代码。

terser 不能确定带有装饰器的类是否在被定义时有副作用(装饰器是函数调用)。在 Angular 的生产版本中,他们有一个名为“build-optimizer”的 webpack 插件,它将转到使用装饰器的地方,并在已编译的 javascript(来自 Typescript)旁边添加一个特殊注释 /*@__PURE__*/,terser 识别并删除装饰类(如果没有在其他地方引用)。

关于从 NgModule 中移除组件

构建过程从您的main.ts 文件开始,并抓取所有文件的所有导入以包含在您的构建中。如果从 main.ts 文件中,爬虫过程找到的任何文件都不会导入您的组件文件,则它永远不会被包含在内。这不是 tree-shaking,它根本不包含在构建过​​程中。

如果您的模块文件是导入组件文件的唯一位置,那么删除该导入将足以不将该组件包含在您的构建中。

关于您可以做的事情

您可以进行一些特定于 Angular 的更改,以确保您只构建您使用的代码。

  1. 为Injectable 使用{providedIn: root} 装饰选项,并从任何Angular 装饰的providers: [] 中删除任何可注入服务、保护、任何东西的地方。
  2. 使用 Ivy 渲染器,这意味着捆绑的框架更少(如果您不使用它)。

此外,在调用站点(不是定义),您可以使用 /@__PURE__/ 注释标记任何没有副作用的函数,这样即使它们在某处被调用,如果返回值可以通过其他一些优化删除该功能本身也可以删除。我没有对此进行测试,但理论上它应该可以工作。

我不知道所有不同的构建阶段如何转换您的代码,以及它们是否会在 terser 看到它们之前移动或移除 cmets。

您可以使用这个 Playground 工具对其进行测试: https://terser-playground.surge.sh/

试试这个例子:

(function() {
  const a = 1;
  const b = 2;
  const c = /*@__PURE__*/ test();
  console.log(a + b);
}());

function test() {
  return 3
}

【讨论】:

【解决方案2】:

您可以使用webpack-bundle-analyzer,这将帮助您在最终输出文件中可视化大小和不同使用的组件。这样你就可以确定一个模块是否被使用,然后你可以安全地删除它。

【讨论】:

  • 但是如何在 Angular 中使用它?您需要自己运行ng eject 并连接您的构建过程吗?
  • @KevinBeal npm install -D webpack-bundle-analyzer;使用分析数据进行构建:将 --stats-json 添加到您的 ng build 命令中。查看生成的分析:webpack-bundle-analyzer
猜你喜欢
  • 1970-01-01
  • 2020-05-16
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多