webpack 性能优化

前言

webpack 性能优化无非是从时间和空间两个维度去分析。时间指的是打包时间尽可能快;空间指的是打包体积尽可能小。本文的 webpack 性能优化是基于 webpack 4.3.0 版本。本文主要是阐述 webpack 性能优化方面的内容,更多 webpack 知识可参考 wabpack 中 loader 和 plugins 的区别webpack 4 新特性

1. 时间维度

1.1 缓存策略

1.1.1 缓存 babel-loader

配置示例:

 {
        test: /\.js$/,
        loader: 'babel-loader?cacheDirectory=true',
        include: [
          resolve('src'),
        ],
        exclude:/node_modules/
      },

以上示例中配置了 babel-loader,其功能是将 ES6 语法转换为 ES5 语法,请注意babel-loader?cacheDirectory=true,这行配置的意思是对已经转换过的未经改动的编译文件进行缓存,以此可以加快打包时间。注意需要排除 node_modules 文件夹,因为该文件所在的 JS 使用的是 ES5 语法,所以没必要再使用 Babel 转换。

1.1.2 缓存不常变动模块

不管是 React 框架还是 Vue 框架,有些模块比如 react 、react-router、vue、vue-router 等一般情况下(除非模块升级)都不会改动,所以在打包的时候希望这些资源能够被缓存下来。那么首先得把这些模块进行分割,然后缓存。所以这里有两步。
第一步:代码分割,使用 webpack 内置的 optimization.splitChunks 配置
示例如下:

  optimization: {
    concatenateModules:true,
    splitChunks:{
      chunks: "all",//async 按需加载的异步块 initial(初始块) all(所有块)
      minSize: 30000, // 模块的最小体积
      minChunks: 1, // 模块的最小被引用次数
      maxAsyncRequests: 5, // 按需加载的最大并行请求数
      maxInitialRequests: 3, // 一个入口最大并行请求数
      automaticNameDelimiter: '~', // 文件名的连接符
      name: true,
      cacheGroups: { // 缓存组
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendor",
          priority: -10,
          enforce: true
        }
      }
    }},

在 webpack4 之前使用的是 CommonsChunkPlugin 进行代码分割。而 webpack4 之后就可以使用内置的 optimization.splitChunks 进行代码分割。代码分割的目的就是为了将一些不常更改的第三方库单独分离出来。
第二步:缓存,使用 hard-source-webpack-plugin 插件。

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
plugins: [
new HardSourceWebpackPlugin()
]

以上配置中使用的是 hard-source-webpack-plugin 进行模块缓存。这样只有在第一次打包的时候花费的时间会长一些,但是从第二次之后,模块已经被缓存到 node_modules/.cache/hard-source 目录下,不会被打包进来,大大节省打包时间。

1.2 JS 与 CSS 并行加载

在 webpack 4 之前抽离 CSS 的插件是 extract-text-webpack-plugin 。之后采用的是 mini-css-extract-plugin 插件。其作用是用 JS 中将 CSS 单独抽离出来,并行加载,可以提升加载速度。
配置如下:

const MiniCssExtractPlugin=require('mini-css-extract-plugin');
plugins:[
 // 提取单独的 CSS
    new MiniCssExtractPlugin({
      filename: utils.assetsPath('css/[name].[hash].css'),
      allChunks: true,//也包含所有的 chunk。
    }),
]

1.3 开启多线程

1.3.1 使用 HappyPack 开启多线程

除了以上直接使用缓存方案,还可以使用 HappyPack 插件对 Loader 进行多线程打包。

 module: {
  rules: [
  {
        test: /\.js$/,
        use:['happypack/loader?id=babel'],     
        include: [
          resolve('src'),
        ],
        exclude:path.resolve(__dirname, 'node_modules')
  },
]},
 plugins:[
 new Happypack({
        id:"babel",
        loaders:['babel-loader?cacheDirectory=true'],
        threads:4   //开启4个线程转换loader
 })
]

1.4 使用 DNS 加载静态数据

使用 DNS 加载静态数据会比较快,同时也可以减小公共模块的体积。

<script src="https://cdn.staticfile.org/vue/2.6.10/vue.min.js"></script>
<!-- 引入vue-router -->
<script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js"></script>
<!-- 引入组件库 -->
<script src="https://cdn.staticfile.org/element-ui/2.12.0/index.js"></script>
<!-- 引入样式 -->
<link href="https://cdn.staticfile.org/element-ui/2.12.0/theme-chalk/index.css" rel="stylesheet">

2. 空间维度

空间维度指的是通过对 CSS、JS 等静态资源进行压缩以减少资源体积。

2.1 压缩

2.1.1 CSS 压缩

optimize-css-assets-webpack-plugin 插件主要是用来压缩 CSS 文件的。
配置如下:

const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
plugins:[
   new OptimizeCSSPlugin({
      cssProcessorOptions:{safe: true, map:{ inline: false }}     
    }),
]

2.1.2 JS 压缩

在 webpack 4 之前采用的 JS 压缩插件是 uglifyjs-webpack-plugin 。之后采用的是 terser-webpack-plugin 插件。其配置方式如出一辙。
uglifyjs-webpack-plugin 配置如下:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
plugins:[
new UglifyJsPlugin({
      uglifyOptions: {
       compress: {
          warnings: false,  //buid 的时候不要报warnings
          drop_console: true  //no console
        }
      },
      sourceMap: false,
      parallel: true//是否开启多线程
    }),
]

terser-webpack-plugin 配置如下:

const TerserPlugin = require('terser-webpack-plugin');
plugins:[
   new TerserPlugin({
      terserOptions: {
        compress: {
          warnings: false,  //buid 的时候不要报warnings
          drop_console: true  //no console
        }
      },
      sourceMap: false,
      parallel: true//是否开启多线程
    }),
]

可以看出他们的区别就在于 uglifyOptions 对象与 terserOptions 对象有所不同。

2.1.3 CSS 和 JS 压缩

compression-webpack-plugin 插件可以压缩选择的类型文件,其采用的是 gzip 格式进行压缩。
配置如下:

const CompressionWebpackPlugin = require('compression-webpack-plugin');
plugins:[
   new CompressionWebpackPlugin({
      asset: '[path].gz[query]',//目标资源名称
      algorithm: 'gzip',//压缩格式
      test: new RegExp('\\.(css|js)$'),//匹配压缩文件
      threshold: 10240,//只压缩比这个大的资源10KB
      minRatio: 0.8//压缩率小于0.8才会被压缩
    })
]
发布了252 篇原创文章 · 获赞 2360 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_44135121/article/details/103420843