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

 

 

完 

 

 

 

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-05 00:32:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-05 00:32:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-05 00:32:02       87 阅读
  4. Python语言-面向对象

    2024-04-05 00:32:02       96 阅读

热门阅读

  1. Linux 设备驱动管理之内核对象(Kernel Object)机制

    2024-04-05 00:32:02       40 阅读
  2. 69. x 的平方根

    2024-04-05 00:32:02       34 阅读
  3. linux小技巧(一)--文件比较

    2024-04-05 00:32:02       49 阅读
  4. OpenStack and Kolla Ansible Release

    2024-04-05 00:32:02       42 阅读
  5. MySQL常见故障与优化

    2024-04-05 00:32:02       41 阅读
  6. IP知识详解

    2024-04-05 00:32:02       39 阅读
  7. Golang基础-10

    2024-04-05 00:32:02       36 阅读
  8. 大模型日报2024-04-03

    2024-04-05 00:32:02       45 阅读