UmiJs - 拆包优化

前言

我们在写前端代码的时候,难以避免的是,我们可能引入的依赖越来越多。那么随之而来的,我们打包编译后的产物,也会随之越来越大。

默认情况下,使用Umi框架的人都知道,Umi会将前端页面,凡是用到的依赖都给打包到umi.js文件。同样地,CSS相关的则打入umi.css文件中。那当你的项目达到一定规模或者复杂程度上去的时候,尤其是umi.js文件就会很大。因此本篇文章主要分享一下拆包的经验。

一. 如何拆包,怎么拆

拆包之前我们应该去了解自己本身的项目,打出来的js文件结构是怎样的。我们可以在package.json文件中添加命令:

1.1 分析自己项目的编译产物结构

"scripts": {
	"analyze": "cross-env ANALYZE=1 umi build",
}

然后执行如下命令:

npm run anaylze

最后umi会分析你的编译产物,并弹出窗口进行图形化展示,如图:
在这里插入图片描述
可见我们的umi.js文件,即便是压缩后,依旧有4.5M的大小。可见它不一般呐。

1.2 开始拆包

首先,umiJs相关的配置,一般在目录的config/config.ts文件中,官网文档
在这里插入图片描述
我们需要在配置里面添加配置项 chainWebpack

chainWebpack: (config) => {
  config.optimization.splitChunks({
    chunks: 'all',
    minSize: 30000,
    minChunks: 1,
    maxSize: 0,
    automaticNameDelimiter: '.',
    name: true,
    maxAsyncRequests: 30,
    maxInitialRequests: 10,
    cacheGroups: {
      
    }
  });
}

相关配置项的含义:
chunks:用于指定哪些代码块应该被拆分。可以分为如下几种类型:

  • 'all':所有代码块都会被拆分。
  • 'async':只拆分异步代码块。异步代码块是指通过 import() 或类似方式动态加载的代码块。
  • 'initial':只拆分初始代码块。初始代码块是指在入口文件中直接引用的代码块。
  • 函数:可以使用一个函数来自定义哪些代码块应该被拆分。该函数接收一个参数 chunk代表当前的代码块。函数需要返回一个布尔值,表示该代码块是否应该被拆分。这个很有用

其他的配置含义如下:

  • minSize 选项指定了拆分后的代码块最小大小。
  • minChunks 选项指定了一个模块被多少个入口文件引用时才会被拆分。
  • maxSize 选项指定了拆分后的代码块最大大小。
  • automaticNameDelimiter 选项指定了拆分后的文件名的分隔符。
  • name 选项指定了是否根据模块名自动生成文件名。
  • maxAsyncRequests 选项指定了最大异步请求数。
  • maxInitialRequests 选项指定了最大初始请求数。
  • cacheGroups 选项用于配置缓存组。

大家可以照抄上面的配置。接下来看下cacheGroup的写法:

cacheGroups: {
  vendors: {
    name: 'vendors',
    test: /[\\/]node_modules[\\/]/,
    priority: 11
  },
  reactFileViewer: {
    name: 'reactFileViewer',
    test: /(react-file-viewer)/,
    priority: 12
  },
}

我这里呢,将我的umiJs中的相关依赖拆成了两个JS文件 umi.js本身还是会存在的,只不过它里面大部分的内容被“转移”到这俩js文件中) 因为react-file-viewer这个依赖它占用的大小非常非常的大,因此把他抽出来。

我们需要关注的是这么几个东西:

  1. 打包的文件名称:name
  2. 打包的正则匹配:test
  3. 优先级:priority 属性用于设置优先级,数字越大,优先级越高,打包时会优先匹配优先级高的配置。 这个同样很重要!!!

上面的配置含义如下:

  1. 我优先把react-file-viewer这个依赖单独打包成reactFileViewer.js文件。优先级12。
  2. 剩余所有的依赖全部打入到vendors.js文件中。优先级11。因为我的正则写的是[\\/]node_modules[\\/],所以会把所有用到的依赖都打入进去。

