Webpack4優化之路

張淼發表於2018-04-04

簡介

Webpack4 那點兒東西 基於webpack4總結了一些webpack的常見配置,但是webpack 各種強大的配置有時候讓你不堪重負,會打包很多的檔案,遍歷解析很多檔案。。。。。總之,這些操作會讓webpack打包過程變得很慢,所以開發過程中我們不得不去優化一些配置,讓webpack更好的服務於我們的開發。

動態連結庫DLL

即把基礎模組的程式碼打包進入動態連結庫裡,比如常用的react,vue等,當需要匯入的模組在動態連線庫裡的時候,模組不能再次被打包,而是去動態連線庫裡獲取

  1. 建立一個webpack.dll.config.js檔案打包常用類庫到dll中
module.exports = {
    entry: {
        react: ['vue'] //vue模組打包到一個動態連線庫
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].dll.js', //輸出動態連線庫的檔名稱
        library: '_dll_[name]' //全域性變數名稱
    },
    plugins: [
        new webpack.DllPlugin({
            name: '_dll_[name]', //和output.library中一致,也就是輸出的manifest.json中的 name值
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ]
}
webpack --config webpack.dll.config.js --mode production
複製程式碼
  1. 在住配置檔案 webpack.config.js中加入以下程式碼
plugins: [
 new webpack.DllReferencePlugin({
       manifest: require(path.join(__dirname, 'dist', 'vue.manifest.json')),
   })
]
webpack --config webpack.config.js --mode development
複製程式碼

這樣會從dll中獲取vue,而且不用再次打包vue了。

Webpack熱替換之HMR

Hot Module Replacement(以下簡稱 HMR)是 webpack 中超級有用的特性之一 ,當你對程式碼進行修改並儲存後,webpack 將對程式碼重新打包,並將新的模組傳送到瀏覽器端,瀏覽器通過新的模組替換老的模組,這樣在不重新整理瀏覽器的前提下就能夠對應用進行更新。從而減少很多時間。の。。。。比如,頁面中有一個modal框,需要點選button觸發modal顯示,在開發過程中,如果修改了modal 的樣式,觸發瀏覽器重新整理,你還需要再次點選button才能看到修改後的modal樣式,但是熱替換是不需要重新整理瀏覽器的,可以直接觀察到修改後的變化。 上文中已經介紹了watch的用法,但是watch是針對打包時檔案發生變化進行重新打包,而HMR是針對webpack-dev-server的。

  1. devserver配置如下
devServer: {//配置此靜態檔案伺服器,可以用來預覽打包後專案
    inline:true,//打包後加入一個websocket客戶端
    hot:true,//熱載入
    contentBase: path.resolve(__dirname, 'dist'),//開發服務執行時的檔案根目錄
    host: 'localhost',//主機地址
    port: 9090,//埠號
    compress: true//開發伺服器是否啟動gzip等壓縮
}
複製程式碼
  1. plugins配置項加入以下兩行
 new webpack.HotModuleReplacementPlugin(),
 new webpack.NamedModulesPlugin()//使用者名稱替代id
複製程式碼

3.業務程式碼中的修改

if(module.hot) {
    module.hot.accept('./hello.js', function() {
        div.innerHTML = hello()
    })
}
複製程式碼
  1. 原理及流程解析大致流程: webpack-dev-server可以和瀏覽器之間建立一個web socket進行通訊,一旦新檔案被打包出來,webpack-dev-server就告訴瀏覽器這個訊息,這時瀏覽器就可以自動重新整理頁面或者進行熱替換操作。當一個模組b發生改變,而模組內又沒有HMR程式碼(類似於上述3中的程式碼)來處理這一訊息時,那這一訊息就會被傳遞到依賴模組b的其他模組上;如果訊息在新模組上沒有被捕獲的話就會再次進行傳遞;如果所有的訊息都被捕獲了的話,那我們的應用就應該已經按照程式碼進行了更新;反之如果有訊息冒泡到了入口(entry)檔案還沒有被捕獲的話,那就說明我們的程式碼中沒有處理這類變更方法,那webpack就會重新整理瀏覽器頁面,即從HMR回退到LiveReload。

Tree Shaking

tree shaking 是一個術語,通常用於描述移除 JavaScript 上下文中的未引用程式碼。這個術語和概念實際上是興起於 ES2015 模組打包工具 rollup。你可以將應用程式想象成一棵樹。綠色表示實際用到的原始碼和 library,是樹上活的樹葉。灰色表示無用的程式碼,是秋天樹上枯萎的樹葉。為了除去死去的樹葉,你必須搖動這棵樹,使它們落下。但是webpakc的Tree Shaking依賴靜態的ES6模組化語法即通過import和export匯入匯出的程式碼,而且需要引入一個能夠刪除未引用程式碼(dead code)的壓縮工具(minifier)(例如 UglifyJSPlugin)或者在執行命令的時候用webpack --display-used-exports --optimize-minimize --mode production

比如以下程式碼

export function getName() {
    return 'hello world';
}
export function getAge() {
    return 9999;
}
複製程式碼

如果你只引用了其中一個,那麼通過Tree Shaking會剔除另一個未用到的,打包的時候直接忽略。

{
    test: /\.js/,
    use: {
        loader: 'babel-loader',
        query: {
            presets: ["env", {
+                                   modules: false //關閉 Babel 的模組轉換功能,保留原本的 ES6 模組化語法
+                               }]
        }
    }
}
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
plugins: [
    new UglifyJSPlugin()
 ]
webpack --display-used-exports --optimize-minimize
複製程式碼

提取公共程式碼

這個變化還是很大的,之前的webpack版本用的都是commonchunkplugin,但是webpack4開始使用common-chunk-and-vendor-chunk 配置如下:

optimization: {
	splitChunks: {
		cacheGroups: {
			commons: {
				chunks: "initial",
				minChunks: 2,
				maxInitialRequests: 5, // The default limit is too small to showcase the effect
				minSize: 0 // This is example is too small to create commons chunks
			},
			vendor: {
				test: /node_modules/,
				chunks: "initial",
				name: "vendor",
				priority: 10,
				enforce: true
			}
		}
	}
}
複製程式碼

Scope Hoisting

作用域提升,這是在webpack3中所提出來的。它會使程式碼體積更小,因為函式申明語句會產生大量程式碼.

const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
plugins: [
// 開啟 Scope Hoisting
new ModuleConcatenationPlugin(),
],
複製程式碼

CDN

對於靜態資源的處理,放入CDN是一個很好的選擇,webpack中配置CDN的方式如下:

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name]_[hash:8].js',
    publicPath: 'http://static.xxxx.com/'
},
複製程式碼

多程式之HappyPack

HappyPack就能讓Webpack把任務分解給多個子程式去併發的執行,子程式處理完後再把結果傳送給主程式,其中子程式的個數為cpu的個數減去1,需要在loader處修改如下

 use: 'happypack/loader?id=babel',
複製程式碼

並且在plugin中新增以下程式碼:

new HappyPack({
    id: 'babel',
    //如何處理.js檔案,和rules裡的配置相同
    loaders: [{
        loader: 'babel-loader',
        query: {
            presets: [
                "env", "stage-0"
            ]
        }
    }]
}),
複製程式碼

小結

以上為webpack配置中的一些常見優化方案,但是根據專案的不同,需要選擇的方案也不太一樣,多嘗試,根據特定的環境選擇特定的優化方案,我覺得是一件比較不錯的事情。

相關文章