配置Tree Shaking来减少JavaScript的打包体积

栏目: 编程工具 · 发布时间: 7年前

内容简介:译者按:用Tree Shaking技术来减少JavaScript的Payload大小小编推荐:Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和Java线上bug实时监控。真的是一个很好用的bug监控服务,众多大佬公司都在使用。

译者按:用Tree Shaking技术来减少JavaScript的Payload大小

配置Tree Shaking来减少JavaScript的打包体积

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

小编推荐:Fundebug专注于JavaScript、微信小程序、微信小游戏,Node.js和 Java 线上bug实时监控。真的是一个很好用的bug监控服务,众多大佬公司都在使用。

如今一个网页应用可以体积很大,特别是JavaScript代码。2018年年中, HTTP Archive 统计在移动端JavaScript文件的平均传输大小将近350KB。你要知道,这仅仅是传输的大小。在网络传输的时候,JavaScript往往是经过压缩的。也就是说,在浏览器解压缩之后,实际的大小会远远大于这个值。而这一点相当重要。如果考虑到浏览器处理数据的资源消耗,其中压缩是不得不考虑的。一个300KB的文件解压缩会达到900KB,并且在分析和编译的时候,体积依然是900KB。

配置Tree Shaking来减少JavaScript的打包体积

其实,处理JavaScript是很耗资源的。不像图片只会在下载的时候有一点简单的解码处理,JavaScript需要分析,编译,然后再被执行。一个字节一个字节地处理,所以JavaScript的处理很贵。

配置Tree Shaking来减少JavaScript的打包体积

为了 优化JavaScript引擎 ,各种 改进方法 被提出来。提升JavaScript代码的性能,是开发者最擅长的事情。毕竟,有谁比架构师更擅长优化架构的性能呢?

Code splitting 是其中一个用来提升性能的方法,通过将JavaScript应用拆分成一个个块,然后在需要的时候才下载。这个方法很好,但是有一个很常见的问题没有处理,那就是有很多打包的代码我们压根没有用到。为了解决这个问题,我们用tree shaking。

什么叫tree shaking ?

Tree shaking 是一种消除无用代码(dead code)的方式。这个词是由最先从 Rollup 社区开始流行的,不过本身的理念很早就有了。在 webpack 中也有相同的理念,在本文我们会用一个例子来描述。

“tree shaking”这个词来自于应用的架构以及本身的依赖关系就像一个树形结构。树的每一个节点表示应用中一个唯一的功能。在现代网页应用中,依赖关系通常使用 static import statement ,如下所示:

// Import all the array utilities!
import arrayUtils from "array-utils";

注意:如果你不了解ES6,我强烈推荐你阅读 Pony Foo上面的这篇文章 。我们这篇文章假定你对ES6有一定的了解。如果没有,赶紧学学去吧。

当你的app还很小的时候,也许只有很少的依赖文件。而且应该几乎使用了所有你自己添加的依赖。但是,当你的app开发了一段时间,越来越多的依赖添加进去。由于各种原因,旧的依赖可能根本没有使用了,但是呢依然在你的代码库里面,没有被删除。最终导致你的app夹带了很多并 没有使用的JavaScript 。通过分析我们如何使用import语句,tree shaking会移除无用代码。

// Import only some of the utilities!
import { unique, implode, explode } from "array-utils";

这个import语句和之前的区别在于,与其引入整个array-utils,而整个array-utils可能有非常多的函数,不如只引入我们需要的部分。在开发构建的时候,这两种使用方法并没有区别。但是在生产打包的时候,我们可以配置webpack来剔除不需要的函数,使得整个代码文件变小。在这篇文章中,我们会指导你如何做。

案例

为了演示起见,我写了一个简单的 单页应用 。你可以克隆代码并跟着操作。我会详细描述每一步,所以克隆不是必备步骤。

示例是一个可以搜索吉他效果器的数据库。

配置Tree Shaking来减少JavaScript的打包体积

应用在构建的时候,所有的JavaScript文件打包成了一个vendor和一个app文件。

配置Tree Shaking来减少JavaScript的打包体积

上图中的文件是打包后的结果,已经经过 uglification 。21.1KB的大小完全可以接受。不过,当前是没有使用tree shaking来优化的结果。我们来看看如何进一步优化。

在任何应用中,寻找使用tree shaking优化的机会首先要寻找import语句。 一般都在component文件的顶部 ,像这样:

import * as utils from "../../utils/utils";

也许你已经看过这样的语句。其实ES6中有多种导入模块的方法,不过这样的导入语句最值得注意。因为它意味着导入utils模块中的所有函数,并放到utils的命名空间下面。所有,一个最大的疑问是:在模块中到底有多少函数?

如果你查看 utils模块的源代码 ,你会发现真的很多。大概有1300行的代码量。

不过,别担心。也许所有的函数都在当前文件中使用了,对吧?我们真的需要所有的函数吗?我们来检查一下,通过查找 utils. ,看看有几处使用。结果呢:

配置Tree Shaking来减少JavaScript的打包体积

好吧,总共只找到了3处。

我们再看看具体是哪个函数?如果我们一个一个地查看,会发现其实只用了一个函数,就是 utils.simpleSort

