55 npm run serve 和 npm run build 的分包策略

2024-04-01 10:04
文章标签 build npm 分包 策略 run serve

本文主要是介绍55 npm run serve 和 npm run build 的分包策略,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

这里我们来看一下 vue 这边 打包的时候的一些 拆分包的一些策略

我们经常会使用到 npm run build 进行服务的打包

然后 打包出来的情况, 可能如下, 可以看到 chunk-vendors 是进行了包的拆分, 我们这里就是 来看一下 这里 npm run build 的时候的, 一个分包的策略

3349532ecefa4a6d893ffc0f31cbd540.png

 

 

测试配置

在 vue.config.js 中配置 webpack 打包配置如下

对于 node_modules 下面的所有的依赖, 限定分包策略为 最小10kb, 最大10kb

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,configureWebpack: {optimization: {splitChunks: {cacheGroups: {defaultVendors: {test: /[\\/]node_modules[\\/]/,priority: 10,minSize: 10000,maxSize: 10000,},default: {chunks: "all",minSize: 10000,maxSize: 10000,},}}}}
})

 

 

chunk-vendors 分组的分包策略

首先超过 maxSize 的包会被单独拧出来形成一个单独的包, 不管他的大小多大

a23b5de626504cfa906f96b86832ea27.png

 

然后其次就是 具体的分包的处理了

如果当前 js 添加到当前包未超过 maxSize, 继续迭代下一个

如果当前 js 太小了, 则重新放回队列, 继续迭代下一个

接下来就是 这里定义的一个拆包的算法了,  这里不细说, 我们也不关注具体的拆分的细节

循环结束, 拆分包的过程就结束了, 拆分成了 n 个小包

3212200534cb47fbbdc6313621fff005.png

 

 

拆分的过程调试如下

比如这里 vue.runtime.esm.js 包 268kb, 超过了配置的 10kb 的大小, 直接拧出来形成一个单独的 chunk

40bdcc62063e414db567e2ddf7359574.png

 

接下来 32 个 js, 合计 15kb, 形成一个 chunk

a243c842422a47d9b47dddc300f3f31b.png

 

接下来也是 32 个 js 形成一个 chunk

2c43da1ba51f4013bfc201400a9543c1.png

 

接下来是 剩余的 14 个 js 形成一个 chunk

1102e338718c49978dc26751c8a97724.png

 

当前 chunk 的命名方式是获取 第一个元素的名称 和 最后一个元素名称 的最大公共部分

ebc2a08a894045beb42f62563545628d.png

 

然后这里是在 compilation 中新增各个 chunk 的地方

chunk 的的名称后缀是根据 group 的名称进行 hash 生成的

bc4d6555c69e460eaf441e386c1e21b9.png

 

然后 如图, 就是编译结果的 chunk-vendors-7a6313df 文件, 里面包含了 32 个 js 文件, 然后 minify 压缩之后, 只有 6kb

要看各个 chunk-vendors 中包含了那些 js, 只能通过运行时调试查看

然后 chunk-vendors-2afcb3e6 这个显然就是 vue.runtime.esm.js 文件, minifiy 压缩之后, 只有 70kb

5771dd4b111d48d19e5441903ef0f0fa.png

 

示例项目中各个 module 大小, 以及各个 chunk 对应的 module 列表如下 excel

d36631b2318b4592b595c579551f0cff.png

 

 

npm run serve 中的 app.js 中默认情况下的 chunk 的拆分

app.js 的拆分分了很多种情况, 这里 我们先来看下 默认的行为

