Vue 与 React 互操作
在开发中有时候会遇到这样的问题:
当前项目自身是 Vue 技术栈,已经迭代了很多次了,但是现在一个核心模块需要用到第三方实现,但是第三方给出的组件是 React,此时应该怎么处理呢?
以我开发过的项目代码为例:
- 前端
- 一个 Vue 开发的视频应用,可播放、可上传。
- 文件存储
- 上传:前端上传文件时,先上传到 Go 编写的 P2P 文件节点保存(本地节点、或线上部署节点),保存后返回一个文件哈希地址给前端,前端将文件哈希 post 发送到 NodeJS 编写的服务端,存储到 MongoDb 数据库中
- 下载:前端通过 NodeJS 服务端请求视频哈希地址,再通过 P2P 节点查找文件哈希地址获取视频数据,从而播放视频
- 支付链路
- 通过区块链做价值交换,使用代币交易,如:视频订阅付费、代币交换等操作
现在前端界面需要集成第三方的代币交易逻辑:uniswap,官方提供了 sdk、和 React UI 组件库 @uniswap/widgets
方案一:结合第三方 sdk 自定义 Vue 组件
通过第三方的 sdk 创建满足当前项目需求的 Vue 组件,
有如下优点与缺点:
- 优点
- 可以根据 sdk 逻辑,自定义界面实现,使得该模块完全融入主界面
- 缺点
- 实现成本
- uniswap 交易逻辑复杂,涉及滑点保护、路由最优解计算、gas 估算、授权审批、以及多链路,自建组件,需要自行处理所有边缘情况,处理不当容易导致交易失败、资金损失
- @uniswap/sdk-core:核心逻辑库,如:处理代币定义、金额计算、路由算法
- @uniswap/v3-sdk:智能合约交互逻辑,如:获取池子状态、计算价格影响、构建交易数据等
- 维护成本
- 虽然有 package.json 做版本锁定,sdk 的代码不会再变动,
- 但是 uniswap 的智能合约与后端路由服务是不断迭代更新的,
- 如果 sdk 版本老旧,可能无法享受到后续新增协议与费率优化特性,
- 手动升级,还需要同步交互逻辑,以及做全面功能测试
- 实现成本
方案二:使用提供的 React 组件
直接使用第三方提供的 React 组件 @uniswap/widgets
有如下优缺点:
- 优点
- Widget 内部会自动处理与最新后端服务的通信。只要官方保持组件接口的向后兼容(通常大版本内会保持),就只需要关注 UI 适配,这比维护核心交易逻辑成本要低得多
- 缺点
- 与项目技术栈不符合,不能直接使用,需要跨框架集成
初步路线选择
因为自己维护 uniswap sdk 交易逻辑与边界处理较为复杂耗时,我们还是选择了直接使用提供的 @uniswap/widgets React 组件,只需要解决跨框架集成的问题
按照集成所处的阶段来分,跨框架集成方案有以下几类
- 运行时桥接(最常用的)
- 桥接的框架双方各自正常编译,在运行时由一方创建真实 DOM 挂载点,把另一方的组件树挂载进入,中间加一层代理层来翻译 props、事件、生命周期
- 常用方案
- 手写桥接组件
- 通用桥接库
vuera:React in Vue2veaury:React in Vue3
- 编译时转换(小众方案)
- 在构建阶段把 A 框架的源码直接翻译成 B 框架的源码,运行时根本不存在"两个框架"的问题,但是 JSX 与 Vue template 无法无损互译,生命周期模型也不同,只适用于一次性迁移,不适合长期混用
- 应用级隔离(上下文不共享,交互更复杂)
- 如:iframe、微前端(qiankun 等)、Web Components。
- 此时集成的不是"组件"而是"应用",只适用于需要强隔离的场景下才使用
- 隔离性
- Web Components:css 完全隔离、js 共享上下文
- 微前端框架:qiankun / single-spa:???
- iframe:css js 完全隔离,只能 postMessage 通信
最终路线选择
因为编译时转换存在无法完全互转的问题,应用级隔离也存在上下文不共享,通信麻烦的问题,所以选择运行时桥接
虽然通用桥接库方便快捷,但不如自己手写桥接组件更轻量,所以选择自己手写编译时桥接组件作为代理层
react18 in vue2 实践
代码示例:???