作用
默认情况下只有非独立分包可以调用主包的内容,分包异步化的出现可以通过配置与接口进行部分内容的跨分包调用
环境
uniapp(vue cli + vite + vue3) + 微信小程序
应用场景
- 跨分包调用代码
- 跨分包调用 npm 包
- uniapp 打包默认会将 npm 包打进主包的 vendor.js 中,导致主包过大
- 可手动将 npm 包移入分包中
- 通过分包异步化的方式跨分包调用 npm 包
- 跨分包调用组件
跨分包调用代码
使用微信自带的 require 函数,此处写的代码在编译后会原样调用,因此需使用相对路径,文件后缀也是 js
<script setup lang="ts">
require
.async('../../sub/pkgA/logicA.js')
.then((pkg) => {
pkg.tst('main')
})
.catch(({ mod, errMsg }) => {
console.error(`path: ${mod}, ${errMsg}`)
})
</script>
分包的业务代码
// sub/pkgA/logicA.ts
export function tst(name: string) {
console.log('tst55667788', name)
}
为了让分包业务代码打包进产物,需要在分包页面中进行引用
// sub/pkgA/pkgA.vue
<script setup lang="ts">
import { tst } from './logicA.ts'
</script>
<template>
<div>
{{ tst }}
</div>
</template>
跨分包调用 npm 包
使用方式与跨分包调用业务代码一致,唯一的区别就是需要将 node_modules 中的 npm 包移入子包代码中,并且需要被子包页面所引用
- sub
- pkgA
- dayjs // npm 包代码
- pkgA.vue
跨分包调用组件
配置 componentPlaceholder
// pages.json
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom"
"componentPlaceholder": {
"comp-a": "view" // 组件名: 占位内容
}
}
}
]
调用分包中的组件
<script setup lang="ts">
import compA from '@/sub/pkgA/compA.vue'
</script>
<template>
<comp-a />
</template>
为了让分包中的组件代码能打包进产物,需要在分包页面中进行引用
// pkgA/pkgA.vue
<script setup lang="ts">
import CompA from './compA.vue'
</script>
<template>
<div>
<CompA />
</div>
</template>
PS:pages.json 中可以给页面配置 componentPlaceholder 引用其他分包的异步组件; 组件中没法配置 componentPlaceholder,因此在组件中引用另一个分包的组件会产生错误 ❌
解决方案:通过 vite 插件对打包产物进行修改,添加上 componentPlaceholder
export default () => {
return {
name: 'vite-uni-comp-placeholder',
enforce: 'post' as any,
generateBundle: async (_, bundle) => {
const keys = Object.keys(bundle)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const item = bundle[key]
if (item.type === 'asset' && key.endsWith('.json')) {
const obj = JSON.parse(item.source as string)
if (!obj.usingComponents) continue
Object.keys(obj.usingComponents).forEach((key) => {
const value = obj.usingComponents[key]
// 使用了子包中的组件,此处路径可自行替换为子包路径
if (value.startsWith('../../sub')) {
// 自行添加 componentPlaceholder 配置
obj.componentPlaceholder = obj.componentPlaceholder || {}
obj.componentPlaceholder[key] = 'view'
}
})
item.source = JSON.stringify(obj)
}
}
}
}
}