webpack4之代码分割splitChunks和压缩优化

我们打包出来的js文件,只要修改或增加了内容,就会导致入口js文件的hash变化,从而重新打包。为了提高打包速度,每次变化仅仅是重新打包自定义代码部分,webpack4提供了optimization.splitChunks

回顾一下:webpack3时代,项目的代码分离抽取出来,是这样子的:使用new webpack.optimize.CommonsChunkPlugin,分别分离出第三方库,webpack运行时的代码文件,自定义公共代码部分

    new webpack.optimize.ModuleConcatenationPlugin(),
    // vendor,分离出的第三方库:node_modules的模块,这些是固定的
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // 分离出的运行时的代码,这些经常有修改,经常要webpack重新打包
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // 公共模块代码
    new webpack.optimize.CommonsChunkPlugin({
      name: 'app',
      async: 'vendor-async',
      children: true,
      minChunks: 3//模块被多少个chunk公共引用才被抽取出来成为commons chunk
    })

webpack4的代码分离splitChunks

自从webpack4以来,分离代码用的是optimization.splitChunks
官网SplitChunksPlugin说明

Since webpack v4, the CommonsChunkPlugin was removed in favor of optimization.splitChunks.

这个splitChunks,默认做好相关配置了

> New chunk can be shared OR modules are from the node_modules folder
> 模块被重复引用或者来自node_modules中的模块

> New chunk would be bigger than 30kb (before min+gz) 
> 在压缩前最小为30kb

> Maximum number of parallel requests when loading chunks on demand
> would be lower or equal to 5
> 在并行的按需加载时,请求数量小于等于5

> Maximum number of parallel requests at initial page load would be lower or equal to 3 When trying to fulfill the last two conditions, bigger chunks are preferred.
> 在并行的初始化加载时,请求数量小于等于3

以下是其默认代码配置详情

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',//块的范围,有三个可选值:initial/async动态异步加载/all全部块(推荐),默认为async;
      minSize: 30000,//代码分割的最小值,默认30k;
      maxSize: 0,
      minChunks: 1,//模块被引用次数多少时才会进行代码分割,默认为1;
      maxAsyncRequests: 5,//最大的按需(异步)加载次数,默认为5
      maxInitialRequests: 3,//最大的初始化加载次数,默认为3;
      automaticNameDelimiter: '~',
      automaticNameMaxLength: 30,
      name: true,//拆分出来块的名字(Chunk Names),默认由块名和hash值自动生成;
      cacheGroups: {//缓存组
        vendors: {//key 为entry中定义的 入口名称
          test: /[\\/]node_modules[\\/]/,
          priority: -10//优先级
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true//复用之前的打包模块
        }
      }
    }
  }
};

前置条件:我们在项目中引入一个异步模块,命名为async-module,
本项目中其他已经安装的第三方库有vue,vue-router,均是静态引入

使用默认async配置的打包结果

    async-module1.6bf897eb.js  227 bytes       0  [emitted] [immutable]  async-module1
async-module1.6bf897eb.js.map  133 bytes       0  [emitted] [dev]        async-module1
             main.f754e233.js    130 KiB       1  [emitted] [immutable]  main
         main.f754e233.js.map  127 bytes       1  [emitted] [dev]        main

查看代码分析结果:main.js文件包含node_modules和src,
旁边紫色小块是异步模块async-module1.js
webpack4之代码分割splitChunks和压缩优化_第1张图片

来个小尝试,如果把默认配置中的vendor改为’all’会是怎样的?

    async-module1.6bf897eb.js  227 bytes       0  [emitted] [immutable]  async-module1
async-module1.6bf897eb.js.map  133 bytes       0  [emitted] [dev]        async-module1
             main.339cc1fc.js    7.7 KiB       1  [emitted] [immutable]  main
         main.339cc1fc.js.map  115 bytes       1  [emitted] [dev]        main
     vendors~main.c8120c6a.js    123 KiB       2  [emitted] [immutable]  vendors~main
 vendors~main.c8120c6a.js.map  137 bytes       2  [emitted] [dev]        vendors~main

webpack4之代码分割splitChunks和压缩优化_第2张图片
可以看到,此时webpack会把第三方库node_modules的抽离放在vendors~main.js中,src的放在main.js中,异步的放在async-module1.js中

