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

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

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

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

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

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

.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的内容,可查看教程的第二部分git

你须要使用UglifyJsPlugin。默认状况下,它在mode: "produnction"是被启用。若是你倾向于不使用mode: "produnction",你能够手动添加UglifyJsPlugingithub

若是对UglifyJsPlugin不熟,可查看教程的第五部分web

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

Harmony是ES6和ES2015的代号。json

让咱们来研究有关例子。

// 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 */

/***/ (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方法。咱们来试验一下,使用下面的配置:

// 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的配置,以便于咱们清楚地看到咱们的代码发生了什么。使用上面的配置运行,获得下面输出:

/* (...) */

 

/* 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方法。

// index.js

import _ from 'lodash';

 

console.log(_.debounce);

  

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

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"实现。

// 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。

相关文章
相关标签/搜索