写点什么

干货 | 携程门票 H5 转小程序实践

  • 2021-07-06
  • 本文字数:4117 字

    阅读完需:约 14 分钟

干货 | 携程门票H5转小程序实践

一、背景

自微信小程序出来后,互联网进入一个新的纪元。由于手机的容量有限,每个人不可能装太多 APP ,总有一些 APP 大家都装,称之为超级 APP,它们集成越来越多的功能,其中以小程序尤为突出。小程序巨大的流量红利不容小视,这也是小程序越来越火的部分原因。

 

我们团队一直致力于推进 react 多端一致,在进入小程序一致性研发工作之前,RN 和 web 已经实现了大部分的跨端工作。彼时(2020 年 8 月)小程序的研发多以原生为主、迭代周期很长,且代码书写和结构与 RN、web 开发有着巨大区别;为了提高研发效率、完善多端一致的技术路线,将现有代码以较小改动转成小程序代码势在必行。

二、各个跨端转换框架对比

结合当时小程序开发场景以及内部的一些限制,跨端框架需要满足“能够与原生项目混合”的要求,主要包括:


  • 在原生项目中使用转换后的页面

  • 在原生项目的分包中运行完整的转后的项目

  • 在原生项目中使用转换后的自定义组件,且在包体积等方面都需要考虑


结合我们之前做的一些调研,部分对比(有兴趣的朋友可以自行了解这些跨端转换框架)如下:

 

对比维度

KBone

Remax

Taro

Nanachi

跨平台

DSL

ReactVue

React

ReactVue

React

开发效率

一般

一般

包体积

较小

与原生项目混合

支持

不支持

不支持

支持

书写规范限制

2.1 可移植性

这里的可移植性主要指的是,转换后的代码是否能够“与原生项目混合”,我们有大量的业务场景需要涉及到跨团队的合作,进而在部分场景下需要提供组件供第三方接入,具体如下:



如上图所示区域 1 是原生的小程序页面,区域 2 是我们需要提供的自定义组件,在无法统一研发模式的情况下,选择的框架必须能够与原生项目混合,Remax 和 Taro 被排出在外。

2.2 包体积大小

由于分配到各个团队的包大小有限,再加上微信对于分包体积大小的限制以及体积过大带来的性能问题,转换后的小程序代码需要控制大小。在调研的过程中,Kbone、Remax 的非业务体积已经不在可接受的范围内,而 Nanachi 的框架部分代码仅为 40K 左右,造成这种差异的原因是因为 Nanachi 选择的实现方式为纯静态转换。

 

小结:综上,Kbone 不支持跨端,Remax 和 Taro 不支持“原生项目混合”,大小也会比较限制上线,加之四个框架在性能表现上并没有谁能一枝独秀,故在当时的条件下,Nanachi 是最佳选择。

三、Nanachi 简介

Nanachi,是一处编写多处运行的小程序快应用的转译框架,提供按平台打包核心库、按平台打包缺省组件、按平台打包业务代码、按平台注入 API 包的能力。


核心库是指 ReactWx, ReactBu, ReactAli, ReactQuick,针对不同的平台使用不同的迷你 React 库,娜娜奇是希望使用 React 强大的组件机制来突破小程序的弱模板限制。


缺省组件是指不同平台的小程序都是采用内置组件方式来构建页面的,由于微信的小程序起步较早且内置组件较完整,所以 Nanachi 以微信平台作为参考来提供一些组件补全其他平台缺失的内置组件。


按需打包业务代码是指登录支付等核心流程可能出入太大,如果使用 if else 会导致小程序的 size 过大,因此提供 ANU_ENV 变量实现打编译打包对应平台的代码。


API 包是指 wx, swan, my 这些对象,为小程序提供调用电池,摄像头,通信录,二维包等原生 API 的能力,但是它们也不统一,需要我们做兼容处理。直接访问 React.api 就能得到磨平后的 API。


按需注入 API 补丁包则是刚才功能的更高级形式,目的是让体积更加小。

四、存在的问题

4.1  React 代码到小程序代码的大致过程


由于 Nanachi 是纯静态转换,所以源文件到目标文件有着较强的映射关系。一个标准的 Class 式组件会被 Nanachi 映射成对应的模块和文件,如上图所示为 Nanachi 的一个大致的映射关系,更直观的展示可以参考以下示例:



import React from '@react';import Dog from '@components/Dog/index';class P extends React.Component { render() { return ( <div> <div>类继承的演示</div> <Dog age={12} /> </div> ); }}export default P;
复制代码


以上代码会生成两个文件:



//Component.js
function P() {}P = _ReactWX2.default.miniCreateClass(P, _ReactWX2.default.Component, { render:function() { var h = _ReactWX2.default.createElement; return h( "view",null, h("view", null, "\u7C7B\u7EE7\u627F\u7684\u6F14\u793A"), h(_ReactWX2.default.template, { age:12, templatedata:"data09558693", is: _index2.default }) ); }, classUid:"c70258" }, {});Page(_ReactWX2.default.createPage(P, "pages/demo/syntax/extend/index"));exports.default= P;
//Component.wxml
<import src="../../../../components/Dog/index.wxml"/><view> <view>类继承的演示</view> <template is="Dog" data="{{...data}}" wx:for="{{data09558693}}" wx:for-item="data" wx:for-index="index" wx:key="*this"></template></view>
复制代码


