webpack打包優化的幾種方案

火焰小能貓發表於2020-10-11

實現webpack打包優化,有兩個優化點:

  • 如何減少打包時間
  • 如何減少打包大小

減少打包時間

1.優化Loader

對於Loader來說,首先優化的當是babel了,babel會將程式碼轉成字串並生成AST,然後繼續轉化成新的程式碼,轉換的程式碼越多,效率就越低。

首先可以優化Loader的搜尋範圍

module.exports = {
    module: {
        rules: [
            test: /\.js$/, // 對js檔案使用babel
            loader: 'babel-loader',
            include: [resolve('src')],// 只在src資料夾下查詢
            // 不去查詢的資料夾路徑,node_modules下的程式碼是編譯過得,沒必要再去處理一遍
            exclude: /node_modules/ 
        ]
    }
}

另外可以將babel編譯過檔案快取起來,以此加快打包時間,主要在於設定cacheDirectory

loader: 'babel-loader?cacheDirectory=true'

2.HappyPack

因為受限於Node的單執行緒執行,所以webpack的打包也是單執行緒的,使用HappyPack可以將Loader的同步執行轉為並行,從而執行Loader時的編譯等待時間。

module: {
    loaders: [
        test: /\.js$/,
        include: [resolve('src')],
        exclude: /node_modules/,
        loader: 'happypack/loader?id=happybabel' //id對應外掛下的配置的id
    ]
},
plugins: [
    new HappyPack({
        id: 'happybabel',
        loaders: ['babel-loader?cacheDirectory'],
        threads: 4, // 執行緒開啟數
    })
]

3.DllPlugin

該外掛可以將特定的類庫提前打包然後引入,這種方式可以極大的減少類庫的打包次數,只有當類庫有更新版本時才會重新打包,並且也實現了將公共程式碼抽離成單獨檔案的優化方案。

// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
    entry: {
        vendor: ['react'] // 需要統一打包的類庫
    },
    output: {
      path: path.join(__dirname, 'dist'),
        filename: '[name].dll.js',
        library: '[name]-[hash]'
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]-[hash]', //name必須要和output.library一致
            context: __dirname, //注意與DllReferencePlugin的context匹配一致
            path: path.join(__dirname, 'dist', '[name]-manifest.json')
        })
    ]
}

然後在package.json檔案中增加一個指令碼

'dll': 'webpack --config webpack.dll.js --mode=development'
//執行後會打包出react.dll.js和manifest.json兩個依賴檔案

最後使用DllReferencePlugin將剛生成的依賴檔案引入專案中

// webpack.conf.js
module.exports = {
    //...其他配置
    plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./dist/vendor-manifest.json') //此即打包出來的json檔案
        })
    ]
}

更多有關webpack配置DllPlugin請參考如何使用 Webpack 的 Dllpluginwebpack中DllPlugin用法

4.程式碼壓縮相關

  • 啟用gzip壓縮

  • webpack3中,可以使用UglifyJS壓縮程式碼,但是它是單執行緒的,因此可以使用webpack-parallel-uglify-plugin來執行UglifyJS,但在webpack4中只要啟動了modeproduction就預設開啟了該配置

  • 壓縮html和css程式碼,通過配置刪除console.logdebugger等,防止可能造成的記憶體洩漏

 

new UglifyJsPlugin({
    UglifyOptions: {
        compress: {
            warnings: false,
            drop_console: true,
            pure_funcs: ['console.log']
        }
    },
    sourceMap: config.build.productionSourceMap,
    parallel: true
})
//或使用以下配置
new webpack.optimize.UglifyJsPlugin({
    compress: {
        warnings: false,
        drop_debugger: true,
        drop_console: true
    }
})

減少打包大小

1.按需載入,首頁載入檔案越小越好,將每個頁面單獨打包為一個檔案,(同樣對於loadsh類庫也可以使用按需載入),原理即是使用的時候再去下載對應的檔案,返回一個promise,當promise成功後再去執行回撥。

2.Scope Hoisting

它會分析出模組之前的關係,儘可能的把打包出來的模組合併到一個函式中去

// 如在index.js問價中引用了test.js檔案
export const a = 1  // test.js
import {a} from './test.js'  // index.js
// 以上打包出來的檔案會有兩個函式,類似如下
[
    function(module, exports, require) {} // **0**
    function(module, exports, require) {} // **1**
]

如果使用scope hoisting的話會盡量打包成一個函式,在webpack 4中只需開啟concatenateModules即可

module.exports = {
    optimize: {
        concatenateModules: true
    }
}

3.Tree shaking

它會刪除專案中未被引用的程式碼,而如果在webpack 4中只要開啟生產環境就會自動啟動這個功能

相關文章