JavaScript树摇晃,像专业人士

这是一篇有关优化和减少应用程序包大小的文章的翻译。很好,因为这里描述了最佳实践,还包括一些技巧,这些技巧使Trishhing工作并从程序集中抛出未使用的代码。这将对许多人有用,因为现在每个人都使用开箱即用的装配系统。但是,要使其正常工作,您必须遵守以下原则。

图片

当您需要减少分发包的大小并提高JS上的应用程序性能时,Trichashing成为主要技术。

trichashing的工作原理:

  1. 您在每个模块中声明导入和导出。
  2. 收集器(Webpack,汇总或其他)在组装过程中分析依赖关系树。
  3. 未使用的代码将从最终捆绑包中排除。

图片
该实用程序文件导出两个函数,

图片
但是仅使用initializeName,可以删除formatName。

不幸的是,为使摇动正确进行,仅设置一个收集器是不够的。为了获得更好的结果,有必要考虑许多细节,并确保在优化过程中未跳过模块。

从哪里开始?


有大量的准则来设置摇动。最好从官方Webpack文档开始深入探讨该主题

值得一提的是,几年前,我创建了一个样板,该样板具有已配置的装配体和Trichashing。因此,如果您需要一个项目的起点,那么我的存储库可以成为krakenjs / grumbler的一个很好的例子

本文讨论使用Webpack,Babel和Terser。但是,无论您使用Webpack,Rollup还是其他方法,本文介绍的大多数原理都将起作用。

使用ES6语法进行导入和导出


使用ES6进出口是进行Trichashing的第一步,也是最重要的一步。

在构建过程中,“模块”模式的大多数其他实现(包括commonjs和require.js)都是不确定的。此功能不允许Webpack等收集器准确确定要导入的内容,要导出的内容以及因此可以安全删除的代码。

图片
使用commonjs时可能的选项。

使用ES6模块时,导入和导出选项受到更多限制:

  • 您只能在模块级别导入和导出,而不能在函数内部导入和导出。
  • 模块名称只能是静态字符串,不能是变量;
  • 您导入的所有内容都必须导出到某个地方。

图片
ES6模块具有更简单的语义和使用规则。

简化的规则使汇编程序可以准确了解导入和导出的内容,并因此确定根本不使用哪个代码。

禁止Babel运输进出口


使用Babel转换代码时可能遇到的第一个问题是将ES6模块默认转换为commonjs。这样可以防止收集器优化代码并抛出过多代码。

幸运的是,在Babel配置中,有一种简单的方法可以禁用模块转换

完成此操作后,收集器将可以承担进出口的转运工作。

使您的出口原子化


在以下情况下,Webpack通常不影响导出:

  • ;
  • ;
  • .

此类出口将完全包含在捆绑包中,或完全删除。因此,最终,您可能会得到一个捆绑包,其中包含永远不会使用的代码。

图片
即使仅使用一个功能,这两个功能也将包含在捆绑软件中。

图片
在这里,该类将完全添加到程序集中。

尝试使您的出口尽可能小而简单。

图片
只有将要使用的功能才会进入最终捆绑包。

遵循此建议,收集器可以抛出更多代码,因为在汇编过程中,您现在可以跟踪导入和使用了哪个功能,而哪些不是。

本技巧还有助于以更实用和可重用的风格编写代码,并避免在不合理的情况下使用类。

如果您对函数式编程感兴趣,请查阅本文

避免模​​块级别的副作用


在编写模块时,许多人会忽略一个重要但非常隐蔽的因素-副作用的影响。

图片
Webpack无法理解window.memoize的功能,因此无法抛出此功能。

请注意,上面的示例window.memoize将在导入模块时调用。

正如Webpack所见:

  • 好的,在这里创建并导出一个纯添加函数-如果以后不再使用,也许可以删除它;
  • 然后调用window.memoize,将add传递到该窗口。
  • 我不知道她在做什么window.memoize,但我知道她可能会打电话给add并产生副作用。
  • 因此,为了安全起见,即使没有其他人使用 add功能,我也会将其保留在包中

实际上,我们确定它window.memoize是一个纯函数,不会产生任何副作用,如果有人使用它,则会调用add memoizedAdd

但是Webpack不知道这一点,为了和平起见,将add函数添加到了最终的bundle中。

老实说: Webpack和Terser 最新版本在检测副作用方面异常出色。

图片
我们为Webpack提供更多信息并获得优化的捆绑包。

现在,收集器具有足够的信息用于分析:

  • memoize在模块级别调用,可能会遇到很多问题;
  • 但是功能memoize来自ES6导入,您需要查看中的功能util.js
  • 实际上,memoize看起来像一个纯函数,没有副作用;
  • 如果没有人使用该函数add,我们可以安全地将其从最终捆绑包中排除。

当Webpack没有收到足够的信息来做出决定时,它将采用安全的路径并退出该功能。

使用工具识别潜在的震动问题


我发现了两种确定问题的工具。

第一个工具是模块串联(Webpack的插件),它可以使您显着提高性能。它具有调试选项。值得注意的是,阻止串联和trichashing的因素是相同的:例如,模块级别的副作用。认真对待插件的警告,因为任何问题都可能会增加捆绑软件的大小。

第二个是linter https://www.npmjs.com/package/eslint-plugin-tree-shaking的插件我还没有将其集成到样板中,因为在我进行实验时它不支持流程。但是,他很好地确定了trichashing的问题。

小心库


尝试使用针对Trichashing优化的库。例如jquery.min.js如果导入一大堆最小化的代码,则可能不会优化此模块。最好寻找一个可以从其导入原子功能的模块,而对于组装和缩小,请使用Webpack或Rollup。

有时您可以导入整个库。例如,当使用React生产版本时,您不需要扔掉任何东西-其中的所有内容都已经优化。

如果您使用导出单个函数的库,例如lodash,请尝试仅导入必要的函数,并确保其他函数不包含在最终捆绑包中。

使用构建标志


Webpack的DefinePlugin 插件具有一个很棒的功能,但不是最著名的功能-影响在构建过程中将排除哪些代码的功能。

图片

如果我们将其传递__PRODUCTION__: true给插件,那么最终的bundle中不仅会包含函数调用validateOptions,还会包含其定义。
这简化了用于开发和生产的不同捆绑软件的创建,并且还有助于确保用于调试的代码不会进入生产环境。

开始组装


很难确定Webpack如何优化特定模块。

因此,运行构建,检查最终的捆绑包,看看会发生什么。看一下JavaScript代码,确保其中没有多余的东西应该通过trichashing丢弃。

还有吗


如果您知道其他有用的提示,请在评论中写上。

All Articles