温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Webpack 4教程 - 第七部分 减少打包体积与Tree Shaking

发布时间:2020-07-20 21:19:17 来源:网络 阅读:700 作者:powertoolsteam 栏目:web开发

转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
原文出处:https://wanago.io/2018/08/13/webpack-4-course-part-seven-decreasing-the-bundle-size-with-tree-shaking/

在本次Webpack 4教程中,我们会更进一步讲述项目优化。我们会学习什么是tree shaking以及如何使用它。你会找到让Webpack 4中tree shaking运作起来所需要的东西,并知道怎样从中受益。开始吧!

首先,让我们来回答什么是tree shaking以及它带来什么好处。我们常常在文件中使用具名引入(named imports),这些引入的文件里有其他导出(exports)。在某些情况下,我们并没有引入所有的导出,但Webpack仍会把整个模块都导入进来。这种情况下就需要使用tree shaking了,因为它能帮助我们去除掉用不到的代码。因此打包后的体积能显著下降。

如果你想了解更多关于improts和exports的内容,请查看我们的第一部分-入口、输出和ES6模块。

为了让tree shaking起作用,你需要满足一些配置要求。首先,必须使用ES 6模块,而不是使用诸如CommonJS的模块处理方式。如果你在使用Babel,这一点可能已让你遇到麻烦了。因为Babel的预置默认把任何模块转译成CommonJS模块。你可以简单设置modules: false来解决此问题,在.babalrc或者webpack.config.js中设置都可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
.babelrc
 
{
 
  "presets": [
 
    ["env",
 
      {
 
        "modules"false
 
      }
 
    ]
 
  ]
 
}
 
// webpack.config.js
 
module: {
 
  rules: [
 
    {
 
      test: /\.js$/,
 
        exclude: /(node_modules)/,
 
          use: {
 
            loader: 'babel-loader',
 
            options: {
 
              presets: ['env', { modules: false }]
 
            }
 
          }
 
    }
 
  ]
 
},

  

如果你想阅读更多babel-loader或常规loaders的内容,可查看教程的第二部分。

你需要使用UglifyJsPlugin。默认情况下,它在mode: "produnction"是被启用。如果你倾向于不使用mode: "produnction",你可以手动添加UglifyJsPlugin

如果对UglifyJsPlugin不熟,可查看教程的第五部分。

还有一件记得做的事情是,你需要打开optimization.usedExports。它同样在mode: "produnction"时被默认添加上去了。它告诉Webpack去决定每一个模块所用到的导出。有了它,Webpack会在你的打包产出里添加额外的像是/* unused harmony export */之类的注释,UglifyJsPlugin在之后会使用到它们。

Harmony是ES6和ES2015的代号。

让我们来研究有关例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// utilities.js
 
export function add(a, b) {
 
  return a + b;
 
}
 
  
 
export function subtract(a, b) {
 
  return a - b;
 
}
 
// index.js
 
import { add } from './utilities';
 
  
 
console.log(add(1,2));
 
console.log(add(3,4));

  

以正常配置运行Webpack,我们得到像下面这样的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*(...)*/
 
  
 
/* 1 */
 
/***/ (function(module, __webpack_exports__, __webpack_require__) {
 
  
 
"use strict";
 
__webpack_require__.r(__webpack_exports__);
 
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add"function() { return add; });
 
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "substract"function() { return substract; });
 
function add(a, b) {
 
  return a + b;
 
}
 
function subtract(a, b) {
 
  return a - b;
 
}
 
  
 
/***/ })
 
/******/ ]);

  

正如你看到的,Webpack没有对我们的打包输出进行tree-shaking。这里同时有addsubtract方法。我们来试验一下,使用下面的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// webpack.config.js
 
const webpack = require('webpack');
 
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
 
const UglifyJS = require('uglify-es');
 
  
 
const DefaultUglifyJsOptions = UglifyJS.default_options();
 
const compress = DefaultUglifyJsOptions.compress;
 
for(let compressOption in compress) {
 
  compress[compressOption] = false;
 
}
 
compress.unused = true;
 
  
 
module.exports = {
 
  mode: 'none',
 
  optimization: {
 
    minimize: true,
 
    minimizer: [
 
      new UglifyJsPlugin({
 
        uglifyOptions: {
 
          compress,
 
          mangle: false,
 
          output: {
 
            beautify: true
 
          }
 
        },
 
      })
 
    ],
 
  }
 
}

  

我已经关掉了大部分UglifyJsPlugin的配置,以便于我们清楚地看到我们的代码发生了什么。使用上面的配置运行,得到下面输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* (...) */
 
  
 
/* 0 */
 
/***/ function() {
 
  "use strict";
 
  // CONCATENATED MODULE: ./src/utilities.js
 
  function add(a, b) {
 
    return a + b;
 
  }
 
  // CONCATENATED MODULE: ./src/index.js
 
  console.log(add(1, 2));
 
  console.log(add(3, 4));
 
  /***/}
 
/******/ ]);

  

由于使用了UglifyJsPluginoptimization.usedExportsunused选项,不需要的代码被移除了。请注意,那是UglifyJsPlugin的默认行为,所以使用默认配置也能去除无用的代码(当然这样还会进行其他压缩处理)。

Tree shaking函数库

如果你打算对函数库进行tree shaking,你需要记得上一段提到的是事情:使用ES6模块,而它并不是总是被函数库使用。一个绝佳的例子是lodash。如果你去看它提供的产品代码,可以清楚地看到它并没有使用ES6模块

试想我们打算使用lodash提供的debounce方法。

1
2
3
4
5
6
7
// index.js
 
import _ from 'lodash';
 
  
 
console.log(_.debounce);

  

现在你的输出里包含了整个lodash库。当使用import _ from 'lodash'时,这无法避免。但不要担心!有人已经思考过此问题,并创建了一个包叫做lodash-es。它以ES6模块的形式提供了lodash库。

1
2
3
4
5
import { debounce } from 'lodash';
 
  
 
console.log(debounce);

  

不幸的是,Webpack会tree shaking失败。按照ECMAScript规范,所有子模块都需要被评估,因为它们可能包含副作用(side effects)。我推荐阅读一篇Stack Overflow上Sean Larking的好文章(他是Webpack核心团队的成员)。如果一个包的作者想要提供信息以标识它的库没有副作用,他可以在包的package.json文件里做这件事情。如果你查看lodash代码库的package.json文件,你可以看到它有一个"sideEffects: false"。那么问题出在哪儿呢?

Webpac默认会忽略sideEffect标识。如果想改变这种行为,我们需要吧optimization.sideEffects设置成true。你可以手动设置,或者通过mode: "produnction"实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// webpack.config.js
 
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
 
const HtmlWebpackPlugin = require('html-webpack-plugin');
 
  
 
module.exports = {
 
  mode: 'none',
 
    optimization: {
 
      minimize: true,
 
      minimizer: [
 
        new UglifyJsPlugin()
 
      ],
 
      usedExports: true,
 
      sideEffects: true
 
    },
 
  plugins: [
 
    new HtmlWebpackPlugin()
 
  ]
 
}

  

现在lodash库能够被Webpack进行tree shaking了。

总结

为了使tree shaking起作用,需要满足许多条件。它是个很有用的特性,当然也值得学习。希望你通过本文了解如何使用它,让打包后的体积大幅减小。记住你需要使用ES6模块UglifyJsPlugin。另外,记得配置optimization,把usedExportssideEffects设为true。

 



本文是由葡萄城技术开发团队发布,转载请注明出处:葡萄城官网

了解开放易用的 Web 生成平台,请前往活字格Web应用生成平台

了解可嵌入您系统的在线 Excel,请前往SpreadJS纯前端表格控件


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI