Webpack 构建优化总结

ⅰ亾dé卋堺 提交于 2021-02-07 09:33:25

初级分析:使用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

原文链接: https://juejin.cn/post/6844904136622751758

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!