if (this.state.sortBy === "model") {
  // Simple sort gets used here...
  json = utils.simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  // ..and here...
  json = utils.simpleSort(json, "type", this.state.sortOrder);
} else {
  // ..and here.
  json = utils.simpleSort(json, "manufacturer", this.state.sortOrder);
}

也就是说,我们引入了一个1300行的文件,结果只使用了其中一个函数。

当然,我们要承认这个例子为了演示目的,可能有故意之嫌。不过,它表述了一个事实,那就是在很多真实的应用中,存在着像这样需要优化的地方。那么如何做呢?

禁止Babel将ES6编译到CommonJS

Babel 在很多应用中已经必不可少。不幸的是,它会让tree shaking变得困难。如果你使用 babel-preset-env ,它会将你的ES6编译到可兼容性更好的CommonJS。

问题在于对于CommonJS,tree shaking非常困难,而且webpack不知道哪些需要消除掉。不过呢,好在有一个很简单的解法:配置 babel-preset-env ,让其保持ES6不动,不要翻译。具体的配置放在你配置Babel的地方( .babelrc 或则 package.json ):

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ]
}

简单地配置 "modules":false 即可,webpack会分析所有文件中模块的依赖关系,然后剔除那些没有使用的代码。并且,这个处理不会有兼容问题,因为webpack最终会将代码转换到兼容的版本。

谨记副作用(Side Effect)

另一个需要考虑的是:应用中使用模块是否有副作用。我举一个例子来说什么叫副作用(这个例子表述了在一个函数中去修改函数外部的变量):

let fruits = ["apple", "orange", "pear"];

console.log(fruits); // (3) ["apple", "orange", "pear"]

const addFruit = function(fruit) {
  fruits.push(fruit);
};

addFruit("kiwi");

console.log(fruits); // (4) ["apple", "orange", "pear", "kiwi"]

在这个例子中, addFruit 修改了 fruit 数组,而 fruit 数组是全局的。

只有当函数给定输入后,产生相应的输出,而不修改任何外部的东西,我们才可以安全的做shaking操作。

所以,在webpack中,我们可以通过配置 "sideEffects":false 表示模块是安全的,没有副作用的。

{
  "name": "webpack-tree-shaking-example",
  "version": "1.0.0",
  "sideEffects": false
}

或则,你可以告诉webpack哪些文件有副作用:

{
  "name": "webpack-tree-shaking-example",
  "version": "1.0.0",
  "sideEffects": [
    "./src/utils/utils.js"
  ]
}

在上面的配置中,webpack会假定其它文件都是无副作用的。如果你不想添加到 package.json 文件中,你可以配置 module.rules

按需导入

我们可以只导入我们需要使用的函数,在示例中,我么只需要 simpleSort

import { simpleSort } from "../../utils/utils";

使用上面的语法,我们就只会将simpleSort函数导出,我们只需要将 utils.simpleSort 改为 simpleSort

if (this.state.sortBy === "model") {
  json = simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  json = simpleSort(json, "type", this.state.sortOrder);
} else {
  json = simpleSort(json, "manufacturer", this.state.sortOrder);
}

接下来我们看看执行效果,首先回顾之前的打包效果:

配置Tree Shaking来减少JavaScript的打包体积

接下来看使用了tree shaking后的效果:

配置Tree Shaking来减少JavaScript的打包体积

两个模块都变小了,特别是main文件。通过将utils中无用代码删掉,整个体积削减了60%。这不仅节省了下载时间,而且节省了处理时间。

其他情况

在大多数情况下,上面的方法就足够了。但是,总有例外的情况会让你抓耳挠腮。比如, Lodash 就不行。因为Lodash当时的架构就不支持,所以需要一些额外的工作:a) 安装 lodash-es 来替代lodash;b) 使用稍微不同的语法(叫做cherry-picking):

// This still pulls in all of lodash even if everything is configured right.
import { sortBy } from "lodash";

// This will only pull in the sortBy routine.
import sortBy from "lodash-es/sortBy";

如果你倾向于使用一致的import语法,你可以使用标准的lodash包,然后安装 babel-plugin-lodash

如果有些模块使用CommonJS格式(module.exports),那么webpack无法使用tree shaking。一些插件( webpack-common-shake )为CommonJS提供tree shaking。但是,因为 有些CommonJS的模式是无法做tree shaking的 。如果你想很保险地剔除掉没有使用的依赖,ES6才是你最佳的选择。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。

自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

配置Tree Shaking来减少JavaScript的打包体积

版权声明:
转载时请注明作者<b><a href="https://fundebug.com" target="_blank" title="Fundebug">Fundebug</a></b>以及本文地址:
<b><a href="https://blog.fundebug.com/2018/08/15/reduce-js-payload-with-tree-shaking/" target="_blank" title="配置Tree Shaking来减少JavaScript的打包体积">https://blog.fundebug.com/2018/08/15/reduce-js-payload-with-tree-shaking/</a></b>

您的用户遇到BUG了吗?

体验Demo 免费使用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Iterative Methods for Sparse Linear Systems, Second Edition

Iterative Methods for Sparse Linear Systems, Second Edition

Yousef Saad / Society for Industrial and Applied Mathematics / 2003-04-30 / USD 102.00

Tremendous progress has been made in the scientific and engineering disciplines regarding the use of iterative methods for linear systems. The size and complexity of linear and nonlinear systems arisi......一起来看看 《Iterative Methods for Sparse Linear Systems, Second Edition》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具