webpack 性能优化

  • 开发环境性能优化
  • 生产环境性能优化

开发环境性能优化

  • 优化打包构建速度

    • HMR
  • 优化代码调试

    • source-map

生产环境性能优化

  • 优化打包构建速度

    • oneOf
    • babel 缓存
    • 多过程打包
    • externals
    • dll
  • 优化代码运行的性能

    • 缓存(hash,chunkhash,contenthash)
    • tree shaking
    • code split
    • 懒加载和预加载
    • pwa

优化 开发环境 打包构建速度

HMR hot module replacement 热模块替换/模块热替换

作用:一个模块发生变化,只会从新打包这一个模块 而不是从新打包所有,极大晋升构建速度

  • 款式文件: 能够应用HMR性能,因为style-loader外部实现了
  • js文件: 默认不能应用HMR性能 -->解决:须要批改js代码,增加反对HMR性能的代码。留神,HMR性能对js的解决,只能解决非入口js文件的其余文件。
if(module.hot){    //一旦module.hot是true,阐明开启HMR性能,让HMR性能代码失效    module.hot.accept('./xxx.js',function(){        //此办法会监听print.js文件的变动,一旦发生变化,其余默认不会从新打包构建        //会执行前面的回调函数        xxx();    })}
  • html文件: 默认不能应用HMR性能,同时会导致问题:html文件不能热更新了

    解决:改 entry:['入口js','html'],但html文件只有一个,所以不必做HMR性能

    devServer:{        //我的项目构建后的目录        contentBase: resolve(__dirname,'build'),        //启用gzip压缩        compress:true,        //端口号        port:3000,        //主动关上浏览器        open:true    }

优化 开发环境 代码调试

source-map 一种提供源代码到构建后代码映射的技术

如果构建后代码出错了,通过映射能够追踪到谬误的代码

webpack.config.jsdevtools:'source-map'//其余 参数 [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-mapsource-map : 内部    错误代码的精确信息和谬误地位inline-source-map : 内联    错误代码的精确信息和谬误地位hidden-source-map : 内部    错误代码的谬误起因 但没有谬误地位,不能追踪到源代码的谬误,只能提醒到构建后代码的地位eval-source-map : 内联    每一个文件都生成对应的source-map,都在eval    错误代码的精确信息和谬误地位nosources-source-map : 内部    能找到错误代码的精确信息 但没有任何源代码信息cheap-source-map : 内部    错误代码的精确信息和谬误地位 只准确到行,不准确到列cheap-module-source-map : 内部    错误代码的精确信息和谬误地位    module 会将 loader 的 source-map退出内联 和 内部的区别 :    1.内部生成了文件但内联没有生成    2.内联构建速度更快
  • 开发环境:速度快,调试更敌对

    速度快 eval>inline>cheap>...调试更敌对 souce-map>cheap-module-souce-map>cheap-souce-map所以 个别用eval-source-map
  • 生产环境:源代码要不要暗藏,调试要不要敌对?内联会让体积编码,所以个别不必内联

    nosources-source-map 暗藏源代码hidden-source-map 只暗藏源代码,会提醒构建购代码错误信息--> source-map /cheap-module-souce-map

优化生产环境

oneOf

rules里中有许多个loader,这样会导致每个文件都会被所有的loader过一遍,有些能解决,有些解决不了。所以能够利用oneOf达到以下loader只会匹配到第一个。但须要留神,不能有两个loader同时解决同一个文件

webpack.configmodule.exports={    //....    module:{        rule:[            //失常来讲,一个文件只能被一个loader解决            //当一个文件要被多个loader解决,那么肯定要指定loader的执行程序            // 先执行eslint 再执行babel            {                test:/\.js$/,                exclude:/node_modules/,                //优先执行                enforce:'pre',                loader:'eslint-loader',                options:{                    fix:true                }            },            {              oneOf:[                    {                        test: /\.css$/,                        use:[                            ...commonCssLoader                        ]                    },                    {                        test:/\.less$/,                        use:[                            ...commonCssLoader,'less-loader'                        ]                    },                    {                        test:/\.js$/,                        exclude:/node_modules/,                        loader:'babel-loader',                        options:{                            // 预设 :批示babel做怎么的兼容性解决                            presets:[                            [                                    '@babel/preset-env',                                    {                                        //按需加载                                        useBuiltIns:'usage',                                        //指定core-js版本                                        corejs:{                                            version:3                                        },                                        //指定兼容性做到哪个版本的浏览器                                        targerts:{                                            chrome: '40',                                            fixfox: '50',                                            ie: '9',                                            safari: '10',                                            edge: '17'                                        }                                    }                            ]                            ]                        }                    },                    {                        test:/\.(png|jpg|gif)/,                        loader:'url-loader',                        enModule:true,                        options:{                            limit:8*1024,                            name: '[hash:10].[ext]',                            outputpath:''                        }                    },                    {                        test:/\.html$/,                        loader:'html-loader'                    },                    {                        exclude:/\.(js|less|css|png|jpg|gif)/,                        loader:'file-loader',                        options:{                            name:'[hash:10].[ext]'                        }                    }                ]            }        ]    },}

缓存

1.babel缓存-->第二次打包更快

{    test:/\.js$/,    exclude:/node_modules/,    loader:'babel-loader',    options:{        // 预设 :批示babel做怎么的兼容性解决        presets:[        [            '@babel/preset-env',            {                //按需加载                useBuiltIns:'usage',                //指定core-js版本                corejs:{                    version:3                },                //指定兼容性做到哪个版本的浏览器                targerts:{                    chrome: '40',                    fixfox: '50',                    ie: '9',                    safari: '10',                    edge: '17'                }            }        ]        ],        //第二次构建时,会读取之前的缓存        cacheDirectory: true        }    },

2.文件资源缓存-->上线缓存优化

    hash:每次webpack构建会生成一个惟一hash值        问题: 因为js和css同时应用一个hash值,如果从新打包,会导致所有缓存生效,可能我却只改了一个文件,    chunkhash:依据chunk生成hash值,如果打包来源于同一个chunk,那么hash值也一样        问题:js和css的hash值还是一样的。            起因:css是由js引入的,所以属于同一个chunk    contenthash: 依据文件内容生成hash值,
webpack.config.js

tree shaking

去除应用程序中没有应用的代码

前提:1.必须应用es6模块化2.开启production模式在package.json中配置"sideEffects":false 所有代码都没有副作用,都能够镜像tree sharking     问题 可能会把css/@babel/polyfille 干掉"sideEffects": ["*.css","*.less"] 哪些文件不 tree sharking

code split

1.入口配置

    单入口 //单页面利用    entry:'./src/js/index.js'     多入口 //多页面利用    entry:{        index:'./src/js/index.js',        test:'./src/js/test.js'    }

2.optimization

module.exports={    //...    // 能够将nodemudules中的代码独自打包成一个chunk最终输入    // 还能够主动剖析多入口chunk中,有没有公共的文件,如果有会打包成一个独自的chunk    optimization:{        splitChunks:{            chunks:'all'        }    }}    

3.import 动静导入语法,能将某个文件独自打包

通过js代码,让某个文件被独自打包成一个chunk,通过正文能够固定此文件的名称

import(/*webpackChunkName: 'xxxName' */'./xx/xxx.js')    .then(res =>{        //加载胜利    })    .catch(()=>{        //加载失败    })

懒加载和预加载

1.懒加载 当文件须要用时才加载

import 动静导入语法

document.getElementById('btn').onclick = function(){    import(/*webpackChunkName: 'xxxName' */'./xx/ss.js')    .then(res=>{        //干啥干啥    })}

2.预加载 webpackPrefetch:true

./xx/ss.js 曾经被加载了,点击的时候再从缓存中加载,

document.getElementById('btn').onclick = function(){    import(/*webpackChunkName: 'xxxName',webpackPrefetch:true */'./xx/ss.js')    .then(res=>{        //干啥干啥    })}
  • 失常加载能够认为是并行加载(同一时间加载多个文件)
  • 预加载prefectch 等其余资源加载结束,浏览器闲暇了,再偷偷加载资源 兼容性比拟差 慎用

PWA 渐进式网络开发应用程序

网络离线可拜访

webbox-->webbox-webpack-plugin

const WebboxWebpackPlugin = require('webbox-webpack-plugin')module.exports={    plugins:[        new WebboxWebpackPlugin.GenerateSW({            /*                1.帮忙 serviceWorker 疾速启动                2.删除旧的 serviceWorker                 生成一个 serviceWorker 配置文件             */            clientsClaim:true,            skipWaiting:true        })    ]}index.js 中注册serviceworker//解决兼容性if('serviceWorker' in navigator){    window.addEventListener('load',()=>{        navigator.serviceWorker            .register('./service-work.js')            .then(()=>{                //胜利            })            .catch(()=>{                //失败            })    })}1.可能会呈现问题 eslint不意识window和navigator解决 package.json中eslintConfig中配置"env":{    "browser":true //反对浏览器端的变量}2. sw代码必须运行在服务器上    -->node.js         --> npm i serve -g             serve -s build 启动一个服务器将build下的资源作为动态资源裸露进来

多过程打包

thread-loader 个别给babel-loader用

但须要留神
过程启动大概需500ms,过程间通信也有开销。只有工作耗费工夫比拟长,才须要多过程打包

{    test:/\.js$/,    exclude:/node_modules/,    use:[        //'thread-loader',        {            loader:'thread-loader',            options:{                workers: 2 //过程2个            }        }        {            loader:'babel-loader',            options:{                // 预设 :批示babel做怎么的兼容性解决                presets:[                [                    '@babel/preset-env',                    {                        //按需加载                        useBuiltIns:'usage',                        //指定core-js版本                        corejs:{                            version:3                        },                        //指定兼容性做到哪个版本的浏览器                        targerts:{                            chrome: '40',                            fixfox: '50',                            ie: '9',                            safari: '10',                            edge: '17'                        }                    }                ]                ],                //第二次构建时,会读取之前的缓存                cacheDirectory: true                }        }    ]    },

externals

module.exports={    externals:{        //疏忽/回绝  库名 -- npm 包名         //能够在index.html中引入cdn    }}

dll 动静连贯

应用dll技术 对某些库(第三方库) 进行独自打包

    指令 webpack --config webpack.dll.jswebpack.dll.jsconst {resolve} = require('path')const webpack = require('webpack')module.exports = {    entry:{        //最终打包生成的[name]-->jquery        //['jquery']-->要打包的库是jquery        jquery:['jquery']    },    ouput:{        filename:'[name].js',        path:resolve(__dirname,'dll'),        library:'[name]_[hash]' //打包的库里面向外裸露进来的内容叫什么名字    },    plugin:[        new webpacl.DllPlugin({            //打包生成一个manifest.json --> 提供和jquery映射            name: '[name]_[hash]',//映射库的裸露内容名称            path:resolve(__dirname,'dll/manifest.json')        })    ],    mode:'production'}webpack.config.jsconst AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')module.exports={    plugins:[        //通知webpack哪些库不参加打包,同时名称也得变        new webpack.DllReferencePlugin({            manifest: resolve(__dirname,'dll/manifest.json')        }),        //将某个文件打包输入进来,并在html中引入该资源        new AddAssetHtmlWebpackPlugin({            filepath:resolve(__dirname,'dll/jquery.js')        })    ]}