关于分包优化的说明

  • 在对应平台的配置下添加"optimization":{"subPackages":true}开启分包优化
  • 目前只支持mp-weixinmp-qqmp-baidump-toutiaomp-kuaishou的分包优化
  • 分包优化具体逻辑:
    • 静态文件:分包下支持 static 等静态资源拷贝,即分包目录内放置的静态资源不会被打包到主包中,也不可在主包中使用
    • js文件:当某个 js 仅被一个分包引用时,该 js 会被打包到该分包内,否则仍打到主包(即被主包引用,或被超过 1 个分包引用)
    • 自定义组件:若某个自定义组件仅被一个分包引用时,且未放入到分包内,编译时会输出提示信息

分包内静态文件示例

"subPackages": [{
	"root": "pages/sub",
	"pages": [{
		"path": "index/index"
	}]
}]

以上面的分包为例,放在每个分包root对应目录下的静态文件会被打包到此分包内。

🚨 一声叹息:Vue3 时代官方把「分包优化」砍了!

维度 Vue2(webpack) Vue3(vite)
官方策略 内置 SplitChunks,自动拆包 ⚠️ 直接移除拆包逻辑
结果 主包轻松 < 2 MB 所有依赖一股脑进 common/vendor.js,瞬间爆表
平台红线 微信小程序主包 ≤ 2 MB 上线即拒审

结论:不是 Vue3 不能分包,而是官方没做;不想被 2 MB 卡脖子,就必须装 @uni-ku/bundle-optimizer

🎏 功能与支持

适用于 Uniapp - CLI 或 HBuilderX 创建的 Vue3 项目

1.分包优化

  • 静态文件:分包下支持 static 等静态资源拷贝,即分包目录内放置的静态资源不会被打包到主包中,也不可在主包中使用
  • js文件:当某个 js 仅被一个分包引用时,该 js 会被打包到该分包内,否则仍打到主包(即被主包引用,或被超过 1 个分包引用)
  • 自定义组件:若某个自定义组件仅被一个分包引用时,且未放入到分包内,编译时会输出提示信息

2. 模块异步跨包调用

允许使用  import() 语法,异步引用模块。

注意,这不是指静态导入,详见此处

v2.1.0 版本开始,插件实现了 无感屏蔽 非法的 import() 行为,同时会有 log 提示开发者迁移写法:

  • 小程序端对 vue 组件文件的 import() 是非法的
  • app端的编译格式是iife,无法使用import()语法,故均视为非法,将全量屏蔽

3. 组件异步跨包引用

在vue 组件的 defineOptions 宏指令或者默认导出下配置 componentPlaceholder,eg:

<!-- setup 模式(组合式) -->
<script setup>
import SubComponent from '@/pages-sub-async/component.vue'
import SubDemo from '@/pages-sub-demo/index.vue'

defineOptions({
  componentPlaceholder: {
    SubComponent: 'view',
    SubDemo: 'view',
  },
})
</script>
<!-- 默认导出模式(选项式) -->
<script>
import SubComponent from '@/pages-sub-async/component.vue'
import SubDemo from '@/pages-sub-demo/index.vue'
// 同样支持支持 defineComponent
export default {
  components: {
    SubComponent,
    SubDemo,
  },
  componentPlaceholder: {
    SubComponent: 'view',
    SubDemo: 'view',
  },
}
</script>

异步组件、异步模块引用基本原理:详见 https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/async.html

📦 安装

pnpm add -D @uni-ku/bundle-optimizer

🚀 使用

0. 插件可配置参数

以下各参数均为可选参数,默认开启所有插件功能,并在项目根目录下生成async-component.d.ts文件

参数-[enable] 类型 默认值 描述
enable boolean|object true 插件功能总开关,object时可详细配置各插件启闭状态,详见下列
enable.optimization boolean true 分包优化启闭状态
enable['async-import'] boolean true 模块异步跨包调用启闭状态
enable['async-component'] boolean true 组件异步跨包引用启闭状态
参数-[logger] 类型 默认值 描述
logger boolean|string[] false 插件日志输出总配置,true时启用所有子插件的日志功能;string[]时可具体启用部分插件的日志,可以是optimizationasync-componentasync-import

1. 引入 @uni-ku/bundle-optimizer

  • CLI: 直接编写 根目录下的 vite.config.*
  • HBuilderX: 需要根据你所使用语言, 在根目录下 创建 vite.config.*

简单配置:

// vite.config.*
import Uni from '@dcloudio/vite-plugin-uni'
import Optimization from '@uni-ku/bundle-optimizer'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    Uni(),
    Optimization({
      enable: true,
      dts: true,
      logger: false,
    }),
    // 以上配置都是默认配置,可以直接不传任何配置
    // Optimization(),
  ],
})

