webpack学习之路(六)

Tree Shaking

  ps:官方文档中本节目录结构继承于起步。css

  Tree Shaking是一个经常使用于移除js环境中无用代码的术语,它依赖于ES2015模块系统中的静态结构特性好比import和export。它的名字和概念其实兴起于ES2015打包工具rollup。html

  webpack发行后就内置支持ES2015模块和无用模块导出检测。而webpack4又扩展了这个功能:经过package.js的"side effect"属性来提示编译器项目中哪些文件是纯粹的(能够放心地删除)。node

添加通用模块

  添加一个导出两个函数的通用模块:src/math.js。webpack

projectweb

webpack-demo
|- package.json
|- webpack.config.js
|- /dist
  |- bundle.js
  |- index.html
|- /src
  |- index.js
+ |- math.js
|- /node_modules

src/math.jsjson

export function square(x) {
  return x * x;
}

export function cube(x) {
  return x * x * x;
}

  把mode设置为开发模式来防止输出包被压缩:数组

webpack.config.js安全

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
- }
+ },
+ mode: 'development'
};

  在入口脚本中引入其中一个方法,为了简洁删除loadash:app

src/index.jside

- import _ from 'lodash';
+ import { cube } from './math.js';

  function component() {
-   var element = document.createElement('div');
+   var element = document.createElement('pre');

-   // lodash 是由当前 script 脚本 import 导入进来的
-   element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+   element.innerHTML = [
+     'Hello webpack!',
+     '5 cubed is equal to ' + cube(5)
+   ].join('\n\n');

    return element;
  }

  document.body.appendChild(component());

  如今咱们没有从src/math.js导入square方法,这个方法就成了未引用代码,也意味着应该被删除。如今构建一下项目观察一下输出包:

dist/bundle.js (around lines 90 - 100)

/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
/* unused harmony export square */
/* harmony export (immutable) */ __webpack_exports__["a"] = cube;
function square(x) {
  return x * x;
}

function cube(x) {
  return x * x * x;
}

  留意一下这个"unused harmony export square"注释,继续看一下往下的代码你会发现它没有被引用可是输出包里面依然有这个方法,接下来咱们会解决这个问题。

将文件标记为无反作用

  ps:反作用指的是一个模块被导入时会有一些特殊的行为而不仅是暴露出一个或多个export,好比polyfill,它会影响全局做用域并且不提供export。

  在一个纯粹的ESM模块世界中,识别反作用很简单,可是咱们无法达到这种程度,因此给webpack编译器一些关于你的代码的纯净度的提示是颇有必要的。

  解决方案就是package.json的"sideEffects"属性:

{
  "name": "your-project",
  "sideEffects": false
}

  以前的代码都没有什么反作用因此咱们能够简单地把属性设置为false来告诉webpack能够安全地删除全部的无用导出模块。

但若是你的代码有一些反作用那你能够提供一个数组:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js"
  ]
}

  这个数组支持相关文件的相对路径、绝对路径和glob模式。它内部使用micromatch。

  ps:任何导入的文件都会受到tree shaking的影响,也就是说若是你在项目中使用了css-loader导入了css文件,那这些文件也须要添加到tree shaking列表不然它就会在生产模式中被无心删掉。

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}

  最后,"sideEffects"也能够在module.rules配置选项中设置。

压缩输出:

  如上咱们已经可使用import和export找出那些须要被删除的无用代码,可是咱们还须要在输出包中删掉它们。为此咱们把mode设置为生产模式就能够压缩输出了:

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
- mode: 'development'
+ mode: 'production'
};

  ps:也能够在命令行中使用--optimize--minimize标记,它会在内部调用压缩插件UglifyJsPlugin。

  如今构建一下项目观察一下结果:如今整个输出包都已经被精简过了,square函数没有被引入并且cube函数也被精简过了(function r(e){return e*e*e}n.a=r)。通过tree shaking和输出压缩输出包小了几个字节,虽然这不算多可是在大型项目中会起到可观的效果。

结论

  为了学会使用 tree shaking,你必须……

  • 使用 ES2015 模块语法(即 import 和 export)。
  • 在项目 package.json 文件中,添加一个 "sideEffects" 入口。
  • 引入一个可以删除未引用代码(dead code)的压缩工具(minifier)(例如 UglifyJSPlugin)。

  你能够将应用程序想象成一棵树。绿色表示实际用到的源码和 library,是树上活的树叶。灰色表示无用的代码,是秋天树上枯萎的树叶。为了除去死去的树叶,你必须摇动这棵树,使它们落下。

相关文章
相关标签/搜索