webpack 性能优化

webpack 性能优化

生产环境性能优化

  • 1.优化打包构建速度
    • oneOf
      • 都不需要安装
      • oneOf里面 loader只会匹配一个
      • 注意: 不能有两个配置处理同一种类型的文件
    • 缓存
      • babel缓存
      • 安装 babel-loader @babel/preset-env(解决兼容 只针对文件中需要兼容的代码导入)
        // 开启babel缓存
        // 第二次构建时,会读取之前的缓存
        cacheDirectory: true
        
    • 多进程打包 (thread-loader)
      • 安装thread-loader
      • 进程启动大概600ms,进程通信也有开销.只有工作消耗时间比较长,才需要多进程打包
      <!-- 一般使用在babel-loader 对其进行优化 -->
      {
          loader:'thread-loader',
          options: {
              workers: 2 // 进程数
          }
      },
      
  • 2.优化代码运行的性能
    • 缓存(hash-chunkhash-contenthash)

      • 都不需要安装
      • 用法:使用不同的hash值给css和js文件命名 实现局部刷新
      output: {
          filename:"js/built.[contenthash:10].js",
          path: resolve(__dirname,'build')
      },
      // MiniCssExtractPlugin作用代替style-loader 提取单独的css文件
      new MiniCssExtractPlugin({
          filename: 'css/built.[contenthash:10].[ext].css'
      }),
      
      • hash就是webpack每次构建成功时的生成的唯一hash值
        • 缓存缺点:只要是webpack重新打包那么所有的文件都会刷新
      • chunkhash来自于同一个入口就同属于同一个chunkhash
        • 缓存缺点:只要同一个入口文件中的某个文件改变比如css 那么js文件也会刷新
      • contenthash文件自身的hash值 文件改变contenthash才会变 能让js css更好的持久化缓存
    • tree-shaking

      • 无需安装 去除无用代码 减少代码体积
      • 前提: 1.必须使用es6模块化 2.开启production环境
      <!-- 在package.json中配置 (不配置 可能有些版本原因导致代码被删) -->
      // 问题:可能会把css /  @babel/polyfill (副作用)文件干掉
      "sideEffects": false // 所有的代码都没有副作用
      <!-- 如果使用json配置建议下面这种写法 -->
      "sideEffects": ["*.css","*.less""] // 标记不要树摇css文件
      
    • code split

      • 都不需要安装
      • 将代码分割成多个包,可并行加载,也可以实现按需加载
      • 单入口
      // 单个入口文件 
      entry: './src/js/index.js',
      output: {
          filename:"js/built.[contenthash:10].js",
          path: resolve(__dirname,'build')
      },
      // 第一种 可以将node_modules中代码单独打包一个chunk最终输出 自动分析chunk中有没有公共的文件。 
      // 如果有会打包成单独一个chunk 
      optimization: {
          splitChunks: {
              chunks: 'all'
          }
      },
      // 第二种 通过js代码,让某个文件被单独打包成一个chunk。 import动态导入语法,能将某个文件单独打包
      import(/* webpackChunkName: 'test'*/'./test')
      .then(({mul,count})=>{
      console.log(mul(2,5));
      })
      .catch(()=>{
      // eslint-disable-next-line
      console.log('文件加载失败');  
      })
      
      • 多入口
      // 多个入口文件
      entry: {
          index: './src/js/index.js',
          test: './src/js/test.js',
      },  
      output: {
          // [name] 取文件名
          filename:"js/[name].[contenthash:10].js",
          path: resolve(__dirname,'build')
      },
      // 第一种 可以将node_modules中代码单独打包一个chunk最终出 自动分析chunk中有没有公共的文件。
      // 如果有会打包成单独一chunk 
      optimization: {
          splitChunks: {
              chunks: 'all'
          }
      },
      // 第二种 通过js代码,让某个文件被单独打包成一个chunk。import动态导入语法,能将某个文件单独打包
      import(/* webpackChunkName: 'test'*/'./test')
      .then(({mul,count})=>{
        console.log(mul(2,5));
      })
      .catch(()=>{
        // eslint-disable-next-line
        console.log('文件加载失败');  
      })
      
    • 懒加载/预加载 (js代码)

      • 不需要安装
      • 懒加载 js文件懒加载 (必须生成多个文件)
      document.getElementById('btn').onclick = function () {
          import( /* webpackChunkName: 'test'*/ './test')
           .then(({mul}) => {
             console.log(mul(2, 6))
           })
           .catch(() => {
           })
       }
      
      • 预加载 Prefetch(慎用,兼容性差,不能确保加载完毕)
      document.getElementById('btn').onclick = function () {
         import( /* webpackChunkName: 'test',webpackPrefetch:true*/ './test')
           .then(({
             mul
           }) => {
             console.log(mul(2, 6))
           })
           .catch(() => {})
       }
      
    • PWA

      • 安装workbox-webpack-plugin插件、配置eslint
      • 离线可访问技术(渐进式网络开发应用程序)
      • 由serviceworker 和workbox-webpack-plugin组成
      • 处理兼容性问题
      <!-- eslint不认识浏览器变量 需在package,json "eslintConfig"中设置 -->
      "env":{
          "browser": true
      }
      
      • 用法
      // pwa插件  
      new WorkboxWebpackPlugin.GenerateSW({
          /*
              1.帮助serviceworker快速启动
              2.删除旧的 serviceworker
          */
          clientsClaim: true,
          skipWaiting: true
      }),
      
      if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
          navigator.serviceWorker
          .register('/service-worker.js')
          .then(() => {
              console.log('sw注册成功');
          })
          .catch(() => {
              console.log('sw注册失败');
          });
      });
      }
      
    • externals

      • 无需安装
      • 彻底不打包 资源引用cdn
      externals: {
          // 拒绝jQuery包被打包进来 然后通过在html中cdn引入jquery
          jquery: 'jquery'
      }
      
    • dll

      • 安装插件 AddAssetHtmlWebpackPlugin 导入webpack
      • 单独打包需要的资源 打包一次 优点:当单独打包后 以后打包就不需要重复打包
      • 新建webpack.dll.js文件 运行webpack --config webapck.dll.js指令生成文件夹
      const {resolve} = require('path')
      const webpack = require('webpack')
      module.exports = {
          entry:{
              jquery: ['jquery']
          },
          output:{
              filename: '[name].js',
              path: resolve(__dirname,'dll'),
              library: '[name]_[hash:10]'
          },
          module:{
      
          },
          plugins:[
              // 打包一个 manifest.json --> 提供jquery映射
              new webpack.DllPlugin({
              name: '[name]_[hash]',
              path: resolve(__dirname,'dll/manifest.json')
              })
          ],
          mode: 'production'
      }
      
      • 将dll文件夹中的资源导入 并在html自动引入
      // 告诉webpack哪些库不参与打包 同时使用时的名称也变了
      new webpack.DllReferencePlugin({
          manifest: resolve(__dirname,['dll/manifest.json'])
      }),
      // 将某个文件打包输出,并在HTML中自动引入该资源
      new AddAssetHtmlWebpackPlugin({
          filepath: resolve(__dirname,'dll/jquery.js')
      })
      
    • 降低图片质量
      例如 JPG 格式的图片,100% 的质量和 90% 质量的通常看不出来区别,尤其是用来当背景图的时候。我经常用 PS 切背景图时, 将图片切成 JPG 格式,并且将它压缩到 60% 的质量,基本上看不出来区别。

      压缩方法有两种:一是通过 webpack 插件 image-webpack-loader,二是通过在线网站进行压缩。

      npm i -D image-webpack-loader
      webpack 配置
      