详细配置说明

// vite.config.*
import Uni from '@dcloudio/vite-plugin-uni'
import Optimization from '@uni-ku/bundle-optimizer'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    Uni(),
    // 可以无需传递任何参数,默认开启所有插件功能,并在项目根目录生成类型定义文件
    Optimization({
      // 插件功能开关,默认为true,即开启所有功能
      enable: {
        'optimization': true,
        'async-import': true,
        'async-component': true,
      },
      // 也可以传递具体的子插件的字符串列表,如 ['optimization', 'async-import', 'async-component'],开启部分插件的log功能
      logger: true, // 默认 false
    }),
  ],
})

2. 修改 manifest.json

需要修改 manifest.json 中的 mp-weixin.optimization.subPackages 配置项为 true,开启方法与vue2版本的uniapp一致。

{
  "mp-weixin": {
    "optimization": {
      "subPackages": true
    }
  }
}

使用了 @uni-helper/vite-plugin-uni-manifest 的项目,修改 manifest.config.ts 的对应配置项即可。

✨ 例子

以下例子均以CLI创建项目为例, HBuilderX 项目与以上设置同理。

现在已经支持 hbx 创建的 vue3 + vite、不以 src 为主要代码目录的项目。

分包优化

分包优化 是本插件运行时默认开启的功能,无需额外配置,只需要确认 manifest.json 中的 mp-weixin.optimization.subPackages 配置项为 true 即可。

模块异步跨包调用

模块异步跨包调用 是指在一个分包中引用另一个分包中的模块(不限主包与分包),这里的模块可以是 js/ts 模块(插件)。

TODO: 是否支持 json 文件?

TODO: 是否支持 vue 文件?当然,小程序环境引入 vue 文件一般是没有什么意义的。

目前实测,小程序环境下,千万不要对一个 vue 组件进行 import() 这会导致这个 vue 组件对应的页面或者文件空白,和 “分包优化” 功能有些许冲突”,后续会尽可能填补这个缺陷

随着新版本的到来 v2.1.0,对非法的 import() 行为,实现了无感的屏蔽操作,同时会有 log 提示开发者迁移写法

可以不用在意可能会因为这个问题导致的页面空白问题了,如果还存在问题,欢迎反馈🙏,详见此处

可以直接使用 esm 的原生异步导入语法 import() 来实现模块的异步引入。

  • h5:原生支持
  • mp:转译成 require.async()
  • app:app端的编译格式是 iife,无法使用 import() 语法,本插件将全量屏蔽 import() 行为
  • 其他 mp:TODO: 未做兼容测试,欢迎反馈‘
// js/ts 模块(插件) 异步引入
await import('@/pages-sub-async/async-plugin/index').then((res) => {
  console.log(res?.AsyncPlugin()) // 该插件导出了一个具名函数
})

// vue 文件 异步引入(页面文件)❌ 不要这样使用,不要这样引用组件文件
import('@/pages-sub-async/index.vue').then((res) => {
  console.log(res.default || res)
})

// vue 文件 异步引入(组件文件)❌ 不要这样使用,不要这样引用组件文件
import('@/pages-sub-async/async-component/index.vue').then((res) => {
  console.log(res.default || res)
})

 组件异步跨包引用

组件异步跨包引用 是指在一个分包中引用另一个分包中的组件(不限主包与分包),这里的组件就是 vue 文件;貌似支持把页面文件也作为组件引入。

需要在 vue 组件的 defineOptions 宏指令或者默认导出下配置 componentPlaceholder

由于小程序端需要 kebab-case 风格的组件名称,插件内部会自动处理你的 componentPlaceholder 配置:将组件名称(key)以及占位目标组件名(value)转换成 kebab-case 风格。

setup 模式(组合式):

<!-- setup 模式(组合式) -->
<script setup>
import SubComponent from '@/pages-sub-async/component.vue'
import SubDemo from '@/pages-sub-demo/index.vue'

defineOptions({
  componentPlaceholder: {
    SubComponent: 'view',
    SubDemo: 'view',
  },
})
</script>

默认导出模式(选项式):

可能有些环境不能使用 defineOptions 宏

<!-- 默认导出模式(选项式) -->
<script>
import SubComponent from '@/pages-sub-async/component.vue'
import SubDemo from '@/pages-sub-demo/index.vue'

// 同样支持支持 defineComponent
export default {
  components: {
    SubComponent,
    SubDemo,
  },
  componentPlaceholder: {
    SubComponent: 'view',
    SubDemo: 'view',
  },
}
</script>

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