写点什么

干货 | 携程门票 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:003415

评论 2 条评论

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

远程办公经验?来一场自问自答形式的介绍吧~ | 社区征文

为自己带盐

初夏征文 7月月更

华为发布HCSP-Solution-5G Security人才认证,助力5G安全人才生态建设

Geek_2d6073

StoneDB 为国产数据库添砖加瓦,基于 MySQL 的一体化实时 HTAP 数据库正式开源!

StoneDB

大数据 MySQL 数据库 #数据库 HTAP #开源

从零开始学 MySQL —数据库和数据表操作

C++后台开发

MySQL 数据库 中间件 后端开发 C++开发

宝,运维100+服务器很头疼怎么办?用行云管家!

行云管家

云计算 运维 服务器 云管

MySQL审计插件介绍

Simon

MySQL 运维 MySQL 数据库

混沌工程平台 ChaosBlade-Box 新版重磅发布

阿里巴巴云原生

阿里云 分布式 云原生 混沌工程

贝联珠贯加入龙蜥社区,共同促进碳中和

OpenAnolis小助手

开源 龙蜥社区 CLA 贝联珠贯 IT资源利用

她就是那个「别人家的HR」|ONES 人物

万事ONES

如何使用物联网低代码平台进行个人设置?

AIRIOT

低代码 物联网 低代码,项目开发

如何写出好代码 - 防御式编程指南

云智慧AIOps社区

Java 架构 代码质量

独家消息:阿里云悄然推出RPA云电脑,已与多家RPA厂商开放合作

王吉伟频道

阿里云 RPA 无影云电脑 RPA云电脑 RPA+DaaS

云服务器ECS夏日省钱秘籍,这次@老用户快来领走

阿里云弹性计算

阿里云 云服务器ECS

ABAP-屏幕切换时,刷新上一个屏幕

桥下本有油菜花

abap

【计算讲谈社】第四讲:自动驾驶,未来的移动智能载体?

大咖说

自动驾驶 阿里云 科技

单集群1万节点!腾讯云大数据平台TBDS获得分布式批处理平台万节点能力认证

科技热闻

linux下清理系统缓存并释放内存

入门小站

Linux

毕业总结

流火

C#/VB.NET 合并PDF文档

在下毛毛雨

C# .net PDF 文件合并

嗨 FUN 一夏,与 StarRocks 一起玩转 SQL Planner!

StarRocks

sql 大数据 数据库·

博睿数据一体化智能可观测平台入选中国信通院2022年“云原生产品名录”

博睿数据

智能运维 博睿数据 One 智能可观测平台

6月刊 | AntDB数据库参与编写《数据库发展研究报告》 亮相信创产业榜单

亚信AntDB数据库

数据库 AntDB 国产数据库

重磅披露!上百个重要信息系统被入侵,主机成为重点攻击目标

青藤云安全

网络安全 网络攻击防御

云小课|3种常用Git工作流推荐

华为云开发者联盟

后端 开发 华为云

华为云专家详解GaussDB(for MySQL)新特性

华为云开发者联盟

数据库 云计算 后端 算子

毕业季 | 华为专家亲授面试秘诀:如何拿到大厂高薪offer?

华为云开发者联盟

面试 工作 offer 大厂 毕业

ABAP-调用Restful API

桥下本有油菜花

abap REST API

K8S 应用部署

kubenetes

越来越多地使用 SLO 来实现可观测性|DevOps

观测云

可观测性

【6.24-7.1】写作社区精彩技术博文回顾

InfoQ写作社区官方

优质创作周报

透过华为军团看科技之变(六):智慧公路

脑极体

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