webpack 的 scope hoisting 是什麼?

原文鏈接:https://ssshooter.com/2019-02...

scope hoisting 是 webpack3 的新功能,直譯過來就是「作用域提升」。熟悉 JavaScript 都應該知道「函數提升」和「變量提升」,JavaScript 會把函數和變量聲明提升到當前作用域的頂部。「作用域提升」也類似於此,webpack 會把引入的 js 文件“提升到”它的引入者頂部。

接下來嘗試在 webpack4 使用這個功能,對比啓用前後的打包區別,相信你一定能很快理解他的作用。

啓用插件

在 webpack4 中使用 scope hoisting,需要添加 ModuleConcatenationPlugin(模塊關聯)插件:

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

module.exports = mode => {
  if (mode === 'production') {
    return {}
  }

  return {
    devtool: 'source-map',
    plugins: [new webpack.optimize.ModuleConcatenationPlugin()],
  }
}

文件準備

現在已經在開發環境添加上 scope hoisting。但是因爲我們希望測試文件引入效果的不同,所以需要添加 4 個文件。

圖片描述

// shouldImport.js
export let sth = 'something you need'

export default {
  others: '',
}
// one.js two.js 皆爲此代碼
import other from './shouldImport'
let a = other
export default a
// index.js
import one from './one'
import two from './two'

let test = 'this is a variable'

export default {
  one,
  two,
  test,
}

文件間的引用關係是這樣的:

圖片描述

文件都準備好了,立即運行 node_modules/.bin/webpack --mode development 打包文件。

這就是 scope hoisting

這是打包文件的入口模塊部分:

{
    './src/index.js': function(
      module,
      __webpack_exports__,
      __webpack_require__
    ) {
      'use strict'
      __webpack_require__.r(__webpack_exports__)

      // 關聯 ./src/shouldImport.js 模塊
      let sth = 'something you need'
      /* es6 默認引入 */ var shouldImport = {
        others: ''
      }

      // 關聯 ./src/one.js 模塊
      let a = shouldImport
      /* es6 默認引入 */ var one = a

      // 關聯 ./src/two.js 模塊
      let two_a = shouldImport
      /* es6 默認引入 */ var two = two_a

      // 關聯 ./src/index.js 模塊
      let test = 'this is a variable'
      /* es6 默認引入 */ var src = (__webpack_exports__['default'] = {
        one: one,
        two: two,
        test
      })
    }
  }

正常來說 webpack 的引入都是把各個模塊分開,通過 __webpack_require__ 導入導出模塊(對原理不熟悉的話可以看這裏),但是使用 scope hoisting 後會把需要導入的文件直接移入導入者頂部,這就是所謂的 hoisting。

可以看出,這麼優化後:

  • 代碼量明顯減少
  • 減少多個函數後內存佔用減少
  • 不用多次使用 __webpack_require__ 調用模塊,運行速度也會得到提升

當然幾時你開啓了 scope hoisting,webpack 也不會一股腦地把所有東西都堆砌到一個模塊。官網對這個問題也清楚地說明了,這裏舉個例子,在你使用非 ES6 模塊或使用異步 import() 時,不會應用作用域提升,模塊依然會拆分開,不過具體代碼會跟正常的引入有一點差異。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章