webpack性能优化全方案

提升webpack性能优化无非从两个方面入手:
1.如何构建速度
2.如何优化打包后的文件

如何文件构建速度

webpack构建的过程,其实是把,从入口开始,通过AST语法树分析,把所有依赖的模块,结合loader和plugin,都进行内容转换,合并在一起,最终输出打包文件的过程。
所以,要提高构建速度,就要减少不必要的模块依赖,和loader、plugin的使用和其他提升速度的办法等等

1.减少不必要的模块依赖
module.noParse字段可用于配置不需要解析的模块。对于类似jquery和lodash这些大型的第三方库,本身就是兼容性非常好的,不需要在进行解析。可以忽略以提升构建速度。

module.exports = {
  // ...
  module: {
    noParse: /jquery|lodash/, // 正则表达式

    // 或者使用 function
    noParse(content) {
      return /jquery|lodash/.test(content)
    },
  }
}

2.减少不必要的loader处理
使用loader的时候尽可能考虑不需要处理的模块,以提升构建速度。
通过module.rule.excludemodule.rule.include排除或仅包含需要应用loader的场景。
例如:

rules: [
  {
    test: /\.js$/,
    exclude: /node_modules/, //不匹配
    loader: "eslint-loader",
  },
  {
    test: /\.js$/,
    include: /src/, //匹配
    loader: "babel-loader",
  },
],

eslint-loader是代码规范检测的loader,所以没必要也不需要去匹配/node_modules下的模块。
babel-loader是为了吧es6和更高版本的语法转换为es3或者es5的语法。假设/src下都是自定义的模块,所以只需要转换自己写的模块就好

3.通过配置区分生产环境和开发环境的plugin,不要混用,导致影响构建速度。

4.使用cache-loader进行缓存文件。
对于一些比较消耗性能的模块,并且打包后文件内容没有改动可以使用cache-loader进行缓存。因为缓存是直接保存在硬盘,所以存取缓存都是要消耗一定的性能。小文件没必要缓存。下次就可以不使用loader而使用缓存。

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'cache-loader',
            options: {
              cacheDirectory: path.resolve('.cache') //还能进行配置
            }
          },
          'babel-loader'
        ],
        include: path.resolve('src')
      }
    ]
  }
}

5.开启多线程构建
webpack是基于node.js运行的,而node.js是单线程的,所以webpack处理文件是一个个处理的,如果需要处理的文件一多的话,处理速度会很慢,因此在需要解析大量文件的项目中,可以通过开启多线程来处理文件,以加快构建速度。

  • loader
    thread-loader会开启一个线程池,线程池中包含适量的线程,利用多线程同时开启多个loader的处理
// webpack.config.js 文件配置
module.exports = {
  mode: "development",
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          "thread-loader",
          "babel-loader"
        ]
      }
    ]
  }
};

  • plugin

可以使用happypack是一个开启多线程解析和构建文件的plugin。