vue.config.js 配置如下

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,configureWebpack: {optimization: {splitChunks: {cacheGroups: {defaultVendors: {test: /[\\/]node_modules[\\/]/,name(module) {return "defaultVendors"},// chunks: "all",// minChunks: 3,priority: 10,// minSize: 10000,maxSize: 10000,},// default: {//   chunks: "all",//   name(module) {//     return "app11"//   },//   // filename: "app112"//   // priority: -10,//   // minSize: 10000,//   maxSize: 10000,// },}}}}
})

 

增加路由配置文件如下, 如下配置了三个路由

import Vue from "vue";
import Router from "vue-router";Vue.use(Router)export default new Router({routes: [{path: '/',name: 'HelloWorld',component: () => import('../components/snake/Game.vue')}, {path: '/HelloWorld',name: 'HelloWorld',component: () => import('../components/HelloWorld')}, {path: '/AsyncQueue',name: 'AsyncQueue',component: () => import('../components/AsyncQueue.vue')}]
})

 

编译之后的生成的 js 相关的目录结构如下, 我们这里关注 app.js 相关的

即 app.js 和 src_components_xxx 相关的三个文件, 其他的为 node_modules 编译之后生成的项目文件

4354757e42ec44fa8f0d1b07448cfb98.png

 

然后我们看一下 app.js 中 chunk 的拆分

在 visit “src\router\index.js” 的时候, 发现了三个 import(), 然后 采集为 blocks

然后 这里单独拆分出来, 成为单独的 chunk

97ae45fa2f5e444590b9c97e500dcd76.png

 

该 chunk 里面没有保存上下文的任何信息, 上下文的信息是保存在 chunkGroup 中的, 后面对 chunk 和 chunkGroup 进行了关联

9dcb45254f854e2586af081b5be702cc.png

 

为目标 chunk 生成 chunkName 的地方是在 NamedChunkIdsPlugin.js 中, 从 chunkGroup 中相关数据中可以拿到目标 chunk 是属于哪一个文件的

9ace82f536f84b46a7409e4a1a6c8e27.png

39899cf0c0244645b4025ce6a9fd6b90.png

 

 

npm run build 中的 app.js 中默认情况下的 chunk 的拆分

整体的流程 和 上面 npm run serve 中的 app.js 的拆分情况如下

计算 chunk 的 id, 名称如下

1b6ce0e3bbd34d7e93292ca2bbe87baf.png

 

使用 numberHash 进行计算, 如果重复了, 就重新计算

e18bd9a7d81e4ea3aeec2ab947e89e89.png

 

整体来说, chunk 名称和其内容没有什么较为明显的关联

因此, 只能通过 文件内容, 来定位具体的业务组件是在哪一个文件中了

fc4ec0a359f548928430c20208a05463.png

 

但是可以通过 app.js 来进行一个粗略的查找, entryPoint 编号为 3208

37ca0b67675f4f2d988f6b18242fd5e0.png

 

这里便是整个路由, 这两批可以看到 具体的路由信息, 以及组件信息, 比如 “/HelloWorld” 对应于组件 575

c41c0fd77cf34c92a157dda74475df8f.png

 

 

app.js 的手动拆包配置

和上面 chunk-vendors 的拆包的配置类似, app.js 相关, 也是可以手动配置 拆包

配置 vue.config.js 的配置如下, 其中 default 下面的配置对应的是 app.js 的配置

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,configureWebpack: {optimization: {splitChunks: {cacheGroups: {defaultVendors: {test: /[\\/]node_modules[\\/]/,name(module) {return "defaultVendors"},// chunks: "all",// minChunks: 3,priority: 10,// minSize: 10000,maxSize: 10000,},default: {chunks: "all",name(module) {return "app11"},// filename: "app112"// priority: -10,// minSize: 10000,maxSize: 10000,},}}}}
})

 

打包之后结果如下, 可以看到的是 拆分的和 chunk-vendors 的拆分貌似类似

26be90b0b55b4376a8188d9ae0905b2a.png

 

假设是手动配置了分包的相关配置, 这里 具体的拆分就是和 chunk-vendors 类似的分包拆分处理

在 SplitChunksPlugin 中进行的处理, 这里可以参见上面的 chunk-vendors 的分包策略处理

a93951de34704af8a541aa8144f62f51.png

 

 

app.js 的默认分包 和 手动配置的分包 的差异

这个是从另外的一个维度 来进行的分析

在默认的分包处理下, 可以看到 我们这里访问 HelloWorld, 仅仅是请求了 HelloWorld 的相关的组件

412698767fc6463fbd50775a357c8031.png

 

编译出来的 index.html 如下, 可以看到的是 仅仅是导入了 app.js 这个入口的 chunk

9c2252773e8e44a2bf34d632f0236f1e.png

 

对于路由下面的各个情况, 是导入的各自的 js

703a73f5d6ca4e60a5ab9091a5ec2921.png

 

js 的映射如下

cc34a94329fa42008290e8f9b58305cb.png

 

在手动分包的处理下, 可以看到 请求了 app.js 囊括的所有的 js

74b2048748f84887b0c9b958635e336b.png

 

编译出来 index.html 如下, 可以看到是 引入了所有的包, 不管是进入哪一个页面, 都是请求的全量的 app.js 和 chunk-vendors.js

5c7c068758464f4ca42fecece3f4978c.png

 

 

app.js 的默认分包的每一个组件包含了那些东西?

HelloWorld.vue 文件内容如下

5733b7e8058041489d10759fcb80bd03.png

 

AsyncQueue.vue 文件内容如下, 导入了一个 HelloWorld.vue 的组件

498e6c5b7f6a419b885620fe0f88f6b4.png

 

然后编译完之后的 import('../components/HelloWorld') 如下

a7cb1ed96fa54d878372f710da3b4f64.png

 

然后编译完之后的 import('../components/AsyncQueue) 如下

可以看到 编译之后的结果 是将使用到的组件都内联进来了, 这样可能导致一些公用组件的内容被内联很多次, app.js 总共的包大小 膨胀

但是 页面时按照需要导入的对应的 js

增加了一些 编译器编译的开销, 服务器存储的开销, 减小了客户端请求的开销

42416971f1b44f3fa5f15c8bf93ffe18.png

 

 

完 

 

 

 

这篇关于55 npm run serve 和 npm run build 的分包策略的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/866867

相关文章

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

SpringBoot中的404错误:原因、影响及解决策略

《SpringBoot中的404错误:原因、影响及解决策略》本文详细介绍了SpringBoot中404错误的出现原因、影响以及处理策略,404错误常见于URL路径错误、控制器配置问题、静态资源配置错误... 目录Spring Boot中的404错误:原因、影响及处理策略404错误的出现原因1. URL路径错

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略

python subprocess.run中的具体使用

《pythonsubprocess.run中的具体使用》subprocess.run是Python3.5及以上版本中用于运行子进程的函数,它提供了更简单和更强大的方式来创建和管理子进程,本文就来详细... 目录一、详解1.1、基本用法1.2、参数详解1.3、返回值1.4、示例1.5、总结二、subproce

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

缓存策略使用总结

缓存是提高系统性能的最简单方法之一。相对而言,数据库(or NoSQL数据库)的速度比较慢,而速度却又是致胜的关键。 如果使用得当,缓存可以减少相应时间、减少数据库负载以及节省成本。本文罗列了几种缓存策略,选择正确的一种会有很大的不同。缓存策略取决于数据和数据访问模式。换句话说,数据是如何写和读的。例如: 系统是写多读少的吗?(例如基于时间的日志)数据是否是只写入一次并被读取多次?(例如用户配