基于 Taro 3 开发微信小程序插件:build-weapp-plugin 实战指南
【免费下载链接】taro开放式跨端跨框架解决方案,支持使用 React/Vue 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。项目地址: https://gitcode.com/gh_mirrors/tar/taro
微信小程序插件支持将组件、页面和接口封装成独立单元,供其他小程序直接引用,大幅提升跨项目复用效率。本指南以 Taro 仓库中的 build-weapp-plugin 示例工程为完整骨架,系统讲解在 Taro 3 项目中配置插件工程、开发三种插件形态(自定义组件、页面、接口)、打通插件与宿主小程序的数据流,以及如何在微信开发者工具中调试与发布,覆盖从零初始化到打包上线的全部关键步骤。
示例工程概览
build-weapp-plugin位于 Taro 仓库的 examples/build-weapp-plugin 目录,是一个使用 React 编写、基于 Webpack 5 编译的微信小程序插件 Demo。它本身既是一个可独立编译的 Taro 工程,又是一个标准的微信小程序插件项目,因此同时包含两类文件:
- 宿主侧源码:位于
src/,其中src/app.config.ts声明如何引用插件,src/pages/index/index.tsx是用于验证插件能力的测试页面; - 插件侧源码:位于
src/plugin/,内含plugin.json(插件配置清单)、index.ts(插件接口实现)、components/avatar(插件组件)、pages/list(插件页面)。
工程通过miniprogramRoot与pluginRoot将编译产物划分为两个相互独立的目录(详见下文"工程配置"一节),既保证插件目录不被宿主逻辑污染,也便于微信开发者工具按插件类型识别。
工程的依赖以 Taro 3.6 系为核心(@tarojs/taro、@tarojs/react、@tarojs/runtime、@tarojs/components、@tarojs/plugin-framework-react等均为3.6.24),框架选用 React 18,样式方案为 Sass,完整依赖清单见 package.json。
快速开始:四步跑通示例
1. 配置 appid
插件与宿主小程序必须绑定同一 AppID,否则开发者工具无法完成插件的注册与加载。按 README 要求修改两处:
- project.config.json 中的
appid字段(示例中为wxa9abf43f10a7bdb0); - src/app.config.ts 中
plugins.myPlugin.provider字段,同样填该 AppID。
若跳过此步,微信开发者工具会使用默认的测试 appid,插件将无法关联到宿主账号下进行真机调试与上传。
2. 安装依赖并编译
在examples/build-weapp-plugin目录下依次执行:
# 安装依赖 $ yarn # 开发模式(监听文件变更,实时重新编译) $ npm run dev # 生产模式(产物压缩、体积优化) $ npm run build两个脚本在 package.json 中定义:
{ "scripts": { "dev": "taro build --plugin weapp --watch", "build": "taro build --plugin weapp" } }--plugin weapp是 Taro CLI 面向微信小程序插件的专用编译模式;--watch开启监听,开发时保存源码会自动增量编译,产物输出到miniprogram/目录。
3. 开发位置约定
插件逻辑全部位于src/plugin内,包括组件、页面与接口;而src/pages/index则是用于测试插件的宿主页面,它负责以"使用者"的视角调用插件,验证组件事件、页面跳转与接口调用是否正常。二者隔离存放,职责清晰。
4. 导入开发者工具预览
使用微信开发者工具导入项目时,项目路径必须指向build-weapp-plugin/miniprogram(即编译产物目录,而非仓库根目录或src)。导入后开发者工具根据project.config.json中的miniprogramRoot与pluginRoot自动区分宿主代码与插件代码。
工程配置详解
project.config.json:插件类型项目声明
{ "miniprogramRoot": "miniprogram/", "pluginRoot": "plugin/", "compileType": "plugin", "appid": "wxa9abf43f10a7bdb0", "projectname": "build-weapp-plugin" }关键字段说明:
compileType: "plugin":向开发者工具声明这是一个插件项目,而非普通小程序;miniprogramRoot:宿主测试小程序(编译产物)的根目录;pluginRoot:插件(编译产物)的根目录,二者缺一不可;appid:插件所属小程序的 AppID,必须与src/app.config.ts中的provider一致。
config/index.js:Taro 构建配置
Taro 侧的构建配置位于 config/index.js,其中两个配置项与插件构建强相关:
outputRoot: 'miniprogram':把 Taro 编译产物输出到miniprogram/,与project.config.json的miniprogramRoot对应;copy.patterns:把宿主测试页引用插件时所需的额外文件复制进产物目录:
copy: { patterns: [ { from: 'src/my-export.js', to: 'miniprogram/miniprogram/my-export.js' } ] }该 copy 配置服务于插件export机制(详见"插件接口"一节):由于宿主侧通过export: 'my-export.js'引用该文件,而插件与宿主是两套独立构建产物,因此必须显式把src/my-export.js复制到宿主产物的miniprogram/miniprogram/下,保证运行时能按相对路径找到。
其余配置(designWidth: 750、deviceRatio、framework: 'react'、compiler.type: 'webpack5'、mini.postcss中的pxtransform/url等)与普通 Taro 工程一致,此处不再展开。
三种插件形态的开发
示例通过 src/plugin/plugin.json 同时声明了三种插件能力:
{ "publicComponents": { "avatar": "components/avatar/avatar" }, "pages": { "list": "pages/list/list" }, "main": "index.ts" }publicComponents:对外暴露的插件组件,键为宿主侧使用的组件名,值为组件路径;pages:对外暴露的插件页面,宿主可跳转;main:插件接口入口,宿主通过Taro.requirePlugin调用。
插件组件:props 与事件传递
插件组件 Avatar 位于 src/plugin/components/avatar/avatar.tsx,核心代码如下:
export default class Avatar extends Component<{ mode: any, onAvatarClick: any }, null> { node: { ctx: any } handleClick () { if (process.env.TARO_ENV === 'jd') { this.node.ctx.triggerEvent('avatarClick') } else { this.node.ctx.triggerEvent('avatar-click') } } render () { return ( <View ref={node => this.node = node} > <Text>triggerEvent 触发点击事件:</Text> <Image className='logo' src='http://storage.360buyimg.com/taro-static/static/images/logo.png' mode={this.props.mode} onClick={this.handleClick.bind(this)} /> <Text>props 传递点击事件:</Text> <Image className='logo' src='http://storage.360buyimg.com/taro-static/static/images/logo.png' mode={this.props.mode} onClick={this.props.onAvatarClick} /> </View> ) } }该组件演示了插件组件的两条核心数据通道(即 README 中提到的"插件组件测试特性"):
- props 传递:宿主把
mode等属性直接传给插件组件,组件在渲染层消费; - 事件传递与触发:
- 事件入参:宿主通过
onAvatarClick回调把事件传入组件,组件直接在onClick中调用; - 事件出参:组件内通过
this.node.ctx.triggerEvent('avatar-click')触发事件上抛给宿主。注意 Taro 用ref拿到自定义组件实例,再读取其内部ctx(Component 实例)调用triggerEvent,且京东端事件名需用驼峰avatarClick,微信端用短横线avatar-click,这是跨端命名差异的典型处理。
- 事件入参:宿主通过
在宿主测试页 src/pages/index/index.tsx 中,两种方式同时被验证:
<avatar onAvatarClick={() => console.log('组件事件传递成功')} props={{ mode: 'aspectFit', onAvatarClick: () => console.log('组件事件传递成功') }} />可见宿主既把onAvatarClick作为 props 直接传入,又把它包裹在props对象中一并传递,覆盖两种用法。
插件页面:选择器、分享与泛型组件
插件页面list位于 src/plugin/pages/list/list.tsx,对应 README 中的"插件页面测试特性",逐一验证了以下能力:
1. 获取小程序渲染层元素
getElement = () => { const query = Taro.createSelectorQuery().in(this.props.$scope) query.select('.page').boundingClientRect().exec(res => { console.log(res) }) }通过Taro.createSelectorQuery()创建查询,并用.in(this.props.$scope)把查询作用域限定到插件页面自身,再.select('.page').boundingClientRect()获取元素布局信息。这是插件页面操作渲染层节点的标准姿势。
2. 分享生命周期
onShareAppMessage() { return { title: '测试分享', path: '/pages/index/index' } }插件页面同样可以定义onShareAppMessage分享生命周期钩子,返回分享标题与路径。
3.genericsImplementation泛型组件
插件页面声明了泛型组件,见 src/plugin/pages/list/list.config.ts:
export default { "componentGenerics": { "mp-comp": true } }并在页面中使用占位:
<mp-comp></mp-comp>泛型组件的实际实现由宿主侧通过app.config.ts中的genericsImplementation指定:
genericsImplementation: { list: { 'mp-comp': 'component/comp' } }即:在名为list的插件页面里,把泛型占位mp-comp替换为宿主自己的组件component/comp。这样插件页面可以"留白"给宿主填充组件,实现页面骨架复用、外观定制的效果。
注意宿主测试页 src/pages/index/index.tsx 中同样渲染了一个
<mp-comp></mp-comp>,注释说明这是 hack:为了让genericsImplementation生效——因为当前构建链路还没有收集插件中使用到的第三方组件,需要在宿主侧手动保留一个占位以触发泛型解析。
插件页面中的ListItem组件(src/plugin/components/listItem/listItem.tsx)是一个纯展示组件,接收name、value两个 props 渲染列表项,用于验证插件页面内部使用自有组件的能力。
插件接口:main 入口与 export 参数
1. main 入口(Taro.requirePlugin)
插件接口实现在 src/plugin/index.ts:
export function sayHello () { console.log('Hello plugin!') } export const answer = 42宿主侧通过Taro.requirePlugin('myPlugin')拿到整个插件接口对象并调用:
usePluginInterface () { const myPluginInterface = Taro.requirePlugin('myPlugin') myPluginInterface.sayHello() const answer = myPluginInterface.answer console.log('answer: ', answer) }Taro.requirePlugin是微信小程序requirePluginAPI 在 Taro 中的封装,参数myPlugin与宿主app.config.ts中plugins字段声明的键名一致。
2. 宿主页面通过 export 暴露参数给插件(README 中"其它测试")
插件页面list在componentDidMount中通过requireMiniProgram()反向读取宿主暴露的数据:
declare const requireMiniProgram: () => { whoami: string } componentDidMount () { // 测试 export 京东小程序不支持在插件侧调用 if (process.env.TARO_ENV !== 'jd') { console.log(requireMiniProgram().whoami) } }宿主侧配套做了三件事:
- 定义暴露文件 src/my-export.js:
module.exports = { whoami: 'Wechat MiniProgram' }; - 在 src/app.config.ts 的插件声明中加入
export: 'my-export.js'; - 在 config/index.js 中通过
copy.patterns把该文件复制到miniprogram/miniprogram/my-export.js,确保插件运行时能按相对路径加载。
这一闭环演示了"宿主向插件传递参数"的机制:插件侧拿到的是宿主小程序的导出模块,可据此读取宿主上下文信息。同时代码注释标明京东小程序暂不支持在插件侧调用该能力,是跨端兼容性的重要提示。
宿主测试页完整结构
宿主测试页 src/pages/index/index.tsx 汇总了上述全部能力的使用方式:
import Taro from '@tarojs/taro' import React, { Component } from 'react' import { View, Button, Navigator } from '@tarojs/components' export default class Index extends Component { usePluginInterface () { /* 见上文 */ } render () { return ( <View className='index'> {/** 测试插件组件 */} <avatar onAvatarClick={...} props={{...}} /> {/** 测试插件页面 */} <Navigator url='plugin://myPlugin/list'> <Button>跳转到插件页面</Button> </Navigator> {/** 使用插件接口 */} <Button onClick={this.usePluginInterface}>测试插件接口</Button> {/** hack:为了让 genericsImplementation 生效 */} <mp-comp></mp-comp> </View> ) } }几点关键用法:
- 插件页面跳转:
plugin://协议是微信小程序跳转插件页面的专用 scheme,格式为plugin://插件名/页面路径,这里对应plugin.json中pages.list的值pages/list/list; - 宿主通过
Navigator组件或Taro.navigateTo均可发起跳转; - 宿主自身的页面声明在 src/app.config.ts 的
pages数组,插件声明在其plugins字段:
plugins: { myPlugin: { version: 'dev', provider: 'wxa9abf43f10a7bdb0', genericsImplementation: { ... }, export: 'my-export.js' } }其中version: 'dev'表示使用开发者工具中的"开发版"插件进行联调;实际发布时需替换为正式版本号。
插件文档编写约定
src/plugin/doc目录用于存放插件文档,README.md 给出了书写约定:
- 插件文档支持 Markdown 的多级标题;
- 引用图片时必须以相对路径引用
doc目录下的本地图片(如[](https://link.gitcode.com/i/f7e876ba49f22972bae62522118e590c)),不能使用网络图片或doc目录之外的图片; - 使用微信开发者工具编辑器的上传按钮可上传插件文档,上传内容包括
doc目录下的README.md与图片。
该文档与示例中的 example.jpeg 一同构成插件详情页展示素材,属于微信插件发布流程的一部分。
从示例走向生产
build-weapp-plugin覆盖了微信小程序插件开发的完整链路,可作为生产项目的起点模板:
- 复用骨架:把
src/plugin下的plugin.json、组件、页面、接口入口整体迁移到业务工程,替换appid与provider; - 扩展能力:按需在
publicComponents、pages中追加新的插件组件与页面;需要宿主定制外观时使用componentGenerics+genericsImplementation组合; - 构建产物:
dev/build脚本产物在miniprogram/,其中plugin/为插件本体、miniprogram/为测试宿主,导入开发者工具时路径指向build-weapp-plugin/miniprogram; - 发布前检查:确认
project.config.json的compileType: "plugin"与 appid 无误、export文件已通过copy.patterns正确复制、插件文档图片均为doc目录内的相对路径引用; - 跨端注意:事件命名(
avatarClick/avatar-click)与requireMiniProgram可用性均存在京东端差异,涉及京东小程序适配时需按process.env.TARO_ENV === 'jd'分别处理。
至此,你已经掌握在 Taro 3 中开发微信小程序插件组件、插件页面与插件接口的完整方法,并理解了triggerEvent事件上抛、Taro.requirePlugin接口调用、genericsImplementation泛型替换与export参数回传四条关键数据通道的底层配合方式。
【免费下载链接】taro开放式跨端跨框架解决方案,支持使用 React/Vue 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。项目地址: https://gitcode.com/gh_mirrors/tar/taro
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考