webpack 性能优化

开发
今天我为大家介绍一下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文件的其他文件。

  1. if(module.hot){ 
  2.     //一旦module.hot是true,说明开启HMR功能,让HMR功能代码生效 
  3.     module.hot.accept('./xxx.js',function(){ 
  4.         //此方法会监听print.js文件的变化,一旦发生变化,其他默认不会重新打包构建 
  5.         //会执行后面的回调函数 
  6.         xxx(); 
  7.     }) 

html文件: 默认不能使用HMR功能,同时会导致问题:html文件不能热更新了 解决:改 entry:['入口js','html'] ,但html文件只有一个,所以不用做HMR功能

  1. devServer:{ 
  2.         //项目构建后的目录 
  3.         contentBase: resolve(__dirname,'build'), 
  4.         //启用gzip压缩 
  5.         compress:true
  6.         //端口号 
  7.         port:3000, 
  8.         //自动打开浏览器 
  9.         open:true 
  10.     } 

优化 开发环境 代码调试
source-map 一种提供源代码到构建后代码映射的技术
如果构建后代码出错了,通过映射可以追踪到错误的代码

  1. webpack.config.js 
  2.  
  3. devtools:'source-map' 
  4. //其他 参数 [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map 
  5.  
  6. source-map : 外部 
  7.     错误代码的准确信息和错误位置 
  8. inline-source-map : 内联 
  9.     错误代码的准确信息和错误位置 
  10. hidden-source-map : 外部 
  11.     错误代码的错误原因 但没有错误位置,不能追踪到源代码的错误,只能提示到构建后代码的位置 
  12. eval-source-map : 内联 
  13.     每一个文件都生成对应的source-map,都在eval 
  14.     错误代码的准确信息和错误位置 
  15. nosources-source-map : 外部 
  16.     能找到错误代码的准确信息 但没有任何源代码信息 
  17. cheap-source-map : 外部 
  18.     错误代码的准确信息和错误位置 只精确到行,不精确到列 
  19. cheap-module-source-map : 外部 
  20.     错误代码的准确信息和错误位置 
  21.     module 会将 loader 的 source-map加入 
  22. 内联 和 外部的区别 : 
  23.     1.外部生成了文件但内联没有生成 
  24.     2.内联构建速度更快 

开发环境:速度快,调试更友好

  1. 速度快 eval>inline>cheap>... 
  2. 调试更友好 souce-map>cheap-module-souce-map>cheap-souce-map 
  3. 所以 一般用eval-source-map 

生产环境:源代码要不要隐藏,调试要不要友好?内联会让体积编码,所以一般不用内联

 

  1. nosources-source-map 隐藏源代码 
  2. hidden-source-map 只隐藏源代码,会提示构建购代码错误信息 
  3. --> source-map /cheap-module-souce-map 

优化生产环境
oneOf
rules里中有许多个loader,这样会导致每个文件都会被所有的loader过一遍,有些能处理,有些处理不了。所以可以利用oneOf达到以下loader只会匹配到第一个。但需要注意,不能有两个loader同时处理同一个文件

  1. webpack.config 
  2. module.exports={ 
  3.     //.... 
  4.     module:{ 
  5.         rule:[ 
  6.             //正常来讲,一个文件只能被一个loader处理 
  7.             //当一个文件要被多个loader处理,那么一定要指定loader的执行顺序 
  8.             // 先执行eslint 再执行babel 
  9.             { 
  10.                 test:/\.js$/, 
  11.                 exclude:/node_modules/, 
  12.                 //优先执行 
  13.                 enforce:'pre'
  14.                 loader:'eslint-loader'
  15.                 options:{ 
  16.                     fix:true 
  17.                 } 
  18.             }, 
  19.             { 
  20.               oneOf:[ 
  21.                     { 
  22.                         test: /\.css$/, 
  23.                         use:[ 
  24.                             ...commonCssLoader 
  25.                         ] 
  26.                     }, 
  27.                     { 
  28.                         test:/\.less$/, 
  29.                         use:[ 
  30.                             ...commonCssLoader,'less-loader' 
  31.                         ] 
  32.                     }, 
  33.                     { 
  34.                         test:/\.js$/, 
  35.                         exclude:/node_modules/, 
  36.                         loader:'babel-loader'
  37.                         options:{ 
  38.                             // 预设 :指示babel做怎样的兼容性处理 
  39.                             presets:[ 
  40.                             [ 
  41.                                     '@babel/preset-env'
  42.                                     { 
  43.                                         //按需加载 
  44.                                         useBuiltIns:'usage'
  45.                                         //指定core-js版本 
  46.                                         corejs:{ 
  47.                                             version:3 
  48.                                         }, 
  49.                                         //指定兼容性做到哪个版本的浏览器 
  50.                                         targerts:{ 
  51.                                             chrome: '40'
  52.                                             fixfox: '50'
  53.                                             ie: '9'
  54.                                             safari: '10'
  55.                                             edge: '17' 
  56.                                         } 
  57.                                     } 
  58.                             ] 
  59.                             ] 
  60.                         } 
  61.                     }, 
  62.                     { 
  63.                         test:/\.(png|jpg|gif)/, 
  64.                         loader:'url-loader'
  65.                         enModule:true
  66.                         options:{ 
  67.                             limit:8*1024, 
  68.                             name'[hash:10].[ext]'
  69.                             outputpath:'' 
  70.                         } 
  71.                     }, 
  72.                     { 
  73.                         test:/\.html$/, 
  74.                         loader:'html-loader' 
  75.                     }, 
  76.                     { 
  77.                         exclude:/\.(js|less|css|png|jpg|gif)/, 
  78.                         loader:'file-loader'
  79.                         options:{ 
  80.                             name:'[hash:10].[ext]' 
  81.                         } 
  82.                     } 
  83.                 ] 
  84.             } 
  85.         ] 
  86.     }, 

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

  1.     test:/\.js$/, 
  2.     exclude:/node_modules/, 
  3.     loader:'babel-loader'
  4.     options:{ 
  5.         // 预设 :指示babel做怎样的兼容性处理 
  6.         presets:[ 
  7.         [ 
  8.             '@babel/preset-env'
  9.             { 
  10.                 //按需加载 
  11.                 useBuiltIns:'usage'
  12.                 //指定core-js版本 
  13.                 corejs:{ 
  14.                     version:3 
  15.                 }, 
  16.                 //指定兼容性做到哪个版本的浏览器 
  17.                 targerts:{ 
  18.                     chrome: '40'
  19.                     fixfox: '50'
  20.                     ie: '9'
  21.                     safari: '10'
  22.                     edge: '17' 
  23.                 } 
  24.             } 
  25.         ] 
  26.         ], 
  27.         //第二次构建时,会读取之前的缓存 
  28.         cacheDirectory: true 
  29.         } 
  30.     }, 

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

  1. hash:每次webpack构建会生成一个唯一hash值 
  2.         问题: 因为js和css同时使用一个hash值,如果重新打包,会导致所有缓存失效,可能我却只改了一个文件, 
  3.     chunkhash:根据chunk生成hash值,如果打包来源于同一个chunk,那么hash值也一样 
  4.         问题:js和css的hash值还是一样的。 
  5.             原因:css是由js引入的,所以属于同一个chunk 
  6.     contenthash: 根据文件内容生成hash值, 

  1. webpack.config.js 

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

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

code split
1.入口配置

  1. 单入口 //单页面应用 
  2.     entry:'./src/js/index.js'  
  3.     多入口 //多页面应用 
  4.     entry:{ 
  5.         index:'./src/js/index.js'
  6.         test:'./src/js/test.js' 
  7.     } 

2.optimization

  1. module.exports={ 
  2.     //... 
  3.     // 可以将nodemudules中的代码单独打包成一个chunk最终输出 
  4.     // 还可以自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk 
  5.     optimization:{ 
  6.         splitChunks:{ 
  7.             chunks:'all' 
  8.         } 
  9.     } 

3.import 动态导入语法,能将某个文件单独打包
通过js代码,让某个文件被单独打包成一个chunk,通过注释可以固定此文件的名称

  1. import(/*webpackChunkName: 'xxxName' */'./xx/xxx.js'
  2.     .then(res =>{ 
  3.         //加载成功 
  4.     }) 
  5.     .catch(()=>{ 
  6.         //加载失败 
  7.     }) 

懒加载和预加载
1.懒加载 当文件需要用时才加载
import 动态导入语法

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

2.预加载 webpackPrefetch:true
./xx/ss.js 已经被加载了,点击的时候再从缓存中加载,

  1. document.getElementById('btn').onclick = function(){ 
  2.     import(/*webpackChunkName: 'xxxName',webpackPrefetch:true */'./xx/ss.js'
  3.     .then(res=>{ 
  4.         //干啥干啥 
  5.     }) 

正常加载可以认为是并行加载(同一时间加载多个文件) 预加载prefectch 等其他资源加载完毕,浏览器空闲了,再偷偷加载资源 兼容性比较差 慎用
PWA 渐进式网络开发应用程序
网络离线可访问
webbox-->webbox-webpack-plugin

  1. const WebboxWebpackPlugin = require('webbox-webpack-plugin'
  2. module.exports={ 
  3.     plugins:[ 
  4.         new WebboxWebpackPlugin.GenerateSW({ 
  5.             /* 
  6.                 1.帮助 serviceWorker 快速启动 
  7.                 2.删除旧的 serviceWorker  
  8.  
  9.                 生成一个 serviceWorker 配置文件 
  10.              */ 
  11.             clientsClaim:true
  12.             skipWaiting:true 
  13.         }) 
  14.     ] 
  15.  
  16. index.js 中注册serviceworker 
  17. //处理兼容性 
  18. if('serviceWorker' in navigator){ 
  19.     window.addEventListener('load',()=>{ 
  20.         navigator.serviceWorker 
  21.             .register('./service-work.js'
  22.             .then(()=>{ 
  23.                 //成功 
  24.             }) 
  25.             .catch(()=>{ 
  26.                 //失败 
  27.             }) 
  28.     }) 
  29.  
  30. 1.可能会出现问题 eslint不认识window和navigator 
  31. 解决 package.json中eslintConfig中配置 
  32. "env":{ 
  33.     "browser":true //支持浏览器端的变量 
  34.  
  35. 2. sw代码必须运行在服务器上 
  36.     -->node.js  
  37.         --> npm i serve -g  
  38.             serve -s build 启动一个服务器将build下的资源作为静态资源暴露出去 

多进程打包
thread-loader 一般给babel-loader用
但需要注意
进程启动大约需500ms,进程间通信也有开销。只有工作消耗时间比较长,才需要多进程打包

  1.     test:/\.js$/, 
  2.     exclude:/node_modules/, 
  3.     use:[ 
  4.         //'thread-loader'
  5.         { 
  6.             loader:'thread-loader'
  7.             options:{ 
  8.                 workers: 2 //进程2个 
  9.             } 
  10.         } 
  11.         { 
  12.             loader:'babel-loader'
  13.             options:{ 
  14.                 // 预设 :指示babel做怎样的兼容性处理 
  15.                 presets:[ 
  16.                 [ 
  17.                     '@babel/preset-env'
  18.                     { 
  19.                         //按需加载 
  20.                         useBuiltIns:'usage'
  21.                         //指定core-js版本 
  22.                         corejs:{ 
  23.                             version:3 
  24.                         }, 
  25.                         //指定兼容性做到哪个版本的浏览器 
  26.                         targerts:{ 
  27.                             chrome: '40'
  28.                             fixfox: '50'
  29.                             ie: '9'
  30.                             safari: '10'
  31.                             edge: '17' 
  32.                         } 
  33.                     } 
  34.                 ] 
  35.                 ], 
  36.                 //第二次构建时,会读取之前的缓存 
  37.                 cacheDirectory: true 
  38.                 } 
  39.         } 
  40.     ] 
  41.     }, 

externals

  1. module.exports={ 
  2.     externals:{ 
  3.         //忽略/拒绝  库名 -- npm 包名  
  4.         //可以在index.html中引入cdn 
  5.     } 

dll 动态连接
使用dll技术 对某些库(第三方库) 进行单独打包

  1. 指令 webpack --config webpack.dll.js 
  2. webpack.dll.js 
  3. const {resolve} = require('path'
  4. const webpack = require('webpack'
  5. module.exports = { 
  6.     entry:{ 
  7.         //最终打包生成的[name]-->jquery 
  8.         //['jquery']-->要打包的库是jquery 
  9.         jquery:['jquery'
  10.     }, 
  11.     ouput:{ 
  12.         filename:'[name].js'
  13.         path:resolve(__dirname,'dll'), 
  14.         library:'[name]_[hash]' //打包的库里面向外暴露出去的内容叫什么名字 
  15.     }, 
  16.     plugin:[ 
  17.         new webpacl.DllPlugin({ 
  18.             //打包生成一个manifest.json --> 提供和jquery映射 
  19.             name'[name]_[hash]',//映射库的暴露内容名称 
  20.             path:resolve(__dirname,'dll/manifest.json'
  21.  
  22.         }) 
  23.     ], 
  24.     mode:'production' 
  25.  
  26. webpack.config.js 
  27. const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin'
  28. module.exports={ 
  29.     plugins:[ 
  30.         //告诉webpack哪些库不参与打包,同时名称也得变 
  31.         new webpack.DllReferencePlugin({ 
  32.             manifest: resolve(__dirname,'dll/manifest.json'
  33.         }), 
  34.         //将某个文件打包输出出去,并在html中引入该资源 
  35.         new AddAssetHtmlWebpackPlugin({ 
  36.             filepath:resolve(__dirname,'dll/jquery.js'
  37.         }) 
  38.     ] 

编辑推荐

 

责任编辑:姜华 来源: 晨曦大前端
相关推荐

2019-03-15 15:00:49

Webpack构建速度前端

2021-11-09 09:57:46

Webpack 前端分包优化

2019-03-26 10:02:16

WebpackJavascript前端

2019-03-05 10:20:49

WebWebpack分离数据

2023-04-27 08:35:20

Webpack 4性能优化

2023-05-31 08:19:23

Webpack4Webpack 5

2017-07-11 15:50:11

前端webpack2优化

2021-10-25 10:23:49

Webpack 前端Tree shakin

2021-09-06 06:45:06

Webpack优化MindMaster

2021-09-27 08:16:38

Webpack 前端Cache

2021-10-12 09:52:30

Webpack 前端多进程打包

2021-05-08 08:35:33

Webpack前端性能

2021-11-15 09:44:49

Webpack 前端 Scope Hois

2018-04-19 15:13:53

javascriptwebpackvue.js

2014-12-10 10:12:02

Web

2009-09-08 09:45:23

App Engine性

2022-02-16 14:10:51

服务器性能优化Linux

2021-12-24 08:01:44

Webpack优化打包

2009-06-16 16:10:59

Hibernate性能

2017-08-08 09:45:43

Python性能优化
点赞
收藏

51CTO技术栈公众号