react-native-miniprogram
让 React Native 代码直接运行在微信小程序(及兼容小程序平台)之上的跨端渲染引擎,设计思路完整对标
react-native-web。
目录
项目简介
react-native-miniprogram 是面向 微信小程序 的 React Native 运行时适配层:
- 业务代码 无需改动,继续用
View/Text/StyleSheet/FlatList/Animated等 RN 接口 - 运行期把 React 组件树 实时编译为小程序原生组件(
view/text/scroll-view/input等) - 事件、样式、API 四层映射,最大化保持 RN 语义一致性
- 架构完整复刻
react-native-web,升级 / 调优有明确参照系
目标用户:希望用一套 React Native 代码同时覆盖 App 与小程序的团队。
特性
- RN 接口兼容:
View/Text/Image/ScrollView/TextInput/Pressable/Touchable*/Modal/FlatList/SectionList/Animated… - 基于 react-reconciler:自定义
HostConfig,完整 Fiber 调度 - setData 合批:微任务合批 +
JSON.stringifypayload 去重,大幅减少渲染开销 - StyleSheet 三分支编译:atomic / classic / inline,编译期产出
app.wxss - BiDi 双向布局:
PROPERTIES_I18N/PROPERTIES_FLIP支持 LTR / RTL 自动翻转 - Pressability 状态机:完整复刻 RN 原生
TouchableMixin(含 longPress / hitSlop) - TypeScript 全量:
src/已完成 TS 化,类型信息完整 - API 垫片:
AsyncStorage/Dimensions/Keyboard/Linking/AppState/Clipboard/BackHandler/Alert/UIManager/ImageLoader…
整体架构
┌─────────────────────────────────────────────────────┐
│ React 业务组件(复用 RN 代码) │
└────────────────────────┬────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ exports/* RN 同名 API │
│ View / Text / ScrollView / TextInput / StyleSheet │
└────────────────────────┬────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ modules/* 公共能力 │
│ createDOMProps / createElement / styleq / │
│ Pressability / ResponderSystem … │
└────────────────────────┬────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ runtime/* 核心运行时 │
│ MiniRootNode + react-reconciler HostConfig │
│ scheduler(合批 setData)+ eventHub(事件反查表) │
└────────────────────────┬────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ 微信小程序原生组件 │
│ view / text / image / scroll-view / input / … │
└─────────────────────────────────────────────────────┘
关键运行时模块:
| 模块 | 作用 |
|---|---|
MiniRootNode |
持有 pageInstance,作为 reconciler 的 root container |
HostConfig |
实现 react-reconciler 接口,管理节点创建/更新/删除 |
scheduler |
微任务合批 setData,payload 去重 |
eventHub |
小程序事件 React 合成事件双向映射 |
serialize |
MiniNode 树序列化为 setData payload |
快速开始
安装
npm install react-native-miniprogram react
# 或
yarn add react-native-miniprogram react
配置 Babel 别名
在你的小程序构建工具中把 react-native 别名到 react-native-miniprogram:
// babel.config.js
module.exports = {
plugins: [
['module-resolver', {
alias: { 'react-native': 'react-native-miniprogram' }
}]
]
};
编写业务代码(与 RN 完全一致)
import React from 'react';
import { View, Text, StyleSheet, Pressable } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello, MiniApp!</Text>
<Pressable onPress={() => console.log('pressed')}>
<Text>点我</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 20, backgroundColor: '#fff' },
title: { fontSize: 24, fontWeight: 'bold', color: '#333' }
});
在页面中挂载
// pages/index/index.js
import render, { eventHub } from 'react-native-miniprogram';
import App from '../../src/App';
Page(eventHub.install({
onLoad() {
this.$app = render(<App />, this);
},
onUnload() {
this.$app && this.$app.unmount();
}
}));
其中:
render(element, pageInstance)把 React 树渲染到pageInstance.data.$rnmeventHub.install(definition)给页面定义注入_dispatch事件上行通道this.$app.unmount()页面卸载时释放
复制模板到小程序工程
项目自带 template/ 目录,构建后会产出:
template/app-entry/— 小程序app.js/app.wxss注入入口template/element/— 通用自定义组件element,承载所有渲染节点
构建流程参见 scripts/copy-template.js。
映射规则
| 维度 | 实现位置 | 说明 |
|---|---|---|
| 组件映射 | runtime/serialize.ts |
View → view、Text → text、Image → image、ScrollView → scroll-view、TextInput → input/textarea |
| 事件映射 | runtime/eventHub.ts |
onPress / onTouchStart bindtap / bindtouchstart(双向反查) |
| 样式映射 | exports/StyleSheet + vendor/styleq |
RN StyleSheet.create → atomic class + inline → app.wxss |
| API 映射 | exports/{Alert,AsyncStorage,…} |
Alert.alert → wx.showModal、AsyncStorage → wx.*Storage*、Linking.openURL → wx.navigateTo |
模板与构建产物
构建会生成:
dist/
├── cjs/ CommonJS 产物
└── (esm)/ ES Module 产物
template/
├── app-entry/ 小程序主包入口模板
└── element/ 通用渲染组件(element.wxml / element.wxss)
其中 element/element.wxml 通过 递归 + 条件渲染 承载 MiniNode 树,element.wxss 承载 StyleSheet 编译产物。详见 template/app-entry/README.md。
API 覆盖情况
| 类别 | API | 状态 |
|---|---|---|
| 核心组件 | View / Text / Image / ScrollView / TextInput / Pressable / TouchableOpacity / TouchableHighlight / Modal / Button / Switch / CheckBox / Picker / ActivityIndicator |
|
| 列表 | FlatList / SectionList / VirtualizedList |
(基于 RN vendor) |
| 动画 | Animated / Easing / PanResponder |
(基于 RN vendor) |
| 样式 | StyleSheet.create / StyleSheet.flatten / StyleSheet.compose |
|
| 通知 | Alert / AlertAsync |
|
| 存储 | AsyncStorage |
|
| 尺寸 | Dimensions / PixelRatio / Platform |
|
| 键盘 | Keyboard |
|
| 链接 | Linking |
|
| 应用 | AppState / BackHandler / InteractionManager |
|
| 剪贴板 | Clipboard |
|
| UI | UIManager.measure / LayoutAnimation |
|
| 不支持 | StatusBar / PushNotification 等受平台限制 |
开发与构建
# 安装依赖
yarn install
# 开发(watch 模式)
yarn dev
# 构建全量产物(CJS + ESM + template)
yarn build
# 单元测试
yarn test
yarn test:coverage
常见问题
Q:性能如何?
A:scheduler 使用微任务合批 + payload JSON.stringify 去重,避免 React 每次提交都触发 setData。对于大列表建议用 VirtualizedList / FlatList,底层已做 recycle。
Q:样式为什么有些 RN 写法不生效?
A:部分 RN 简写样式(如 background / font)在小程序 wxss 中会被拆分,参见 StyleSheet/validate.ts 警告列表。建议使用长格式。
Q:事件 event.target 为什么不是 DOM 节点?
A:小程序无 DOM,我们用 MiniNode 模拟。event.target / event.currentTarget 都指向 MiniNode,可通过其 id / dataset / type 访问语义信息。
Q:如何自定义节点 dataKey?
A:调用 render(element, page, { dataKey: 'myData' }),在 element.wxml 中对应 page.data.myData。
路线图
- 支持抖音小程序 / 支付宝小程序 / 百度智能小程序
-
LayoutAnimation与原生 CSS 动画对齐 - DevTools 浏览器插件(可视化 MiniNode 树)
- SSR-like 预渲染(构建期生成首屏快照)
- 补强 runtime 单测覆盖率到 80%+
审计报告
本项目已完成完整代码审计,详见 AUDIT_REPORT.md:
- 架构对齐度
- 代码正确性 ☆
- 可维护性 ☆
贡献
欢迎 Issue / PR。请遵循:
- 优先阅读
AUDIT_REPORT.md了解当前架构现状 - 修改前先跑
yarn test - 提 PR 时附带 reproduce demo 或测试用例
协议
MIT React Native for MiniApp Contributors