【Webpack】654- 了不起的 Webpack Scope Hoisting 學習指南

2021-03-02 前端自習課
一、什麼是 Scope Hoisting

Scope Hoisting 是 webpack3 的新功能,直譯為 "「作用域提升」",它可以讓 webpack 打包出來的「代碼文件更小」「運行更快」

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

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

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

// index.js
import str from "./main.js";

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

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

再開啟 Scope Hoisting 後,相同源碼打包輸出結果變為:

[
  (function (module, __webpack_exports__, __webpack_require__) {
    var util = ('hello leo~');
    console.log(util);
  })
]

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

「代碼體積更小」,因為函數申明語句會產生大量代碼,導致包體積增大(模塊越多越明顯);代碼在運行時因為創建的函數作用域更少,「內存開銷也隨之變小」。二、webpack 模塊機制

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

// 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: {
        usedExports: true,
    },
};

打包後輸出結果(精簡後):通過分析,我們可以得出以下結論:

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

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

由於 Scope Hoisting 需要分析出模塊之間的依賴關係,因此源碼「必須採用 ES6 模塊化語句」,不然它將無法生效。原因和4-10 使用 TreeShaking 中介紹的類似。

四、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 告訴我們哪些文件因為什麼原因導致降級處理了。

五、總結

本文主要和大家一起回顧了 Scope Hoisting 基本概念,使用方式和使用後效果對比,希望大家不要只停留在會用 webpack,也要看看其中一些不常見的知識,比如本文介紹的 Scope Hoisting,它對我們項目優化非常有幫助,但平常又很少會去注意。

六、參考文章《通過Scope Hoisting優化Webpack輸出》《webpack 的 scope hoisting 是什麼?》

回復「加群」與大佬們一起交流學習~

點擊「閱讀原文」查看70+篇原創文章