那么最后再次执行对应的分析命令 npm run anaylze,结果如下:
在这里插入图片描述

由于我这里是演示,其实umi.js文件还是很大。那么你就需要看它里面到底装了什么东西,把比较大的东西给他拆出来,我总结下几个拆分的规则:

  1. 跟业务无关的,比如antd这种文件,可以单独拆出来。按照依赖的类型进行拆包,比如工具类相关的(lodashmoment等)、React相关的等等。
  2. 特别特别大,但是只有个别页面使用的,可以单独抽出来,对应使用的页面引入对应JS,例如我上面的react-file-viewer
  3. 尽量做到均衡平分,因为页面加载Js是并行多个加载的,所以若你拆包不均衡,一个js大小2M,一个大小100KB,那么最后页面加载的时间还是以最长的2M为准。反之,如果你均分成两个1M大小的文件,那么页面加载JS的时长大概就在1秒。(都是粗略的计算)

二. 有哪些注意点

倘若你跟我一样,前端打包后,采取模板渲染的方式(比如Egg的ejs模板渲染),或者是外部显式引入umi.js等静态资源文件的地方。那么你在拆包之后就需要考虑到资源的加载顺序问题了。

2.1 样式丢失

比如:倘若你把antd相关的资源从umi.js文件中隔离出来,那么你在外部引入资源的时候,就需要考虑到两件事:

  1. antd打出的包你也要引入,例如 < link rel="stylesheet" href='antd.chunk.css' />
  2. 特别重要:考虑到antdumi的文件加载顺序。例如:当你先引入umi.css文件,再引入antd.css文件(而umi.js里面包含了我们的前端页面,里面使用到了antd的组件),那么就会造成完成umi.js文件加载的时刻,找不到对应的antd样式,即样式丢失。

那么我们怎么办,建议:

  1. 由于我们把umi.js文件中大部分的依赖全部抽除去了,最终umi.js文件的大小实际上只有几KB因此为了避免这种由于加载顺序导致的样式依赖丢失,我们可以把antd这类资源保留到umi.js中。

代码编写如下:

vendors: {
  name: 'vendors',
  test: /[\\/]node_modules[\\/](?!antd|@ant-design)/,
  priority: 11
},

在原本的基础上,通过正则表达式,排除了antd相关的依赖,即正则末尾加上:

(?!antd|@ant-design)

那么当umi.js把剩余所有的依赖抽出到vendors文件中的时候,会保留antd相关资源,因此antd相关的资源就会保留到umi.js文件中。那么外部引入的时候,也不会有样式丢失的问题了。

2.2 存在需单独打包的页面

如果你的项目,已经把个别页面单独打包了,而某些情况下,你又不希望它打出来的文件被更改。那么你可以在拆包的过程中,将其排除:

比如,我的项目单独对一个页面打包,打包成了test.js文件:

const ChunksIgnoreList = ['test','test2'];

chainWebpack: (config) => {
  // 单独打包
  config.entry('test').add('./src/pages/test/index.js');
  config.entry('test2').add('./src/pages/test2/index.js');
  // ...省略
  config.optimization.splitChunks({
    chunks: (chunk) => ChunksIgnoreList.filter((item) => item.includes(chunk.name)).length === 0,
    // ...省略
  });
}

我们就可以在splitChunks中的chunks属性,自定义函数(文章上面有提到,是可以写自定义函数的,我们就不要写all了),这里将我们上面单独打包的文件,全部给排除掉了,只有chunk的名称不是上面ChunksIgnoreList 中定义的几个,都允许被拆分打包。对应的拆包结果如下:

在这里插入图片描述

当然,这里需要补充一点:

  1. 如果你单独打包某个页面,又使用了split的拆包方式,那么是不建议前者的打包方式存在的。
  2. 比如antd为例,你单独打包一个页面,antd可能会被打包到test.js文件中。但是antd同样又会被打包到umi.js文件中,就造成了打包内容的重复。
  3. 因此推荐只用split方式打包就可以了。除非你有一些特殊的需求。
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值