webpack性能优化配置

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')
              })
          ]
      
原文地址:https://www.cnblogs.com/bruce-w/p/14074156.html