{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000, /* 图片大小小于1000字节限制时会自动转成 base64 码引用*/
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    /*对图片进行压缩*/
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}

开发环境性能优化(主要提高编码效率)

  • 优化打包速度

    • HMR
      • 作用:一个模块发生变化,只会重新打包这一个模块(而不是全部打包)
      • 开启devServer里面设置 hot:true
      devServer:{
          contentBase: resolve(__dirname,'build'),
          compress: true, // 启动gzip
          port: 3000,
          open: true,
          hot:true // 开启HMR
      },
      
      • css必须使用style-loader
      • js 判断兼容性是否开启了HMR 功能
      // 在入口js中使用
      if (module.hot) {
          // 一旦 module.hot 为true,说明开启HMR功能
          module.hot.accept('./print.js', () => {
              // 方法会监听 print.js文件的变化,一旦发生变化,其它模块不会重新打包构建
              // 会执行后面的回调函数
              print();
          });
      } 
      
  • 优化代码调试

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

      • [inline- | hidden-| eval-][nosources-][cheap-[module-]]source-map

      • 推荐配置 eval-source-map(vue-cli或react默认此) / eval-cheap-module-source-map

  • source-map详解:

    提供源代码到构建后代码映射技术(如果代码出错了,通过映射关系可以追踪到源代码错误)
             
    cheap只确定行  module会将loader的source map加入
      
      [inline- | hidden-| eval-][nosources-][cheap-[module-]]source-map
    
    • 错误代码准确信息 准确位置

        source-map  生成在一个单独的map文件中 外部
        inline-source-map  生成在js内部文件中 只生成一个source-map 内联
        eval-source-map  生成在js内部文件中 每一个文件后面都会追加一个放在eval函数中的source-map 内联
        cheap-module-source-map: 外部 module会将loader的source map加入
      
    • 以下两个都是为了隐藏源码而生
      ( 错误代码错误原因 但是没有错误位置 不能追踪源代码错误位置 只能提示到构建后代码的位置)

      hidden-source-map  外部
      
      错误代码准确信息 但是没有任何源代码信息
      nosources-source-map: 外部
      
      错误代码准确信息 准确位置(但是只精确到行)
      cheap-source-map: 外部
      
    • 内联 和 外部的区别:

        1.外部生成文件 
        2.内联的构建速度是更快的
      
    • 开发环境:

        速度快,调试友好
      
        速度快(eval>inline>cheap>...)
        
            eval-cheap-source-map 最快
            eval-source-map 其次
            
        调试友好
        
            source-map
            cheap-module-source-map
            cheap-source-map
        -- eval-source-map(vue-cli或react默认此) / eval-cheap-module-source-map
      
    • 生产环境:

       源码隐藏 调试友好
      
         内联会让代码体积很大 基本不考虑
         nosources-source-map 全部隐藏
         hidden-source-map   只隐藏源代码 会提示构建后的代码
      
       --> source-map/ cheap-module-source-map
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值