webpack性能优化
- 开发环境性能优化
- 生产环境性能优化
开发环境性能优化
- 优化打包构建速度
// 在webpack.config.js中配置 hot : true devServer : { contentBase : path.resolve(__dirname,"build"), compress : true, port : 3000, open : true, //开启HMR热模块替换 hot : true, } /** * HMR : hot moudle replacement 热模块替换/模块热替换 * 作用:一个模块发生改变,只会重新打包当前一个模块,不会影响其他模块,极大提高打包速度 * * *样式文件:可以使用HMR功能,因为style-loader内部已经做了功能实现 * * *js文件 : 默认情况下js文件是不能使用HMR功能的 * 注意:HMR功能对js的处理只能处理非入口js的其他文件。(依赖都在入口文件引入) * 在入口文件做一下逻辑 ```js if(module.hot){ //当module.hot为true 说明开启了HMR功能, module.hot.accept('xxxxx.js',function(){ // module.hot.accept 监听xxxxx.js 文件的变化,不会影响其他文件的打包构建。 执行方法 }) } ```js * * *html文件:默认情况下htm;文件是不能使用HMR功能的,同时会导致html不能热更新,(不建议做HMR) * 解决方案: 修改entry入口 将html文件引入 */
- 优化代码调试
//在webpack.config.js中 devtool : 'source-map', /* source-map 提供源代码到构建后代码 映射 通俗解释:如果构建后代码报错,通过映射可以追踪到源代码报错地方。 */ /* devtool后面参数汇总: source-map : 外部 错误代码准确信息 和 源代码的准确位置 inline-source-map : 内联 只会生成一个内联 source-map 错误代码准确信息 和 源代码的准确位置 hidden-source-map : 外部 错误代码的原因 但是 不会追踪到源代码的错误的位置 eval-source-map : 内联 每一个文件都生成对应的source-map 都在eval 错误代码准确信息 和 源代码的准确位置 文件会多了一个hash值 nosoureces-source-map : 外部 错误代码准确信息 但是 没有源代码信息 cheap-source-map : 外部 错误代码准确信息 和 源代码的准确位置 但是 整行都会报错,不会具体的那一段代码 cheap-module-source-map : 外部 错误代码准确信息 和 源代码的准确位置 内联 和 外部的区别 : a: 外部生成了文件,内联没有生成文件 b: 内联构建速度更快 怎么使用source-map: 开发环境: 速度快,调试更加方便友好, 速度: eval > inline > cheao > ... 可以组合应用: eval-cheap-source-map eval-source-map 调试: source-map cheap-module-source-map cheap-source-map 比较好-----> eval-source-map / eval-cheap-module-source-map 生产环境: 源代码要不要隐藏?调试要不要友好 内联会让代码体积变大,所有在生产环境尽量不要使用内联 nosoureces-source-map 全部隐藏 hidden-source-map 只隐藏源代码,会提示构建后代码错误信息 比较好-----> source-map / cheap-module-source-map */
生产环境性能优化
-
优化打包构建速度
-
优化代码运行性能
-
oneOf优化
moudle : { rules : [ { //以下loader只会匹配以下 //执行逻辑:匹配成功之后就不会再往下匹配 //注意不能有两个配置处理同一种类型文件 //如果有两个配置处理一个文件(例如:js eslint babel ) 可以把优先执行的配置单独拎出来,{ } 放在rules里面。 onnOf : [ {...配置} ] } ] }
-
缓存
//对bable缓存 { test: /.js$/, exclude: /node_modules/, loader: 'babel-loader', //开启缓存 cacheDirectory : true } //文件资源缓存: /* filename : 'css/built.[hash:10].css' hash : 每次webpack构建时会生成一个唯一的hash值 问题:因为js和css同时使用一个hash值 如果重新打包会导致所有缓存失败, filename : 'css/built.[chunkhash:10].css' chunkhash : 根据chunk 生成的hash值,如果打包来源于同一个chunk 那么hash值就一样 问题:因为js和css同时使用一个hash值 filename : 'css/built.[contenthash:10].css' contenthash : 根据文件内容生成的hash值,不同文件hash值不一样 */
-
tree shaking 去除无用的代码
//当webpack.config.js mode:'production' 则开启 tree shaking /* 前提条件: a: 必须使用es6模块化 b: 开启production环境 作用:减少代码体积 在package.json中配置 "sideEffects" : false, 所有代码没有副作用(都可以进行 tree shaking) 问题:可能会把css/ @babel/polyfill 文件干掉 "sideEffects" : ["*.css","*.scss"], */
-
code split ( 代码分割 )
//单入口、多入口 module.exports = { //entry : './src/main.js' // 单入口 //多入口 entry : { main : './src/main.js', test : './src/test.js' }, //输出配置 output : { //name 给输出的文件命名,否则多入口输出都是一个文件名称。 filename : js[name].js, path : path.resolve(__dirname,'build') } }
//webpack.config.js //将node_module中代码单独打包一个chunk输出 //会分析多入口chunk中,有没有公共的文件。如果有只打包一个 //例如 a.js b.js都依赖jquery 这样单独拎出jquery打包 module.exports = { optimization:{ splitChunks : { chunks : 'all' } } }
//通过js逻辑,完成文件被单独打包一个chunk import(/*webpacjChunkName:test*/'.test') .then(() => { console.log('文件加载成功') }) .catch(() => { console.log('文件加载失败') })
-
懒加载 预加载
//懒加载 //场景:当点击按钮的时候在调用某个模块、以及某个模块中的方法 //不直接 import引入 而是把引入放在逻辑里面 btn.addEventListener('click',() => { import(/*webpacjChunkName:test*/'./text.js') .then((fn) => { fn() }) })
//预加载 //会在模块使用之前去加载js文件 // webpackPrefetch :true btn.addEventListener('click',() => { import(/*webpacjChunkName:test,webpackPrefetch :true*/'./text.js') .then((fn) => { fn() }) })
-
PWA 离线访问
//webpack.config.js配置 //安装 // $ cnpm instal work-box-webpack-plugin -D //引入 // const WorBoxWebpackPlugin = require('work-box-webpack-plugin'); //配置 module.exports = { plugins : [ new WorBoxWebpackPlugin({ /* 1: 使serviceworler快速启动 2:删除旧的serviceworker 生成有一个serviceworker 配置文件 */ clientsClaim : true, skipWaiting : true, }) ] } //在入口文件js中注册serviceworker if('serviceworker' in navigator){ window.addEventListener('load',() => { navigator.serviceworker .register('./serviceworker.js') .then(() => { console.log('serviceworker注册成功') }) .catch(() => { console.log('serviceworker注册失败') }) }) } /* 注意事项: 1: eslint 不识别 window / navigator全局变量 解决: 在package.json中eslintConfig配置 "env" : { "browser" : true //支持浏览器端全局变量 } 2: serviceworker 必须运行在服务器上 */
-
多进程打包
// cnpm install thread-loader -D //配置 : 在 babel中使用即可 { test: /.js$/, exclude: /node_modules/, use : [ { /* 开启多个进程打包: 进程启动大概在600ms 进程通信也有开销 只有工作消耗比较大的时候才能使用多进程打包 */ loader : 'thread-loader', options : { workers : 2//进程2个 } }, { loader: 'babel-loader', options: { persets: [ [ '@babel/preset-env', { useBuildIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '60', ie: '9', safari: '10', edge: '17' } } ] ] } } ] }
-
externals (忽略某个包进行打包 : 例如忽略引入的jquery库)
//配置:只需要在webpack.config.js 添加 externals即可 externals : { //拒绝jQuery被打包进来 //jQuery 为 npm包的名称 jquery : 'jQuery' }
-
DLL打包
// 创建 webpack.dll.js文件 // 使用dll技术对某些库 (第三方库 : jquery、react、vue ...) 进行单独打包 const {reslove} = require('path') const webpack = require('webpack') module.exports = { entry : { //最终打包成的[name] => jquery //['jquery'] 要打包的库是 jquery jquery : ['jquery'] }, output : { filename : '[name].js', path : resolve(__dirname,'dll'), library : '[name]_[hash]' //打包的库里面向外暴露出去的内容的名称 }, plugins : [ new webpack.DllPlugin({ name : '[name]_[hash]' //映射库的暴露的内容名称 path : resolve(__dirname,'dll/manifest.json') //输出文件的路径 }) ], mode : 'production' } //webpack.config.js中配置 // 安装 引入 webpack add-asset-html-webpack-plugin plugins : [ // 告诉webpack哪些库不参与打包,同时使用时候的名称也需要变更 new webpack.DllReferencePlugin({ manifest : path.resolve(__dirname,'dll/manifest.json') }), //将某个文件打包输出去,并在html中自动引入 new AdAssetHtmlWebpackPlugin({ filename : path.resolve(__dirname,'dll/jquery.js') }) ]
-