如此,完成了源文件到目标文件的转换。

4.2  问题

.js 文件和.wxml 文件的数据交互是通过 this.data 来进行的,所以源代码中的 props 和 state 会在编译过程中添加到 this.data 上,而视图的改变会通过 this.setData 来进行更新。所以在 4.1 章节中“对象属性”这一块内容由于不属于 state 或者 props,是没法被 Nanachi 编译的。由此不难发现,由于框架是强映射的,源文件到目标文件之间需要用到大量的编译条件以及一些 api 的模拟来达到减小手动修改代码来匹配未完成规则的限制,这里列举了一些框架限制:

 

1)只允许 this.props.xx 或者 this.state.xx 的数据传递 

2)不支持组件作为 props 传递(不支持动态组件)

3)不支持 ref 机制、不支持 findDOMNode 

4)文件目录结构以及命名等规范必须强制遵循

五、转换方案和具体实施

Nanachi 框架支持通过编写一套代码来转换成不同端的应用,但转换过程中存在一些限制,我们通过增强框架核心库功能、添加转译插件等来支持与原生项目混合开发,减少框架的限制。

5.1 整体转译流程


1)根据用户输入的页面路径来收集页面依赖文件的依赖树,并作为静态转译插件的输入来源。

2)对依赖树进行静态编译,并生成符合 Nanachi 框架转译规范的代码结构,通过 Nanachi 框架转换成原生小程序项目。

3)将转译后的小程序以页面的方式接入原生小程序项目中,需要将转译后的小程序页面转换为符合小程序 Page  API 的参数,并与原小程序页面参数合并作为输入,实现小程序页面注册。

5.2 小程序静态转译插件

小程序静态转译插件是 React 语法编译插件集合,通过 Babel 使用这一系列插件可以将现有项目的 React 代码转换为符合不同平台小程序语法规范的代码,是“源码到源码”编译。在梳理 React 项目与小程序的异同点后,通过制定的代码规范,并对 React 项目代码进行静态分析,创建或操作抽象语法树(AST)来实现小程序代码的转换。

 

5.2.1 制定代码规范

 

基于 React 语法、小程序语法规范的差异点进行梳理分析并制定相关代码规范,规范代码、目录规则结构、文件命名规范、文件内容规范,实现使用小程序静态转译时源代码少改动、语法限制小且静态分析有规律可循的目的。

 

5.2.2 替换动态变量


JSX 中的动态变量无法直接转换成符合小程序的语法,需要通过将动态变量转换为可监测的变量来实现 JSX 到小程序 View 层的转换。


首先需要梳理 JSX 中使用到的动态变量类型,作为静态分析时变量收集的依据。有了依据便能通过对源码进行静态分析,识别不同的变量类型的 AST 节点规则,梳理对应变量类型的收集逻辑,实现对源码中 JSX 使用到的变量的收集。最后对收集的变量进行节点、类型和作用域分析,通过创建或操作 AST 将动态变量转换为可监测的变量(props、state)。

 

5.2.3  抽取动态组件


对于在运行时才能确定依赖的子组件的组件,需要在静态转译过程中对组件抽取生成新的组件,保证源码少改动、语法限制小的同时实现动态组件的转换。


插件会先分析动态组件的 AST 节点及特征,在静态分析阶段收集组件使用过的变量、子组件、形参等调用过的变量。接着插件在转译过程中将需要调用的变量提取出来,链接到新的组件中去,使新的组件在运行的时候不依赖于子组件。

 

5.2.4  Ref 处理

 

Ref 是一个获取 DOM 节点或 React 元素实例的工具,小程序中无法直接使用 Ref 属性,需要将源码的 Ref 属性解析成对应的获取组件实例逻辑并封装小程序 DOM 节点 API,实现 Ref 属性到小程序的转换,保证转换后功能的可用性。

 

5.2.5 Tree Shaking


从源码转译为小程序时,会因为使用外部依赖函数存在冗余代码,导致小程序体积过大的问题,需要通过 Tree Shaking 来去除冗余代码。


首先需要收集 Tree Shaking 的分析依据,通过对源码进行依赖收集时,收集被依赖的文件及使用到的函数,以此获得基础的分析数据。在此基础上对收集到的依赖文件进一步分析,通过排除函数中的形参、内部变量并分析作用域、分析变量的组成来收集函数使用过的外部变量。最后将收集到的变量作为依据,通过操作 AST 将冗余的代码去除,并生成新的文件。

5.3 项目效果

经过一系列的编译和转换操作,基本上实现了一套代码更改小程序、RN、H5 的同时迭代。下图分别是小程序、RN、H5 的线上效果图:

 

六、小结

本文分享了 H5 转换小程序时的选型考量、问题,以及一些问题的处理方案,旨在给大家提供一些新的思路。如前文描述,这个项目是基于已有项目的转换,所以做了许多对代码格式和结构的编译重组工作,故而新建项目开发的话会更加友好。


