webpack 性能优化

348 阅读4分钟

分析工具

体积优化

  • JS压缩
  • CSS压缩
  • 图片压缩
  • 拆分代码

速度优化

开发环境优化

HMR(hot module replacement) 热模块替换

  • 作用:一个模块发生变化,只会重新打包这个模块(其他不变),提高构建速度
  • 样式文件:可以使用HMR功能,因为使用style-loader内部实现了
  • Js文件:默认不能使用HMR功能---》需要修改js代码,添加支持HMR功能的代码 注意:HMR功能对JS文件的处理,只能处理非入口js文件的其他文件。
  • html文件:默认不能使用HMR功能,同时会导致问题:html文件不能热更新了。解决:修改entry入口,将html文件引入
const webpack = require('webpack')

module.exports = {
   ...
   devServer:{
      hot:true,
      hotOnly:true
   },
   plugins:{
     new webpack.HotModuleReplacementPlugin()
   }
   
}

source map

source map :一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪源代码错误)

module.exports = {
   ....
   devtool:'source-map'
}

image.png

生产环境优化

oneOf

  • 作用:一个文件不会被多个loader匹配
  • 注意:不能有两个配置处理同一种类型文件 比如:对于js文件的eslint-loader和babelloader,可以把先执行的eslint-loader放在oneOf的上方
module.exports = {
  ...
  rules:[
   {
     test:/\.js$/,
     loader:'eslint-loader',
   }
   oneOf:[
     {
       test:/\.js$/,
       loader:'babel-loader',
     }
   ]
  ]
}

缓存

  • babel缓存:cacheDirectory:true ---》让第二次打包构建速度更快
module.exports = {
 ...
 rules:[
   {
    test:/\.js$/,
    loader:'babel-loader',
    options:{
    //开启babel缓存,第二次构建时,会读取之前的缓存
      cacheDirectory:true
    }
   }
 ]
}
  • 文件资源缓存 hash:每次webpack构建时会生成一个唯一的hash值 问题一:因为js和css同时使用同一个hash值,如果重新打包,会导致所有缓存失效。 解决:chunkhash,根据chunk生成的hash值。但是还是会出现问题: js和css的hash值还是一样的,因为css时在js中被引入,所以同属于一个chunk. 解决:contenthash:根据文件的内容生成hash值。不同文件hash值不一样。 ---> 让代码上线运行缓存更好使用
module.exports = {
   ...
   entry:'./src/index.js',
   output:{
     filename:'js/built.[contenthash:10].js'
   },
   ...
   plugins:[
     new MiniCssExtractPlugin({
        filename:'css/built.[contenthash:10].css'
     })
   ]
  
}

tree shaking

作用:去除无用代码 条件:必须使用Es6模块化,开启production环境

package.json中配置
"sideEffects":false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css/@babel/polyfill(副作用)文件去除
"sideEffects":["*.css","*.less"]

分离

  • code split(代码分割) 作用:可以把代码分离到不同的bundle中,实现按需加载或并行加载文件。代码 分离可以用于获取更小的bundle,以及控制资源加载优先级,提高加载时间。
  • bundle split 过程:创建多个更小的文件,并行加载,以获得更好的缓存效果。 作用:使浏览器并行下载,提高下载速度。运用浏览器缓存,只要代码被修改,文件名中的哈希值改变了才会去再次加载。

PWA(Progressive Web Application) 离线访问技术

webpack配置使用workbox-webpack-plugin插件,生成一个serviceWorker配置文件

安装插件:npm i worker-webpack-plugin
引入插件:const worboxWebpackPlugin = require('worker-webpack-plugin')

module.exports = {
  ... 
  plugins:[ 
    new WorkboxWebpackPlugin.GenerateSW({ //生成一个serviceworker配置文件
      clientsClaim:true,// 帮助serviceworker快速启动
      skipWaiting:true// 删除旧的serviceworker
    })
  ]
}

在入口文件index.js中注册serviceWorker
if('serviceWorker' in navigator){
  window.addEventListener('load',()=>{
    navigator.serviceWorker.register('/service-worker.js')
    .then(()=>{
       // do something
    }).catch(()=>{
       // do something
    })
  })
}
修改package.json中eslintConfig配置(因为eslint不认识window,navigator等全局变量)
"eslintConfig":{
  "env":{
    "browser":true,//支持浏览器的全局变量
  }
}
serviceWorker必须运行在服务器上,需要启动服务器
1:通过nodejs运行
2:安装npm i serve -g
serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去

externals

防止将某些import的包(package)打包到bundle中,而是在运行时再去从外部获取这些扩展依赖

module.exports = {
  ...
  externals:{
   // 拒绝打包时引入
   jquery:'jQuery',
  }
}
但是需要在index.html文件中手动引入

优化构建速度

  • 缩小文件的搜索范围
    • resolve字段告诉webpack怎么去搜索文件
    • module。noParse字段告诉webpack不必解析那些文件,排除对非模块库文件的解析
    • 配置loader,通过test、exclude、include 缩小搜索范围
  • 使用DIIPlugin减少基础模块编译次数
  • 使用HappyPack开启多进程Loader转换
    • 运行在Node.js之上的Webpack是单线程模型,只能一个一个文件处理,不能并行处理。HappyPack可以将任务分解给多个子进程,最后将结果发给主进程。
  • 使用ParalleUglifyPlugin开启多进程压缩JS文件
    • ParalleUglifyPlugin可以开启多个子进程,每个子进程使用UglifyJS压缩代码,并行执行

优化开发体验

  • webpack监听文件
    • 1.启动webpack时加上--watch参数
    • 2.在配置文件中设置watch:true。合理设置watchOptions可以优化监听体验。
  • 开启模块热替换HMR
  • DevServer刷新浏览器

优化输出质量-压缩文件体积

  • 区分环境---减少生成环境代码体积
  • 压缩代码--JS、CSS、ES
  • 使用Tree Shaking剔除JS死代码

优化输出质量--加速网络请求

  • 使用CSN加速静态资源加载
    • 网页的静态资源上传到CDN服务上,访问资源时,使用CDN服务提供的URL。
  • 多页面应用提取页面键公共代码,利用缓存
  • 分割代码,按需加载