原文鏈接: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() 時,不會應用作用域提升,模塊依然會拆分開,不過具體代碼會跟正常的引入有一點差異。