背景
- 微信小程序限制单个分包/主包大小不能超过2M
- 整个小程序所有分包不超过20M
- Taro中开启智能提取分包依赖导致小程序分包中存在大量重复代码
Taro 异步化能力
Taro原生混合 new-blended 模式
把 Taro 项目作为原生项目中的一个分包单独使用,并且把特定的组件单独打包为原生组件
模式介绍
新的混合模式在项目打包过程中会同时处理 Taro组件编译为原生自定义组件 的任务,该模式适用于同时需要用到 页面混合模式 以及 Taro组件编译为原生自定义组件 的场景。
以往使用taro build native-components 命令编译的自定义组件会额外包含一套Taro运行时,而这个特性可以帮助你在编译原生自定义组件的同时与taro页面共享同一套运行时代码,避免了两套运行时导致包体增大的问题。通过这种优化,我们能够更加高效地使用混合模式,并减少包体积的增长。
组件异步化实现
异步工程改造
将组件迁移至异步分包化工程中并在 app.config.ts 文件中全局注册

// app.config.ts
components:[
'components/Picker/index',
],
异步化组件需要配置index.config.ts处理css样式生效
//src/components/Picker/index.config.ts
export default {
styleIsolation: 'shared',
virtualHost: true,
}

config配置
//config/prod.ts
mini: {
webpackChain(chain){
chain.merge({
output:{
// 防止不同工程中 chunkid 的冲突
chunkLoadingGlobal: 'asynclibjsonp',
}
})
}
},
//package.json
"scripts": {
"build:weapp": "taro build --type weapp --new-blended",
"dev:weapp": "taro build --type weapp --new-blended --watch"
},
主工程改造
新建 pages-subpackage/lib-component 分包
//src/pages-subpackage/lib-components/pages/index/index.tsx
export default () => ''
//src/app.config.ts
// 注册异步分包口子
subpackages:[
{
name: 'lib-components',
root: 'pages-subpackage/lib-components',
pages: [
'pages/index/index',
],
}
]
app.config.ts注册异步组件路径
//src/app.config.ts
usingComponents: ({
weapp: {
// 异步分包中组件
'native-async-picker': './components/Picker/wechat',
},
})[process.env.TARO_ENV] || {}
components新增Picker文件夹 index.weapp.tsx 和 wechat 文件夹
//src/components/Picker/index.weapp.tsx
export interface IAsynPicker {
title: string;
list: any[];
onButtonClick: () => void;
}
function AsyncPicker<T>(props: IAsynPicker) {
return (
//TODO:这里可能ts报错 typings/component.d.ts中添加类型
<native-async-picker props={props} />
)
}
export default AsyncPicker
//typings/component.d.ts
import React from 'react';
declare global {
namespace JSX {
interface IntrinsicElements {
'native-async-picker': React.DetailedHTMLProps<any, any>;
}
}
}
export {};
//src/components/Picker/wechat/index.json
{
"component": true,
"usingComponents": {
// 这里的路径是你异步工程产物移动到主工程产物下对应的路径
"picker": "../../../pages-subpackage/lib-components/components/Picker/index"
},
"componentPlaceholder": {
"picker": "view"
}
}
// src/components/Picker/wechat/index.wxml
//异步化组件无法采取React中组件传递方式
<picker props="{{props}}" />
// src/components/Picker/wechat/index.ts
//原生组件只能用props接收
Component({
properties: {
props: {
type: Object,
value: {},
},
},
})
主工程脚本改造
//scripts/index.js
export default (ctx) => {
ctx.onBuildFinish(() => {
buildSubpackage({
libName:'',
outputPath:'',
srcPath:'',
})
})
}
//scripts/buildPackage.js
const { execSync } = require('child_process')
const path = require('path')
const fs = require('fs')
const chalk = require('chalk')
function buildSubpackage(item) {
const startAt = Date.now()
log('building', chalk.green(item.libName))
try {
// 迁移至异步化工程路径下运行
execSync(`cd ./packages/${item.libName} && npm run build:${process.env.TARO_ENV}`)
const output = path.join(projectRoot, item.outputPath)
if (fs.existsSync(output)) {
fs.rmSync(output, { recursive: true })
}
// 迁移异步化工程构建产物至主工程构建产物目录下
mergeDir(path.join(item.srcPath, './dist'), output)
} catch (e) {
log(`${item.libName} Subpackage 打包失败`, e)
throw new Error(`${item.libName} Subpackage 打包失败(${e.message})`)
}
}
config配置改造
// config/index.ts
plugins: [
//注册自定义插件
[path.resolve(__dirname, '../scripts/index.js')],
]
主工程页面上使用
//src/pages/index/index.tsx
import { View, Text } from '@tarojs/components'
import { useLoad } from '@tarojs/taro'
import Picker from '../../components/Picker/index.weapp'
import './index.scss'
export default function Index() {
useLoad(() => {
console.log('Page loaded.')
})
return (
<View className='index'>
<Text>Hello world!</Text>
<Picker title='异步组件测试' list={[1,2,3]} onButtonClick={()=>console.log("success")}></Picker>
</View>
)
}
微信开发者工具效果

最后
- Taro版本4.0.1+React18
- 支付宝小程序、抖音小程序未测试过
- 原生组件只能支持对应平台将不再具备多端转换的能力