另外由于框架强静态化的编译思想,导致目前依旧有不少规则需要遵守,这块 Taro3 表现的会比较好,规则束缚没有那么多。在实践中,转换后组件性能是比不上原生的小程序组件的,并且会随着组件复杂度上升而下降,所以各位在选择 H5 转换小程序的方案时,需要对效率和性能的平衡做一个考量。

 

【参考文档】

[1] React 转小程序现状

https://zhuanlan.zhihu.com/p/41144332

[2] anu 小程序快速入门

https://zhuanlan.zhihu.com/p/44005766

[3] 娜娜奇开发文档

https://qunarcorp.github.io/anu/

[4] React 转微信小程序:从 React 类定义到 Component 调用 

https://zhuanlan.zhihu.com/p/38903385


作者简介:

本文作者为携程门票前端小程序组,关注小程序相关的开发和优化。


本文转载自:携程技术(ID:ctriptech)

原文链接:干货 | 携程门票H5转小程序实践

2021-07-06 13:003419

评论 2 条评论

发布
用户头像
uniapp不香吗
2021-07-12 08:11
回复
项目是将已有React H5代码转为小程序,另外需要作为组件供原生小程序页面接入,最后大小还有限制。这几项 uniapp全部支持吗?
2021-07-15 10:42
回复
没有更多了
发现更多内容

Nautilus Chain上首个DEX PoseiSwap即将开启IDO,潜力几何?

BlockChain先知

Github百万收藏!这部《从零开始写分布式服务框架》称霸榜首!

Java你猿哥

Java 架构 分布式 ssm 分布式框架

硬核!靠这套MySQL笔记轻松过了阿里二面,基础架构调优齐全了

做梦都在改BUG

Java MySQL 数据库

DiskCatalogMaker for mac(磁盘文件管理工具) v8.6.5中文注册版

理理

Mac磁盘管理 DiskCatalogMaker 注册版 DiskCatalogMaker 中文 DiskCatalogMaker 破解

mac文件比较对比工具-Beyond Compare mac最新中文破解版

理理

Beyond Compare 4 Beyond Compare安装教程 Beyond Compare破解 mac文件对比工具

互联网工程师Java面试八股文及答案整理(2023最新版)

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

【1对1咨询】前端和后端,哪个更简单?转行程序员的捷径

程序员晚枫

前端 后端 转行

Java 容器详解:使用与案例

小万哥

Java 程序员 容器 面试 后端

Github标星78k,Alibaba最新发布的Spring Boot项目实战文档!太强了

Java你猿哥

Java spring Spring Boot mybatis ssm

如何使用ChatGPT自带插件

楚少AI

ChatGPT ChatGPT4 chatgpt插件

浅析 Redis 数据结构 List 及其底层编码方式

Java你猿哥

Java redis List ssm

熬了一个月肝完这份阿里架构师的Java面试手册,我从20K变成了30K

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

模块七作业 - 王者荣耀商城异地多活架构设计

🐢先生

架构实战营

阿里大佬带你一周刷完Java面试八股文,比刷视频效果好多了!

Java你猿哥

Java 分布式 微服务 JVM ssm

raw图像处理-RAW Power中文-mac破解软件

理理

mac软件下载 raw图像处理 RAW Power Mac破解版

Nautilus Chain:独特且纯粹的创新型 Layer3

西柚子

炸了!力扣官方首发了这套1568页LeetCode算法刷题笔记(彩页版)

Java你猿哥

面试 算法 LeetCode 力扣 左程云

2023年互联网Java工程师高级面试八股文汇总(1260道题目附解析)

Java你猿哥

Java MySQL zookeeper JVM java面试

绝了!阿里大佬的"Redis深度核心笔记",从基础到源码,全是精华

做梦都在改BUG

Java 数据库 redis 缓存

开源字节 考研集训营小程序

源字节1号

开源 软件开发 前端开发 后端开发 小程序开发

网络安全面试题大全(整理版)500+面试题附答案详解,最全面详细,看完稳了

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

阿里人都在死磕的全彩版"并发编程笔记",面试大厂必备!

做梦都在改BUG

Java 并发编程 高并发

面试官问:kafka为什么如此之快?

做梦都在改BUG

Java kafka 面试

数字化转型应该如何去做?(4A架构篇)

数字随行

数字化转型

流批一体数据交换 etl-engine 融合查询语法

weigeonlyyou

数据迁移 ETL 云数据迁移 Kafka ETL 流批一体化

授权码 + PKCE 模式|OIDC & OAuth2.0 认证协议最佳实践系列【03】

Authing

OIDC PKCE

pd虚拟机专用windows系统镜像(m1/intel)一键安装版

理理

虚拟机 win 11镜像 win镜像 arallels Desktop

阿里资深架构师总结的春招Java岗核心笔记,GitHub标星20k

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

kafka消费者那些事儿

做梦都在改BUG

Java kafka 消费者

Nautilus Chain:独特且纯粹的创新型 Layer3

股市老人

干货 | 携程门票H5转小程序实践_大前端_携程技术_InfoQ精选文章