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,是樹上活的樹葉。灰色表示無用的代碼,是秋天樹上枯萎的樹葉。爲了除去死去的樹葉,你必須搖動這棵樹,使它們落下。

相關文章
相關標籤/搜索