Skip to content

@minisheep/vite-plugin-mp-chunk-splitter

插件功能

用于改变 uni-app 默认将 node_modules 下所有包都输出至 common/vendor.js 的行为。 提供以下功能:

  • 自动根据分包使用的 node_modules 模块输出到对应分包的产物目录下。
  • 可根据大小拆分各个分包的 chunk

安装

shell
pnpm i @minisheep/vite-plugin-mp-chunk-splitter -D
shell
npm i @minisheep/vite-plugin-mp-chunk-splitter -D
shell
yarn add @minisheep/vite-plugin-mp-chunk-splitter -D

使用

在你的 vite 配置文件中添加以下插件:

js
import { createMpChunkSplitterPlugin } from '@minisheep/vite-plugin-mp-chunk-splitter';

export default {
  plugins: [
    createMpChunkSplitterPlugin({
      subpackages: [
        // 和你的分包配置一样
        'package-a',
        'package-b',
        'package-c'
      ],
    }),
  ]
}

这会自动根据分包的 node_modules 使用情况输出至对应产物目录。

如果一个包中使用的依赖超出了限定的大小(默认2M), 会自动拆分成符合要求的子包。详见这里

详细配置

ts
export interface MpChunkSplitterOptions {
  /**
   * 公共 chunks 的路径
   * @defualt `common/chunks`
   * */
  common?: string;
  /**
   * 分包名称列表
   * */
  subpackages?: string[];
  /**
   * 存放分包使用到的 chunk 路径, 位置相对于产物的分包目录
   * @defualt `chunks`
   * */
  subpackageChunkPath?: string;
  /**
   * 当一个分包包含的 chunk 超过多少字节时会分割到其他目录中, 主包不会受到这个限制
   * 设置 0 以禁用分割
   * @defualt 1.8 * 1024 * 1024
   * */
  packageSizeLimit?: number;
  /**
   * 指定分割目录的命名规则
   * @defualt `[package]-dep-[index]` */
  splitName?:
    | string
    | ((subpackage: string, /** 从 1 开始*/ index: number, total: number) => string);

  /**
   * 类似于 uni-app 的默认行为, 开启将依赖打包到单一 chunk 之中, 在依赖碎片文件过多时会显著减小包大小占用
   * 由于分包依赖分析需要完整的一轮构建过程,所以开启这个功能会使构建时间变成两倍。
   * 会强制关闭 rollup 的 watch 选项
   * */
  singleChunkMode?: boolean;
}

高级用法

输出到单一的 chunk

相关概念见 rollup

uni-appnode_modules 下所有包都输出至 common/vendor.js 的行为不同是,这个插件会将每个使用到的模块单独输出成独立的 chunk, 以便于在最终生成 bundle 阶段根据大小对依赖位置进行调整。

所以默认情况构建的产物结构会是下面的样子:

text
dist/
├── common/
│   ├── chunks/   
│   │   ├── module-a.js
│   │   └── module-b.js
│   │   └── ...
│   └── ....
├── package-a/
│   ├── chunks/ 
│   │   ├── module-c.js
│   │   └── module-d.js
│   │   └── ...
│   └── ....
├── app.js
├── app.json
├── app.wxss
└── project.config.json

这种结构便于调试,但依赖路径较长、文件数量多,在依赖较多时会造成包大小增长。

开启 singleChunkMode 可将分包的依赖输出到单个 chunk 以减小空间占用和加载性能,产物结构会变成:

text
dist/
├── common/
│   ├── chunks/vendor.js   
│   └── ....
├── package-a/
│   ├── chunks/vendor.js   
│   └── ....
├── app.js
├── app.json
├── app.wxss
└── project.config.json

⚠️注意

这需要触发一次额外的构建,所以构建时间会变成原有的两倍,并且在 watch 模式下不可用。

指定分割后的分包路径

当一个分包的依赖超出限定的最大大小时,默认会按照 [package]-dep-[index] 的命名规格拆分成若干个分包,直到所有的分包依赖大小都在限定的范围内。

假如 package-a 的总依赖大小为 3800KB, 分包大小限制在 1800KB 时,最终会产生两个 1800KB 的额外分包 package-a-dep-1package-a-dep-2 和一个你配置的分包 package-a (200KB)。

你可以将选项中的 splitName 设置成函数来自定义这个名字:

ts
{
  plugins: [
    createMpChunkSplitterPlugin({
      subpackages: [
        //...
        'package-a' // 假它的依赖总大小为 3800KB
      ],
      splitName(name, index, total) {
        if (name === 'package-a') {
          return [
            `package-three`, // 原有的 package-a-dep-1 会变成  package-three
            `package-three-addons`, // 原有的 package-a-dep-2 会变成  package-three-addons
          ][index - 1]; // index 从 1 开始
        } else {
          return `${name}-dep-${index}`;
        }
      }
    }),
  ]
}

⚠️注意

在真机中,你需要有页面在被分割出来的包 package-threepackage-three-addons 内,并被加载过一次,你才能正常使用 package-a 包中的功能。详见这里

调试

如果你想了解生成的详细情况,你可以在编译时设置环境变量 DEBUG=minisheep:mp-chunk-splitter 以启用调试模式。

例如:

shell
cross-env DEBUG=minisheep:mp-chunk-splitter npm run dev

常见问题

1. 分包后开发者工具仍提示超出包大小限制?

如果你在开发者工具中开启了 ES6 转 ES5 的选项,编译后的代码包体积可能会增大。你可以尝试以下方法优化:

  • 减少分包中非依赖文件的数量;
  • 下调 packageSizeLimit 配置;
  • 关闭 ES6 转 ES5 转换选项。

2. 如何正确加载被拆分的依赖包?

假设你的分包 package-a 被拆分为了 package-a-dep-1package-a-dep-2package-a 三个包,那么你需要确保在进入 package-a 之前,package-a-dep-1package-a-dep-2 已经被加载。

由于小程序目前仅支持通过访问页面的方式加载分包,你可以在 package-a-dep-1package-a-dep-2 中分别创建一个仅用于重定向的页面。

例如,在访问 package-a/pageA 页面前,你可以先依次跳转进入这两个依赖分包的页面,页面栈如下所示:

ts
[
  "/home",
  //⬇️ navigateTo 
  "/package-a-dep-1/entry",
  //⬇️ redirectTo 
  "/package-a-dep-2/entry",
  //⬇️ redirectTo
  "/package-a/pageA"
]

最佳实践

上述加载路径仅在每次小程序启动后的第一次访问时需要按顺序进入各依赖分包页面,后续访问时即可直接跳转到目标页面,因为依赖分包已经被加载。

你可以封装一个“分包加载管理器”来自动管理这一过程,提高用户体验与开发效率。