1. 程式人生 > 其它 >webpack2 的 tree shaking

webpack2 的 tree shaking

tree shaking

  [ʃeɪk]

  • v.搖;發抖;震動;動搖
  • n.抖動;搖動;顫動

即 webpack 在打包的過程中會將沒用的程式碼進行清除(dead code)。

一般 dead code 具有一下的特徵:

  1. 程式碼不會被執行,不可到達
  2. 程式碼執行的結果不會被用到
  3. 程式碼只會影響死變數(只寫不讀)

使 tree shaking 生效:

首先,模組引入要基於 ES6 模組機制,不再使用 commonjs 規範,因為 es6 模組的依賴關係是確定的,和執行時的狀態無關,可以進行可靠的靜態分析,然後清除沒用的程式碼。而 commonjs 的依賴關係是要到執行時候才能確定下來的

這就涉及到es6模組的知識了

commonJS 模組
commonJS的模組規範在Node中發揚光大,總的來說,它的特性有這幾個:

1.動態載入模組
commonJS和es6的最大區別大概就在於此了吧,commonJS模組的動態載入能夠很輕鬆的實現懶載入,優化使用者體驗。

2.載入整個模組
commonJS模組中,匯出的是整個模組。

3.每個模組皆為物件
commonJS模組都被視作一個物件。

4.值拷貝
commonJS的模組輸出和 函式的值傳遞相似,都是值的拷貝

es6 模組
1.靜態解析
即在解析階段就確定輸出的模組,所以es6模組的import一般寫在被引入檔案的開頭。

2.模組不是物件
在es6裡,每個模組並不會當做一個物件看待

3.載入的不是整個模組
在es6模組中經常會看見一個模組中有好幾個export 匯出

4.模組的引用
es6模組中,匯出的並不是模組的值拷貝,而是這個模組的引用

瞭解原理後開始測試

初始化專案

npm init 

安裝webpack包

npm install webpack webpack-cli --save-dev

配置檔案

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>起步</title>
  </head>
  <body>
    <script src="./dist/main.js"></script>
  </body>
</html>

index.js

import vue from './vue';
import test from './test';
vue.methods.fnA()
test.funcB()

test.js

export function funcA() {
  console.log('func A');
}

// src/es6/js/utilB.js
export function funcB() {
  console.log('func B');
}

vue.js

export default {
  data() {
  },
  methods: {
    fnA() {
      console.log(11)
    },
    fnB() {
      console.log(222)
    },
  },
}

package.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.44.0",
    "webpack-cli": "^4.7.2"
  }
}

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

編譯後的main.js檔案

(()=>{"use strict";var e={};(e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),
Object.defineProperty(e,"__esModule",{value:!0})})(e),{data(){},methods:{fnA(){console.log(11)},fnB(){console.log(222)}}}.methods.fnA(),e.default.funcB()})();

可以看出test.js檔案的funcB函式進行了清除