webpack4.x 系列(一) ☞SplitChunksPlugin 代码分割

一、SplitChunksPlugin的概念

最初,Chunks块(以及在其中导入的模块)是通过内部webpack图中的父子关系连接的。CommonsChunkPlugin被用来避免它们之间的重复依赖关系,但是进一步的优化是不可能的,所以,CommonsChunkPlugin被移除,转而继续优化,所以在webpack4引出了 SplitChunksPlugin,使之可以很好地为大多数用户服务。

在默认情况下,SplitChunksPlugin 仅仅影响按需加载的代码块,因为更改初始块会影响HTML文件应包含的脚本标记以运行项目。

webpack将根据以下条件自动拆分代码块(这个只是默认条件,配置可以自己更改):

  • 可以被共享的代码块或者node_mudules文件夹中的代码块。
  • 体积大于30KB的代码块(在gz压缩前)。
  • 当按需加载块时,并行请求(maxAsyncRequests)的最大数量将小于或等于6。
  • 初始页面加载(maxInitialRequests)时并行请求的最大数量将小于或等于4。

二. SplitChunksPlugin的默认配置

下面就是默认配置(看高亮部分就是默认配置)

optimization: {
  // 配置代码分割
  splitChunks: {
    // all代表异步,同步代码都做分割,如果式async只对异步代码做分割
    chunks: 'async',
    // 大于30kb才做代码分割
    minSize: 30000,
    // 假设maxSize:50,加入被分割代码有1m,成功打包完还会做二次分割,分割成20个50kb的文件
    maxSize: 0,
    // 如果文件被引入次数大于等于1次才会做代码分割
    minChunks: 1,
    // 同时加载的模块数为6个,如代码分割成10个库,加载时候只能加载6个
    maxAsyncRequests: 6,
    // 入口文件引入外库,然后做代码分割,最多支持4个
    maxInitialRequests: 4,
    // 组和文件的连接符号
    automaticNameDelimiter: '~',
    // 最大的字节数
    automaticNameMaxLength: 30,
    // name: true,
    // 如要打包lodash和jq两个库,符合下面条件先缓存着,当所有的模块都分析好了后,
    // 把符合defaultVendors组的打包到一起去,把符合default组的模块打包到一起去
    cacheGroups: {
      // 同步代码分割的默认配置,同时把一些库文件放到这里去
      defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        // 优先级,比如我们打包jq时候可以打包到defaultVendors,也可以打包到default,那有了priority
        // 之后,我们webpack就可以判断打包到哪个文件下,这个值越大,优先打包到这个文件中,像这里是-10>-20的。
        priority: -10,
        // filename: 'js/[name]/bundle.js'
      },
      // 如果被代码分割的模块不在module里面,然后就会做默认的打包分割
      default: {
        minChunks: 2,
        priority: -20,
        // 如果一个模块已经被打包过了,直接忽略这个模块,直接使用之前打包过的模块就可以了
        reuseExistingChunk: true
      }
    }
  }

接下来就带你对上面代码做进一步的理解:

三、配置的近一步讲解

splitChunks.chunks

有效值是all、async和initial。配置all时,你可以打包同步代码和异步代码,而async时,你只能打包异步代码。

同步代码:

// 同步代码
import _ from 'lodash'

var element = document.createElement('div');
element.innerHTML = _.join(['hansen', 'jin'], '_');
document.body.appendChild(element);

异步代码:异步代码要在模块前面加上/* webpackChunkName:"lodash"*/才可以给包的命名。

// 异步代码
function getComponent(){
  // 给lodash单独加上名字
  return import(/* webpackChunkName:"lodash"*/ 'lodash').then(({ default: _})=>{
    var element = document.createElement('div');
    element.innerHTML = _.join(['hansen', 'jin'], '_');
    return element
  })
}

getComponent().then(element => {
  document.body.appendChild(element)
})

后面测试用例也是根据这两个代码进行的。

splitChunks.minSize

 生成块的最小字节数,比如minSize:30000,那么30000(字节B) ÷ 1024 = 29.29kb,所以如果大于29.29kb的才做打包,如果小于则不打包,他会将多个打包文件合并在一起。如我引入了jq和lodash库,

打包后是2.13M,这种方法是推荐的,因为这样子只要请求一次就可以了。