在指定chunk为all的基础上再追加一个:runtimeChunk:true,把webpack运行时的函数代码抽离出来

.                //.............省略..................
                default: {
                  minChunks: 2,
                  priority: -20,
                  reuseExistingChunk: true//复用之前的打包模块
                }
              }
            },
            runtimeChunk:true
          }

结果如下

                        Asset       Size  Chunks                         Chunk Names
    async-module1.6bf897eb.js  227 bytes       0  [emitted] [immutable]  async-module1
async-module1.6bf897eb.js.map  133 bytes       0  [emitted] [dev]        async-module1
             main.5b2f5ac7.js   5.51 KiB       1  [emitted] [immutable]  main
         main.5b2f5ac7.js.map  115 bytes       1  [emitted] [dev]        main
     runtime~main.4d3db02e.js   2.29 KiB       2  [emitted] [immutable]  runtime~main
 runtime~main.4d3db02e.js.map  131 bytes       2  [emitted] [dev]        runtime~main
     vendors~main.32b19645.js    123 KiB       3  [emitted] [immutable]  vendors~main
 vendors~main.32b19645.js.map  137 bytes       3  [emitted] [dev]        vendors~main

webpack4之代码分割splitChunks和压缩优化_第3张图片
可以看到运行时的代码依赖函数runtime_main.js也被抽离了出来
到这里代码的抽取就结束了

附个性化的配置,根据需要大家自行配置

optimization: {
            // 采用splitChunks提取出entry chunk的chunk Group
            splitChunks: {
              cacheGroups: {
                // 处理入口chunk,同步的
                vendors: {
                  test: /[\\/]node_modules[\\/]/,
                  chunks: 'initial',
                  name: 'vendors',
                },
                // 处理异步chunk
                'async-vendors': {
                 test: /[\\/]node_modules[\\/]/,
                  minChunks: 2,
                  chunks: 'async',
                  name: 'async-vendors'
                }
              }
            },
            // 为每个入口提取出webpack runtime模块
            runtimeChunk: { name: 'manifest' }
          }

代码压缩

当mode为production时,webpack会自动启动压缩

optimization.minimize:true

压缩js
我自己试了下在optimization中配置

minimizer: [
                new TerserPlugin({
                  cache: true,
                  parallel: true,
                  sourceMap: true, // Must be set to true if using source-maps in production
                  terserOptions: {
                    // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
                  }
                }),
                new OptimizeCSSAssetsPlugin()
              ],

发现打包结果不变
既然压缩js好像没啥变化,那就来压缩css代码和html吧

压缩css

const OptimizeCSSAssetsPlugin=require('optimize-css-assets-webpack-plugin')
//......在plugins中添加
new OptimizeCSSAssetsPlugin ()

压缩html

new HtmlWebpackPlugin({
                minify:{
                    removeRedundantAttributes:true, // 删除多余的属性
                    collapseWhitespace:true, // 折叠空白区域
                    removeAttributeQuotes: true, // 移除属性的引号
                    removeComments: true, // 移除注释
                    collapseBooleanAttributes: true // 省略只有 boolean 值的属性值 例如:readonly checked
                },
                favicon:''
            }),
 index.html  361 bytes          [emitted]
  main.css   2.84 KiB
 ---------------之前与之后的对比----------
 index.html  318 bytes          [emitted]
 main.css   1.23 KiB 

其他优化

resolve
配置扩展项、别名方便于我们的开发,而modules库的查看范围,一定范围加快了webpack的查找速度

    resolve: {
        extensions: ['.js', '.vue', '.json'],//告诉解析器在解析路径资源中能够接受哪些扩展名(例如 .js, .jsx)
        modules: [
            path.resolve('src'),
            path.resolve('node_modules') 
      
          ],// resolve.modules 是用来配置模块库(即 node_modules)所在的位置,默认向上搜素,直接指定位置减少搜索时间
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
            '@': path.resolve('src'),
        }
    },

图片
对于小的头像图片,可以考虑转base64码,网上有在线转换工具的
图片懒加载动画条可以提高用户体验
避免大的背景图

exclude,include(优先级较高)
例如我们在配置.vue文件,js的loader,可以指定排除哪个文件夹,提升性能

		{
                test: /\.vue$/,
                loader: 'vue-loader',
                include: [path.resolve('src')],
            },

你可能感兴趣的:(webpack4,splitChunks,webpack)