相關焦點

  • webpack構建中tree shaking、scope Hoisting(面試題)
    >import binding 是immutablede`tree shaking副作用`雖然生產模式下默認開啟,但是由於經過 babel 編譯全部模塊被封裝成 IIFE(立即執行函數)IIFE 存在副作用無法被 tree-shaking 掉需要配置 { module: false }和 sideEffects: falserollup 和 webpack
  • Webpack的使用指南-Webpack的常用解決方案
    1.自動構建HTML,可壓縮空格,可給引用的js加版本號或隨機數:html-webpack-plugin解決方案:使用插件 html-webpack-pluginwebpack.config.js如下:module.exports = {entry: '.
  • 【webpack】webpack 中最易混淆的 5 個知識點
    前兩天為了優化公司的代碼打包項目,惡補了很多 webpack4 的知識。要是放在幾年前讓我學習 webpack 我肯定是拒絕的,之前看過 webpack 的舊文檔,比我們內部項目的文檔還要簡陋。但是最近看了一下 webpack4 的文檔,發現 webpack官網的 指南[1] 寫的還不錯,跟著這份指南學會 webpack4 基礎配置完全不是問題,想系統學習 webpack 的朋友可以看一下。
  • webpack基本配置有哪些?如何搭建webpack?
    主要內容webpack學習目標第一節 webpack介紹1.webpack介紹webpack 是一個模塊打包器。webpack 的主要目標是將 JavaScript 文件打包在一起,打包後的文件用於在瀏覽器中使用,但它也能夠勝任轉換(transform)、打包(bundle)。
  • webpack教程:如何從頭開始設置 webpack 5
    webpack 對我來說曾經是一個怪物般存在一樣,因為它有太多太多的配置項,相反,使用像create-react-app腳手架可以很輕鬆創建項目,所以有一段時間內,我會儘量避免使用 webpack,因為它看起來既複雜又望而卻步 😊如果你們不習慣從頭開始設置 webpack
  • Webpack打包全世界
    什麼鬼東西,webpack就是把你寫好的只有你自己認識的程序,整理翻譯打包成漂亮的,大家都能看的程序。webpack中有四個核心的概念。 entry、output、loader、plugins。到webpack4.0之後,不用自己添加配置文件也可以直接運行了,這個點讚。入口(entry)webpack中提供了多種定義入口屬性的方式。提供單個入口語法和對象語法。不過呢,常用的配置方法是對象方法,用來包含你引入的第三方庫。比如我常用的vue開發框架,帶入到webpack配置文件裡面就需要如下配置。
  • Webpack命令字典大全
    因為最近一直在用基於VUE腳手架開發項目,慢慢的對於wepback命令也越來越面熟,所以想著整一個常用的命令分享給正在學習腳手架開發或已經在路上的同志們共同學習,進步。全局進行安裝webpack(熟手不建議)$ npm install webpack -g查看wepback版本信息 相當有用$ npm info webpack卸載wepback
  • webpack簡單介紹
    webpack是什麼nodeJS開發的網頁打包工具 ——nodeJS的一個模塊webpack的基本使用1) 使用命令行工具初始化項目(npm init -y),得到一個package.json文件(項目配置文件)【
  • 重學webpack4之基礎篇
    webpack-dev-server,開啟本地伺服器,監聽文件變化後,熱更新頁面不刷新瀏覽器而是熱更新,不輸出文件,而是放在內存中配合 new.webpack.HotModuleReplacementPlugin() 或 react-hot-loader 插件使用// package.jsonwebpack-dev-server
  • 前端必備技能 webpack - 4. webpack處理CSS資源
    配置文件,對創建項目過程有疑問的同學,可以查看 前端必備技能 webpack - 2. webpack環境安裝 的第四部分。就算是我們自己寫的樣式,有時候也會因為頁面更新等原因導致忘記刪除無用的部分,現在我們可以借用 webpack 將無用部分直接去除:npm i purifycss-webpack purify-css -D  因為涉及到 css 的引用,所以我們還需要對 html 資源進行處理:
  • Webpack vs Rollup
    開始使用安裝目前webpack最新版本是3.0.0npm i webpack -g npm i webpack@version -g配置在項目添加webpack.config.jsconst path = require('path');const webpack = require('webpack
  • Webpack 3 從入門到放棄
    其次,這應該會是一篇極長的文章,涵蓋了基本的使用方法,有更高級功能的需求可以參考官方文檔繼續學習。再次,即使是基本的功能,也內容繁多,我儘可能地解釋通俗易懂,將我學習過程中的疑惑和坑一一解釋,如有紕漏,敬請雅正。再次,為了清晰有效地講解,我會演示從零編寫 demo,只要一步步跟著做,就會清晰許多。最後,官方文檔也是個坑爹貨!Webpack,何許人也?
  • 圖解Webpack——實現Plugin
    關注公眾號「執鳶者」,回復「書籍」獲取大量前端學習資料,回復「前端視頻」獲取大量前端教學視頻。面試工作加分項!
  • 如何編寫一個 Webpack Plugin
    webpack 內部執行流程一次完整的 webpack 打包大致是這樣的過程:將命令行參數與 webpack 配置文件 合併、解析得到參數對象。參數對象傳給 webpack 執行得到 Compiler 對象。執行 Compiler 的 run 方法開始編譯。每次執行 run 編譯都會生成一個 Compilation 對象。
  • 擼一個webpack插件!!
    webpack流程通過上面的閱讀,我們知道了如何在webapck事件流上掛載鉤子。假設現在要自定義一個插件更改最後補充資源的內容,我們應該把事件添加到其中的鉤子上呢?哪一個步驟能拿到webpack編譯的資源從而去修改?所以接下來的任務是:了解webpack的流程。貼一張淘寶團隊合作分享的經典webpack流程圖,再慢慢分析〜
  • webpack4.x 系列-entry(入口)
    之前寫過webpack4系列文章,本次對webpack4進行更再次研究學習webpack官網webpck中文網中文網更新慢
  • webpack系列---loader
    webpack本身只能打包Javascript文件,對於其他資源例如 css,圖片,或者其他的語法集比如jsx,是沒有辦法加載的。 這就需要對應的loader將資源轉化,加載進來。所謂 loader 只是一個導出為函數的 JavaScript 模塊。
  • 從Webpack打包後的文件分析導入的原理
    /src/a.js":    function (module, __webpack_exports__, __webpack_require__) {    "use strict";    __webpack_require__.r(__webpack_exports__);    const asyncText = "async";    __webpack_exports
  • 看完 Webpack 源碼,我學到了這些
    一種是最常見的 git clone,將 Github 上 webpack 項目 clone 到本地,pull 後與 webpack 官方最新代碼保持一致,一勞永逸。不過作者嘗試第一種方法時,總是 clone 不下來,很大可能是由於 webpack 源文件過大且 github 伺服器 clone 一直很慢。於是退而求其次,使用第二種方法:下載 Webpack 源碼 release 版本。
  • webpack4 處理頁面
    圖文編輯:開三金前言:1.plugins 是webpack4的插件集合,可以用一些插件擴展webpack4 的功能,就比如HtmlWebpackPlugin2.HtmlWebpackPlugin的主要作用是:為html文件中引入的外部資源如script