splitChunks.maxSize

 使用maxSize告诉webpack尝试将大于maxSize字节的块分割成更小的部分。该算法是确定性的,对模块的更改只会产生局部影响。就是说,你用到这个模块他才会打包。它也增加了请求数,以便更好地进行缓存。它还可以用来减小文件大小,以便更快地重建。比如:maxSize:20000,也就是20KB,加入被分割代码有1M,成功打包完还会做二次分割,分割成20个50kb的文件,不过我想,假设是一个jq文件,打包成小文件也不可能。不过一般默认配置为0。

splitChunks.minChunks

 假设这个值是1,那么文件被引入次数大于等于1次才会做代码分割。

splitChunks.maxAsyncRequests

 按需加载时的最大并行请求数。比如同时加载的模块数为6个,如代码分割成10个库,加载时候只能加载6个。

splitChunks.maxInitialRequests

一个入口点的最大并行请求数。

splitChunks.automaticNameDelimiter 连接符

如:看那个笑脸😄

automaticNameDelimiter: '😄',

则:

splitChunks.cacheGroups 缓存组

缓存组因该是SplitChunksPlugin中最有趣的功能了。在默认设置中,会将 node_mudules 文件夹中的模块打包进一个叫 vendors的bundle中,所有引用超过两次的模块分配到 default bundle 中。更可以通过 priority 来设置优先级。

在这个配置项里面一共有2个配置项:defaultVendors和default。然后把符合defaultVendors组的打包到一起去,把符合default组的模块打包到一起去。

我们来看看代码:

      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          // 优先级,比如我们打包jq时候可以打包到defaultVendors,也可以打包到default,那有了priority
          // 之后,我们webpack就可以判断打包到哪个文件下,这个值越大,优先打包到这个文件中,像这里是-10>-20的。
          priority: -10,
          // 包被引用1次就单独拆分出来
          minChunks: 1,
          // 第三方模块打包之后的文件名称
          filename: 'bundle.js'
        },
        // 如果被代码分割的模块不在module里面,然后就会做默认的打包分割
        default: {
          // 包被引用2次被单独拆分出来
          minChunks: 2,
          // 优先级
          priority: -20,
          // 公共模块打包出来的文件
          filename: 'common.js'
          // 如果一个模块已经被打包过了,直接忽略这个模块,直接使用之前打包过的模块就可以了
          reuseExistingChunk: true
        }
      }

知识点1:

defaultVendors:只把在node_modules的文件打包到bundle.js下面,比如jq,lodash。

default: 把自己写的模块文件导入到default文件里面,并根据默认配置项配置。

知识点2:

priority:  比如一个jq模块,它可以打包以defaultVendor的形式打包,也可以用default的形式打包,但是如果我们设置了优先级,那就不一样了,优先级越高,则优先被走该条配置路线。如上面:defaultVendor的priority为-10,而default的priority为-20,那么-10的优先级级高,所以会走defaultVendor的配置。数字越大的,优先级越高。-10 > -20

知识点3:

reuseExistingChunk:如果当前块包含已经从主包中分离出来的模块,那么它将被重用,而不是生成一个新的块。这可能会影响块的结果文件名。

例子1:

// index.js

import('./a'); // dynamic import
// a.js
import 'react';

//...

将创建包含react的单独块。在导入调用中,此块a.js所包含。

原因:(4个条件)

  • react来自 node_modules 文件夹
  • react 体积超过30KB
  • 导入调用时的并行请求数为2
  • 不影响页面初始加载

react可能不会像应用程序代码那样频繁地更改。通过将它移动到一个单独的块中,这个块可以与应用程序代码分开缓存

例子2:

// entry.js

// dynamic imports
import('./a');
import('./b');
// a.js
import './helpers'; // helpers is 40kb in size

//...
// b.js
import './helpers';
import './more-helpers'; // more-helpers is also 40kb in size

//...

将创建一个单独的块a.js,其中包含./helpers及其所有依赖项。在导入调用时,此块与原始块并行加载。

原因:(4个条件)

  • helpers 是共享块
  • helpers大于30kb
  • 导入调用的并行请求数为2
  • 不影响初始页面加载时的请求

将helpers的内容放入每个块将导致其代码被下载两次。通过使用单独的块,这种情况只会发生一次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值