了不得的 Webpack Scope Hoisting 學習指南

近期原創文章回顧😄html

1、什麼是 Scope Hoisting

Scope Hoisting 是 webpack3 的新功能,直譯爲 "做用域提高",它可讓 webpack 打包出來的代碼文件更小運行更快前端

在 JavaScript 中,還有「變量提高」和「函數提高」,JavaScript 會將變量和函數的聲明提高到當前做用域頂部,而「做用域提高」也相似,webpack 將引入到 JS 文件「提高到」它的引入者的頂部。webpack

首先回顧下在沒有 Scope Hoisting 時用 webpack 打包下面兩個文件:git

// main.js
export default "hello leo~";

// index.js
import str from "./main.js";
console.log(str);
複製代碼

使用 webpack 打包後輸出文件內容以下:es6

[
  (function (module, __webpack_exports__, __webpack_require__{
    var __WEBPACK_IMPORTED_MODULE_0__main_js__ = __webpack_require__(1);
    console.log(__WEBPACK_IMPORTED_MODULE_0__main_js__["a"]);
  }),
  (function (module, __webpack_exports__, __webpack_require__{
    __webpack_exports__["a"] = ('hello leo~');
  })
]
複製代碼

再開啓 Scope Hoisting 後,相同源碼打包輸出結果變爲:github

[
  (function (module, __webpack_exports__, __webpack_require__{
    var main = ('hello leo~');
    console.log(main);
  })
]
複製代碼

對比兩種打包方式輸出的代碼,咱們能夠看出,啓用 Scope Hoisting 後,函數聲明變成一個, main.js 中定義的內容被直接注入到 main.js 對應模塊中,這樣作的好處:web

  • 代碼體積更小,由於函數申明語句會產生大量代碼,致使包體積增大(模塊越多越明顯);
  • 代碼在運行時由於建立的函數做用域更少, 內存開銷也隨之變小

2、webpack 模塊機制

咱們使用下面 webpack.config.js 配置,打包來看看 webpack 模塊機制:npm

// webpack.config.js
const path = require('path');

module.exports = {
    entry'./src/index.js',
    output: {
        filename'bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    mode'none',
    optimization: {
        usedExportstrue,
    },
};
複製代碼

打包後輸出結果(精簡後): 經過分析,咱們能夠得出如下結論:json

  • webpack 打包輸出打是一個 IIFE(匿名閉包);
  • modules  是一個數組,每一項是一個模塊初始化函數;
  • 使用 __webpack_require() 來家在模塊,返回 module.exports ;
  • 經過 __webpack_require__(__webpack_require__.s = 0); 啓動程序。

3、Scope Hoisting 原理

Scope Hoisting 的實現原理其實很簡單:分析出模塊之間的依賴關係,儘量將打散的模塊合併到一個函數中,前提是不能形成代碼冗餘。 所以只有那些被引用了一次的模塊才能被合併segmentfault

因爲 Scope Hoisting 須要分析出模塊之間的依賴關係,所以源碼必須採用 ES6 模塊化語句,否則它將沒法生效。 緣由和4-10 使用 TreeShaking 中介紹的相似。

4、Scope Hoisting 使用方式

1. 自動啓用

在 webpack 的 mode 設置爲 production 時,會默認自動啓用 Scope Hooting。

// webpack.config.js

// ...
module.exports = {
    // ...
 mode: "production"
};
複製代碼

2. 手動啓用

在 webpack 中已經內置 Scope Hoisting ,因此用起來很簡單,只須要配置ModuleConcatenationPlugin 插件便可:

// webpack.config.js

// ...
const webpack = require('webpack');
module.exports = {
    // ...
    plugins: [
        new webpack.optimize.ModuleConcatenationPlugin()
    ]
};
複製代碼

考慮到 Scope Hoisting 以來 ES6 模塊化語法,而如今不少 npm 包的第三方庫仍是使用 CommonJS 語法,爲了充分發揮 Scope Hoisting 效果,咱們能夠增長如下 mainFields 配置:

// webpack.config.js

// ...
const webpack = require('webpack');
module.exports = {
    // ...
    resolve: {
        // 針對 npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
        mainFields: ['jsnext:main''browser''main']
    },
    plugins: [
        new webpack.optimize.ModuleConcatenationPlugin()
    ]
};
複製代碼

針對非 ES6 模塊化語法的代碼,webpack 會降級處理不使用 Scope Hoisting 優化,咱們能夠在 webpack 命令上增長 --display-optimization-bailout 參數,在輸出的日誌查看哪些代碼作了降級處理:

// package.json
{
  // ...
  "scripts": {
    "build""webpack --display-optimization-bailout" 
  }
}
複製代碼

咱們寫個簡單示例代碼:

// index.js
import str from "./main.js";
const { name } = require('./no-es6.js');

// main.js
export default "hello leo~";

// no-es6.js
module.exports = {
    name : "leo"
}
複製代碼

接着打包測試,能夠看到控制檯輸出下面日誌:

輸出的日誌中 ModuleConcatenation bailout 告訴咱們哪些文件由於什麼緣由致使降級處理了。

5、總結

本文主要和你們一塊兒回顧了 Scope Hoisting 基本概念,使用方式和使用後效果對比,但願你們不要只停留在會用 webpack,也要看看其中一些不常見的知識,好比本文介紹的 Scope Hoisting,它對咱們項目優化很是有幫助,但日常又不多會去注意。

6、參考文章

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787/Leo_Reading/issues
ES小冊 js.pingan8787.com
語雀知識庫 Cute-FrontEnd
相關文章
相關標籤/搜索