var HappyPack = require('happypack')
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
module.exports = {
  mode: "development",
  plugins: [
  new HappyPack({
    id: 'js',
    loaders: ['babel-loader'],
    // 用于检索工作线程的预定义线程池
    threadPool: happyThreadPool,
    // 启用此选项可将状态消息从HappyPack记录到STDOUT
    verbose: true
  })
]
开发阶段的页面响应速度

当webpack开启watch,当文件被修改后,webpack会自动构建输出新的打包文件,但是还需要刷新浏览器重载页面才能看到最新的内容,这样的会降低开发效率。webpack-dev-server正好适用于处理类似的问题。webpack-dev-server热更新热替换功能能提高我们开发阶段的页面响应速度。

1.热更新
热更新可以理解为当文件有修改,页面会实时刷新。原理是,webpack-dev-server使用的是express框架作为文件资源的http服务器,通过websoket协议和浏览器端进行通讯。当文件修改的时候,http服务器会监听到文件变化,而触发webpakc编译文件,但是文件内容不会输出到output的目录,而是把编译的内容存放到内存中,然后浏览器就会实时更新内存中的内容,实现页面实时更新。

2.热替换HMR(Hot Module Replacement)
热更新是把整个页面刷新,而热替换是只刷新修改的那部分。css样式修改可以立马看到热替换效果,因为css只是样式。而如js这些逻辑性的代码,无法页面热替换,除了css文件都需要额外的手动处理才能热替换。

// webpack.config.js
const webpack = require('webpack')
 
module.exports = {
  // ...
  devServer: {
    // 开启 HMR 特性,如果资源不支持 HMR 会 fallback 到 live reloading
    hot: true
    // 只使用 HMR,不会 fallback 到 live reloading
    // hotOnly: true
  },
  plugins: [
    // ...
    // HMR 特性所需要的插件
    new webpack.HotModuleReplacementPlugin()
  ]
}

具体热更新和热替换参考:https://blog.csdn.net/ganle/article/details/106455612

如何优化打包后的文件

打包后的文件最优的结果就是文件尽可能少文件尽可能小,所以只需要根据这两个方向去优化。

1.模块分离
模块分离就是将一个整体的代码,分布到不同的打包文件中去,目的就是为了减少公共代码,降低打包文件总体积,特别是对于一些大型的第三方库,使用.模块分离还能充分利用浏览器缓存去加载这些公共模块,不用每次都去请求,利于传输速度。当多个chunk引入了公共模块的时候,webpack默认是不分离模块的,这样就会造成代码重复,所以当多个chunk引入了公共模块或者公共模块体积比较大,或者公共模块较少变动的时候,可以使用分包。
分包有两种方式:手动分离和自动分离

  • 手动分离
    手动分包就是开发人员通过根据分析模块的依赖关系,把公共模块通过打包或手动放到一个公共文件夹里,被打包后的index.html文件引入到页面。
    大致步骤:
    (1)提取公共模块到公共文件夹,并生成资源清单列表(可以手动创建,也可以使用webpack内置插件DllPlugin生成)
    (2)在html页面引入公共模块
    (3)使用DllReferencePlugin控制chunk打包结果,资源清单里面有的模块,不在打包进入bundle里面。

  • 自动分离
    自动分离相对于手动分离会方便一点,只需要配置要分离策略。
    webpack提供了optimization配置项,用于配置一些优化信息
    其中splitChunks是分离模块策略的配置

module.exports = {
  optimization: {
    splitChunks: {
      // 分包策略
      chunks: 'all',
    }
  }
}

使用以上chunksall,就可以满足大部分的场景了。

具体细节参考:
https://blog.csdn.net/xun__xing/article/details/108312321
https://webpack.docschina.org/plugins/split-chunks-plugin/

2.代码压缩

webpack自动集成了Terser插件进行打包时代码压缩,只需要配置optimization选项即可

//压缩js
const TerserPlugin = require('terser-webpack-plugin');
//压缩css
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      }
    ]
  },
  optimization: {
    // 是否要启用压缩,默认情况下,生产环境会自动开启
    minimize: true, 
    minimizer: [ // 压缩时使用的插件,可以有多个
      new TerserPlugin(), 
      new OptimizeCSSAssetsPlugin()
    ],
  },
};

3.删除无用的代码和模块
webpack2开始内置Tree-Shaking功能来删除用不到或者对程序没有影响的代码,极大的减少了打包后的体积。tree-shaking是基于es6的,因此对于一些使用commonJs导出的第三方库如lodash,应该换成es6方式导出的版本,这样才能使用tree-shaking优化。

更多详情参看:https://juejin.cn/post/6844903544756109319

4.模块懒加载
对于一些不会立即使用的模块,可以通过懒加载的形式导入import('xxx'),webpack打包的时候会把这些需要懒加载的模块打包成独立的文件,只有当使用到的时候才会去加载这个文件,并把模块添加到webpackJsonp对象中。
更多参考:https://blog.csdn.net/qq_38888512/article/details/116448683

其他优化相关

1.使用webpack Bundle Analyzer作为模块打包分析
webpack Bundle Analyze分析工具
2.使用compression-webpack-plugin进行预压缩成gzip
compression-webpack-plugin进行压缩
前端优化gzip传输

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值