Webpack 構建優化總結

語言: CN / TW / HK

初級分析:使用webpack內建的stats

stats:構建統計資訊

package.json中使用stats

"scripts": {
    "build:stats":"webpack --env production --json > stats.json"
}
複製程式碼

指定輸出的json物件,輸出一個json檔案

Node.js 中使用

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

webacpk(config, (err, stats) => {
    if(err) {
        return console.error(err);
    }
    
    if(stats.hasErrors()) {
        return console.log(stats.toString("errors-only"))
    }
    
    console.log(stats);
     
})
複製程式碼

缺點:顆粒度太粗,看不出問題所在。

速度分析:使用speed-measure-webpack-plugin

const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin')

const smp = new SpeedMesurePlugin();

const webpackConfig = smp.wrap({
    plugins: [
        new MyPlugin();
        new MyOtherplugin()
    ]
})
複製程式碼

速度分析外掛作用

  • 分析整個打包總耗時
  • 每個外掛和loader的耗時情況

體積分析:使用webpack-bundle-analyzer分析體積

const {BundleAnalyzerPlugin} =require('webpack-bundle-analyzer')

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
}
複製程式碼

構建完成後會在8888埠展開大小

可以分析哪些問題?

  • 依賴的第三方模組檔案大小
  • 業務裡面的元件程式碼大小

多程序多例項構建

使用thread-loader解析資源

原理:每次webpack解析一個模組,thread-loader會將他及它的依賴分配給worker執行緒中

use:[
{
    loader:'thread-loader',
    options: {
        workers: 3
    }
}]
複製程式碼

多程序例項並行壓縮

  • 方法一:使用parallel-uglify-plugin外掛
const ParalleUglifyPlugin = require('parallel-uglify-plugin')

module.exports = {
    plugins: [
        new ParalleUglifyPlugin({
            uglifyJs:{
                output: {
                    beautify:false,
                    comments:false,
                },
                compress:{
                    warnings: false,
                    drop_console:true,
                    collapse_vars:true,
                    reduce_vars:true
                }
            }
            
        })
    ]
}
複製程式碼
  • 方法二:uglifyjs-webpack-plugin開啟parallel引數
plugins: [
    new UglifyJsPlugin({
        uglifyOptions:{},
        parallel:true
    })
]
複製程式碼
  • 方法三(推薦):terser-webpack-plugin開啟parallel引數
module.exports = {
    optimization: {
        minimizer: [
            new TerserPlugin({
                parrallel:4
            })
        ]
    }
}
複製程式碼

進一步分包:預編譯資源模組

思路:將react, react-dom, redux, react-redux基礎包和業務基礎打包成一個檔案。

方法:建立一個單獨的配置檔案,一般命名為webpack.dll.js,使用DLLPlugin進行分包,DllReferencePlugin對manifest.json引用。

const path = require('path')
const webpack = requrie('webpack')

module.exports = {
    context: process.cwd(),
    resolve:{
        extensions:['js', 'jsx', '.json', '.less', '.css'],
        modules:[__dirname, 'node_modules']
    },
    entry: {
        library: [
        'react',
        'react-dom',
        'redux',
        'react-redux']
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, './build/library'),
        library: '[name]'
    },
    plugins: [
        new webpack.Dllplygin({
            name: '[name]',
            path: './build/library/[name].json'
        })
    ]
}
複製程式碼

在webpack.config.js引入

module.exports = {
    plugins: [
        new webpack.DllReferencePlugin({
            mainfest:require('./build/library/mainfest.json')
            
        })
    ]  
}
複製程式碼

充分利用快取提升二次構建速度

快取思路:

  • babel-loader開啟快取
  • terser-webpack-plugin開啟快取
  • 使用cache-loader或者hard-source-webpack-plugin

縮小構建目標

目的:儘可能的少構建模組

比如babel-laoder不解析node_modules

module.exports = {
    rules: {
        test: /\\.js$/,
        loader: 'babel-loader',
        exclude: 'node_modules'
    }
}
複製程式碼

減少檔案搜尋範圍

  • 優化resolve.modules配置(減少模組搜尋層級)
  • 優化resolve.mainFields配置
  • 優化resolve.extensions配置
  • 合理使用alias
module.exports = {
    resolve: {
        alias: {
            react: path.resolve(__dirname, './node_modules/react/dist/react.min.js')
        },
        modules: [path.resolve(__dirname, 'node_modules')],
        extensions: ['js'],
        mainFilelds:['main'],
    }
}
複製程式碼

使用webpack進行圖片壓縮

要求: 基於Node庫的imagemin或者tinypngAPI

使用: 配置image-webpack-loader

return {
    test: /\\.(png|svg|jpg|gif)$/,
    use: [{
        loader:'file-loader'
        options:{
            name:  `${filename}img/[name]${hash}.[ext]`
        }
    },{
        loader:'image-webpack-loader',
        options: {
            mojpeg: {
                progressive: true,
                quality: 65
            },
            optipng: {
                enabled: false,
            } ,
            pngquant: {
                quality: '65-90',
                speed: 4
            }
        }
        
    }]
}
複製程式碼

imagemin的優點點分析

  • 有很多定製選項
  • 可以引入更多第三方優化外掛,例如pngquant
  • 可以處理多種圖片格式

使用TreeShaking擦除無用的CSS

無用的CSS如何刪除掉?

  • PurifyCSS:遍歷程式碼,識別已經用到的CSS class
  • uncss:HTML需要通過jsdom載入, 所有的樣式通過PostCSS解析,通過document.querySelector來識別在html檔案裡面不存在的選擇器。

在webpack中如何使用PurifyCSS?

使用動態Polyfill服務

  • babel-polyfill(React16官方推薦)
  • polyfill-service(社群維護)

Polyfill Service原理

識別User Agent,下發不同的Polyfill

體積優化策略總結

  • Scope Hoisting
    • scope hoisting 後會把需要匯入的檔案直接移入匯入者頂部,這就是所謂的 hoisting,需要新增 ModuleConcatenationPlugin(模組關聯)外掛
  • Tree-shaking
  • 公共資源分離
  • 圖片壓縮
  • 動態Polyfill

原文連結: http://juejin.cn/post/6844904136622751758

分享到: