chainWebpack之optimization.splitChunks的cacheGroups缓存组代码分块实践案

news2024/11/16 22:01:36

研究了好几天webpack打包,我们项目是vue的高版本,已经没有了webpack.config.js文件了,是直接在vue.config.js里的chainWebpack方法直接配置,这样做法的好处是用户既可以保留webpack的默认配置,又可以通过chainWebpack设置更具针对性的参数,链式的写法正是避免了用户直接面对webpack多而复杂的配置项,想要更专业的配置再去学习webpack更深层的知识,大大降低了webpack使用难度和大多数小项目群体学习成本,一般项目只需要使用默认的配置即可满足要求,项目比较大的时候就需要深入的学习了,下面我们来说说webpack里的分块方法optimization.splitChunks以及缓存组cacheGroups的配置方法;

当我们npm run build进行打包的时候,事实上是根据cacheGroups的默认配置进来分包并包的:

splitChunks: {
    chunks: "all",
    minSize: 30000,//默认值,超过30K才独立分包
    cacheGroups: {
        vendors: {
            test: /[\/]node_modules[\/]/,  // 匹配node_modules目录下的文件
            priority: -10   // 打包优先级权重值
        },
        default: {
            minChunks: 2,
            priority: -20,   // 打包优先级权重值
            reuseExistingChunk: true//遇到重复包直接引用,不重新打包
        }
    }
}

默认配置会将 node_mudules下的模块打包进一个叫 vendors的bundle中,所有引用超过两次(minChunks:2)的模块分配到 default的bundle中,这就是我们打包完常见的xxx.bundle.js类;

但是如果node_mudules都打进一个包,通常vendor.bundle.js会很大,因此不得不抽离一部分依赖成单独块,先看一下常见的简单配置:
vue.config.js:

module.exports = {
    chainWebpack( config ) {
        //process.env.NODE_ENV的值要在.env.development和.env.production文件分别配置,不想判断的直接删除when方法这一行
        config.when( process.env.NODE_ENV==="production",  ( config )=>{
            config.optimization.splitChunks({
                chunks:"all",//initial同步,async异步,all同步或者异步
                automaticNameDelimiter:"-",//打包文件名默认连接符号
                cacheGroups: {
                    elementUI: {
                        name: "chunk-elementUI",
                        priority: 30,
                        test: /[\/]node_modules[\/]_?element-ui(.*)/,
                    },
                    nodesInitial: {
                        name:"chunk-nodesInitial",
                        test: /[\/]node_modules[\/]/,
                        priority: 10,
                        minChunks: 1,
                        chunks: "initial",//仅打包同步引用的依赖
                        reuseExistingChunk: true
                    },
                    nodesAsync: {
                        name:"chunk-nodesAsync",
                        test: /[\/]node_modules[\/]/,
                        priority: 9,
                        minChunks: 1,
                        chunks: "async",//仅打包异步引用的依赖
                        reuseExistingChunk: true
                    },
                    components: {
                        name: "chunk-components",
                        test: resolve('src/components'),
                        minChunks: 2,
                        priority: 5,
                        reuseExistingChunk: true
                    }
                }
            })
            config.optimization.runtimeChunk("single")
        })
    }
}

可以见到上面的配置已经将node_modules里的elementUI与公共组件components抽离成独立块,同步和异步引用的依赖分开打包,运行打包之后感觉还不错,这里要注意的是minSize的值,缓存组里独立打包的块如果小于30k,是不会打包的,所以可以针对文件的大小设置打包最小值minSize,使其成为独立块打包出来,下图是小编项目打包后webpack-bundle-analyzer插件分析出来的结果:在这里插入图片描述
因为本项目文件确实比较多比较大,所以可以看到好几个超过1M的大文件,原来默认的时候app.a900c452.js是2M多的,按上面的设置了以后,大于1M的只剩3个,已经是不小的进步,但是明显还可以再抽离一部分,于是在再对webpack-bundle-analyzer插件图分析,看哪些还可以分割出来的,同步异步那两个文件再做分割:

vue.config.js:

module.exports = {
    chainWebpack( config ) {
        //process.env.NODE_ENV的值要在.env.development和.env.production文件分别配置,不想判断的直接删除when方法这一行
        config.when( process.env.NODE_ENV==="production",  ( config )=>{
            config.optimization.splitChunks({
                chunks:"all",//initial同步,async异步,all同步或者异步
                automaticNameDelimiter:"-",
                cacheGroups: {
                    elementUI: {
                        name: "chunk-elementUI",
                        priority: 40,
                        test: /[\/]node_modules[\/]_?element-ui(.*)/,
                        minSize:0
                    },
                    formMaking: {
                        name:"chunk-formMaking",
                        test: resolve('lib/vue-form-making/dist'),
                        priority: 39,
                        minSize:0,
                        enforce:true
                    },
                    antDesignVue: {
                        name:"chunk-antDesignVue",
                        test: /[\/]node_modules[\/]_?ant-design-vue(.*)/,
                        priority: 39,
                        minSize:0,
                        enforce:true
                    },
                    antDesign: {
                        name:"chunk-antDesign",
                        test: /[\/]node_modules[\/]_?@ant-design(.*)/,
                        priority: 39,
                        minSize:0,
                        enforce:true
                    },
                    moment: {
                        name: "chunk-moment",
                        priority: 39,
                        test: /[\/]node_modules[\/]_?moment(.*)/,
                        minSize:0,
                        enforce:true
                    },
                    jeecg: {
                        name:"chunk-jeecg",
                        test: /[\/]node_modules[\/]_?@jeecg(.*)/,
                        priority: 39,
                        minSize:0,
                        enforce:true
                    },
                    quill: {
                        name:"chunk-quill",
                        test: /[\/]node_modules[\/]_?quill(.*)/,
                        priority: 39,
                        minSize:0,
                        chunks: "async",//仅打包异步引用的依赖
                    },
                    nodesAsync: {
                        name:"chunk-nodesAsync",
                        test: /[\/]node_modules[\/]/,
                        priority: 10,
                        minChunks: 2,
                        chunks: "async",//仅打包异步引用的依赖
                        reuseExistingChunk:true
                    },
                    nodesInitial: {
                        name:"chunk-nodesInitial",
                        test: /[\/]node_modules[\/]/,
                        priority: 9,
                        minChunks: 1,
                        chunks: "initial",//仅打包同步引用的依赖
                        reuseExistingChunk:true
                    },
                    components: {
                        name: "chunk-components",
                        test: resolve('src/components'),
                        minChunks: 2,
                        priority: 5,
                        reuseExistingChunk: true
                    }
                }
            })
            config.optimization.runtimeChunk("single")
            config.plugin('webpack-bundle-analyzer').use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
        })
    }
}

打包后的结果图如下:在这里插入图片描述
可以明显看到这次的分块里nodesInitial已经不见了,因为已经被分成其他的小块,但为什么这次的包总大小比上次的大300K左右呢,其实是因为抽离出来之后有部分依赖在其他模块还有引用,无法完全分割只能重复打包,这个可以根据打包情况调整代码的引用方式;

分包过程中可能发现大文件会转移,比如一开始可能是chunk-nodesInitial.js很大,增加缓存组来分割以后,发现nodesInitial文件不见了,这时候反而app.xxxxx.js变得很大,这个问题我还没想明白,只看哪个文件大,对它分包就行;

缓存组分包过程中如果发现分不出来,可以加上enforce: true参数,有点强行拽出来的意思,小编在分块过程中也发现这个情况,比如增加缓存组antDesignVue后,打包是可以独立分离出来的,但是如果再加一个缓存组moment或jeecg,会发现,可能jeecg分出来了,但是ant-design-vue又被拽回去原来的包了,要不就是jeecg分不出来,这时候只要加了enforce: true参数,就能分出来,试过不是权重优先级priority的问题,还要多研究研究,过程中基本是看结果图,看哪个文件大,就分一个缓存组;

本次案例分块的主要逻辑是,先分同步和异步两大块,再从这两大块里找最大的继续分割,同步分出来的就都使用chunks:”initial”,异步分出来的就都是chunks:”async”,一直往下分……

那分到什么程度为止呢,小编的结论是,如果继续分下去,总包变大,那基本就可以停止了,因为总包变大意味着有依赖重复打包了,就不要尝试抽离这个包,换一个包继续尝试,如果大文件里每一个包都分不出来,那就不继续分了,到这个程度基本上分包已到了相对合理的地步,但如果分到总包变大还有大文件,可以尝试换个角度分块,一开始分的两个大包大小最好接近二等分,说明两个包之间的代码耦合度比较低,越低越利于分割,多试试;

本次的分块成果:由原来的192个文件,减少到182个文件,最大文件值由6M缩小到所有文件不超过2M,因为有些单个文件本来就是1M多的,比如formMaking,已经没法再分了,所以暂时优化至此,后续深入了解再做调整;

还有个要提醒的问题,就是使用enforce: true参数后,不知会不会引发使用该组件的页面空白,大家可以自己验证下;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/381246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java开发】JUC基础 05:线程通信/协作

1 生产者消费者问题📌 线程通信应用的场景可以简单地描述为生产者和消费者问题假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费;如果仓库中没有产品,则生产者将产品放入仓库&a…

Java知识复习(八)Spring基础

1、什么是Spring框架? Spring :是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性 2、Spring、SpringMVC和SpringBoot的区别 Spring主要指Spring Framework,就是指如上图所示的各项功能模块Spr…

【Java 多线程学习】

多线程学习多线程1. 并行与并发2.进程和线程3. *****多线程的实现方式3.1 继承Thread类的方式进行实现3.2 实现Runnable接口方式进行实现3.3 利用Callable和Future接口方式实现3.4 设置获取线程名字4.获得线程对象5.线程休眠6.线程调度[线程的优先级]7.后台线程/守护线程多线程…

Pytest自动化框架-权威教程02-Pytest 使用及调用方法

Pytest 使用及调用方法使用python -m pytest调用pytest2.0版本新增你可以在命令行中通过Python编译器来调用Pytest执行测试:Copypython -m pytest [...]通过python调用会将当前目录也添加到sys.path中,除此之外,这几乎等同于命令行直接调用pytest [...]。可能出现的执行退出cod…

【K8S笔记】Kubernetes 集群架构与组件介绍

K8S 官方文档 https://kubernetes.io/zh/docs/home ##注重关注 概念和任务 板块。 K8S 集群架构 K8S也是运用了分布式集群架构: 管理节点/Master 整个集群的管理,任务协作。工作节点/Node 容器运行、删除。 K8S 组件介绍 管理节点/Master 相关组件 …

JDK1.8 ConcurrentHashMap

数据结构锁sizeCtlconcurrencyLevelForwardingNode、ReservationNode扩容get、put、removehashmap:线程不安全 hashtable:通过synchronized保证线程安全但效率低。强一致性 ConcurrentHashMap:弱一致性 数据结构 ConcurrentHashMap为node数…

前端转golang从小白到实战自学笔记(2023/3/1)

了解:https://www.runoob.com/go/go-concurrent.htmlgolang学习方向区块链研发工程师go服务器>(特点:数据处理,处理大并发)/游戏软件工程师golang分布式/云计算软件工程师(盛大云、cdn、京东&#xff09…

Mybatis主要流程源码分析

分层架构图 主要流程图 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d9uhH9IK-1677658947721)(https://note.youdao.com/yws/public/resource/7f152b4b25320263d411a49583d3f4db/xmlnote/WEBRESOURCE9ea90840088eaeaa4a463bbc3f1912e8/17619)] 主…

索引优化与查询优化

1.哪些维度可以进行数据库调优 索引失效、没有充分利用到索引–》索引建立关联查询太多JOIN (设计缺陷或不得已的需求)–》SQL优化服务器调优及各个参数设置(缓冲、线程数等)–》调整my.cnf数据过多–》分库分表 大方向上完全可以分成 物理查询优化和 逻辑查询优化 两大块 物…

记录一次挖矿病毒kthreaddk和rcu_bj,导致CPU飙高处理

htop命令 存在kthreaddk和rcu_bj进程,cpu飙高 占用一般cpu或者70-80% 1、检查定时任务 查看是否有 # crontab -l 检查root账号是否有异常定时任务 有的话crontab -e 修改定时任务保存 并检查所有的用户有没有定时任务( 注:我的是gitlab git账户被入侵)异…

Nginx 配置详解(二)

序言Nginx的代理功能与负载均衡功能是最常被用到的,描述一些关于代理功能的配置,再说明负载均衡详细。Nginx 代理服务的配置说明1、设置 404 页面导向地址error_page 404 https://www.runnob.com; #错误页 proxy_intercept_errors on; #如果被代理服务…

PowerShell Install Mysql 5.7

MySQL介绍 MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。 mysql download Mysql ServerdownloadPowershell 使用使用参数参考 前提条件 开启…

机器学习算法-KNN、决策树

目录1、最近邻算法 KNN1.1 K的选择1.2 案例:鸢尾花2、决策树2.1 决策树介绍2.2 案例:鸢尾花数据2.3 补充1、最近邻算法 KNN 原理:找到K 个与新数据最近的样本,取样本中最多的一个类别作为新数据的类别 要点:距离—是欧…

Three.js上手——搭建Vue3+Three.js项目

上一篇文章 Three.js初试 介绍了一些 Three.js 的基本概念,这一篇主要是介绍一下它的应用。 结合 Vue3 Vite 一起搭建一个项目。 项目初始化 Vite 项目构建 兼容性注意 Vite 需要 Node.js 版本 14.18,16。然而,有些模板需要依赖更高的 Nod…

代码随想录【Day29】|491. 递增子序列、46. 全排列、47. 全排列 II

491. 递增子序列 题目链接 题目描述: 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。 示例: 输入: [4, 6, 7, 7]输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] 说明: …

教务选课排课系统

技术:Java、JSP等摘要:Internet网是目前全球最大的计算机通信网,它遍及全球几乎所有的国家和地区。www系统是一个大型的分布式超媒体信息数据库,它极大的推动了Internet的发展,己经成为Internet中最流行、最主要的信息…

防抖节流函数

防抖和节流对于每一个开发者来说,都不陌生。防抖和节流的概念其实最早并不是出现在软件工程中,防抖是出现在电子元件中,节流出现在流体流动中。 而JavaScript是事件驱动的,大量的操作会触发事件,加入到事件队列中处理…

骨传导耳机发声原理是什么,如何选购骨传导耳机

骨传导耳机很早以前就已经有了,但真正流行到运动圈里也还是最近两年的时间,所以导致很多人对骨传导耳机还不是很了解,不明白其工作原理是什么,在购买骨传导耳机时也总是会感到纠结,不知如何下手,作为一个多…

香港双重牌照、准入安排和禁止事项等重要制度已明确 20多万字的《虚拟资产咨询文件》以证雄心

前不久,香港证监会就加密货币交易发布的《有关适用于获证券及期货事务监察委员会发牌的虚拟资产交易平台营运者的建议监管规定的咨询文件》(以下简称《咨询文件》),并如期就有关监管虚拟资产交易平台的建议展开咨询,以…

制造业数据质量提升的方法和实践

制造业的数据治理尚处于早期阶段,而数据质量管理是所有数据类项目重点关注的领域。数据治理以数据标准、数据质量和元数据的管理为根本,是企业实现数据资产价值创造的基础。上周,在由武汉市经济和信息化局主办的“万企育才工程”之《制造业数…