前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >干货 | 揭秘携程三端通用框架中的CRNWEB

干货 | 揭秘携程三端通用框架中的CRNWEB

作者头像
携程技术
发布2018-07-05 16:06:33
1.4K0
发布2018-07-05 16:06:33
举报
文章被收录于专栏:携程技术携程技术

作者简介

郑勇,携程高级技术经理,目前主要负责CRNWEB框架的开发工作,以及在携程内部的使用推广和性能优化。

前言

React-Native自从2015年推出,就一直火到了现在,一度在技术圈言必RN,激发一波广泛的思潮。携程基础业务研发团队迅速跟进,在React-Native基础之上,开发出了CRN这一适合携程业务高速发展的、抹平了iOS和Android端组件开发差异的、做了大量性能提升的框架。然而无论是CRN还是React-Native本身都无法解决移动板块中的一大版图——WEB平台。

而现实是:存在大量的业务需求需要三端的支持,单独再开发一套H5成本高昂,后期的维护成本也很高,需求同步难,用户体验不一致等问题都会非常明显,而携程基础业务前端框架团队一直都在致力于解决iOS和Android之后,将BU业务代码无缝接入WEB平台的技术方案,于是CRN-WEB(简称CW)应运而生。

一、CRNWEB是什么?

CRN-WEB的使命就是在CRN和React-Native的基础之上,构建一个三端打通的平台,能够实现BU的一套业务逻辑代码,能够根据平台情况运行在三端之上,并带来用户体验上的一致性(和React-Native保持一致)和优越性(使用Virtual DOM,PWA等技术提升性能)。

1、设计共性

对于CRN-WEB这样一个框架,我们在设计之初就可以提取一些软件设计方面共性的问题:

1)易用性,CW框架必须简单易用,大幅度降低开发成本、运维成本和学习成本,将是这个框架的核心价值,如何做到呢?

2)一致性,和现有技术框架的集成问题,即如何将CRN-WEB与CRN和React-Native进行友好的集成,各自发挥各自的功能,如何保证各平台间的一致性?

3)稳定性,React-Native版本迭代迅速,版本间差异较大,既然三端打通,共用BU源码,那么BU的React-Native项目或者CRN项目在接入CW框架后,必须能够稳定运行在WEB平台上,如何保证项目稳定运行?

4)兼容性,WEB平台是非多(浏览器厂商多,版本多,私有规范多,差异多...),兼容性问题一直是WEB项目开发头疼的事情,如何处理好兼容性问题?无疑是非常棘手的。

5)扩展性,包括React-Native本身都还在不断的变动,增加新功能,再加上公司级别的功能性需求,业务级别的功能需求,将令如何保持框架扩展性变得非常麻烦。

2、我们的设计思想

That‘s a big business,的确,这些问题很难处理,但是经过深入的思考,我们提出了这样的设计思想。

React-Native为解决iOS和Android两端兼容提供了解决方案,它是如何做到的呢?当然RN团队经过了大量的工作和思考,最终他们提供了一套规范,即React-Native,与其说它是一个框架不如说它是一套规范,对,我就是这么认为的。

如果CRNWEB的设计也基于React-Native的规范,把React-Native抽象成一个逻辑层,为不同的平台提供相同的Component和API输出和相同的APP主要运行流程,然后在规范之下各个平台各自实现,即iOS Implement,Android Implement,WEB Implement,那么从设计上来看是比较完美的。

对于业务方而言如Flight项目,Hotel项目等等,无需关心底层的技术实现,使用React-Native这一套开发技术体系基本上就足矣。

3、设计优势

这样设计同时还可以解决好几个问题:

比如易用性,我们采用了React-Native的规范,那么我们就可以使用开发人员熟悉的技术,熟悉的规范,熟悉的知识,熟悉的流程,无需额外学习太多其它规范和技术栈。

否则BU的学习成本,接入成本太高,起不到降低开发成本的作用,当然为了解决易用性,还有很多其它方面的工作,比如提供一整套的开发流程,开发工具,发布工具,技术支持等等。

再比如一致性问题,和React-Native,CRN使用相同的规范,这样的设计保持了天然的一致性。

二、CRNWEB是如何工作的呢?

我们依然从程序设计的传统,Hello wolrd开始。

熟悉React-Native的同学可能一眼就能够看出来,这完全就是React-Native的原代码,你说的对,它不仅是一份RN的源代码,也是一份CRN-WEB的源代码。它虽然是一个最简单的Hello World,但是它几乎包含了React-Native的Component和API,以及主要的运行流程。

1、主题结构分成三个部分:

1)头部的依赖部分,使用ES6的语法import,导入依赖的程序包React和React-Native;

2)中间部分实现模块主要逻辑;

3)尾部使用ES6语法export导出模块输出;

在CRN-WEB中也是这样,毫无差异。

2、那么CRNWEB是如何让和React-Native相同的源代码运行在Web平台的呢?

要实现这种能力,那么它必须满足两个最重要的必要条件。第一点,我们要实现在Web平台上面,跟React-Native上面具有相同功能的Component和API,比如这里的View和Text,这个就是我们后面要讲到的组件系统。

第二点,我们要有一种机制使得我们的React-Native原代码能够在Web上面运行起来,调用我们WEB平台上的Component和API,使得我们对代码拥有足够的控制能力。这个就是我们后面要讲到的打包系统。

三、运行分析

HelloWorld代码编写完成,配置好环境,执行CRNWEB命令,查看编译后运行效果和运行结果。

1、入口组件

CRNWEB仍然使用了AppRegistry作为程序入口注册组件,当然这里的AppRegistry已经被换成了AppRegistry.web这个WEB版本的Implementation,AppRegistry实现了registerComponent作为程序入口,承担App初始化工作,例如:

1)运行环境初始化,例如识别是h5还是hybrid;

2)注入默认的全局性样式,例如抹平浏览器差异的样式;

3)全局性请求参数的解构和传递;

4)初始化全局性组件的容器等等;

2、同步组件的异步转换

HelloWorld组件就是一个标准的React-Native组件,在CRNWEB中为了提高性能,将HelloWorld组件转化为异步组件HelloWorld(__CRNWEBFUNCTION__),从而实现页面级别的按需加载,仅在需要的页面运行时进行加载。

这在WEB环境下是非常重要的一项优化,这是专门针对WEB环境下脆弱的网络环境而作出的改进,特别是在页面众多,组件数量大,组件体量大的较大型WEB项目中,性能提升非常显著,这在BU的实践中得到了的认可。

3、具体的业务逻辑页面的编译转化

而原来的HelloWorld业务逻辑被打包到了模块号为97的package中,并处理好了它的依赖,如下:

我们可以看到原来的ES6语法书写的代码被编译成了ES5语法的代码,因为ES5在WEB环境下有着更广泛和友好的支持,兼容性更好。而HelloWold中引入的View,Text,StyleSheet等等组件,也全部变成了WEB版本的具体实现,这里使用了一招瞒天过海。

4、组件系统

而View,Text等等众多的React-Native原生组件对应的WEB版本的具体实现,就构成了CRNWEB的组件系统,篇幅有限不做展开。

5、样式处理

而HelloWorld里引入的StyleSheet就是样式处理系统中的入口文件。

CRNWEB的样式处理系统我们主要提供四种方式:

首先是APPRegistry,我们需要注入一些默认的全局样式,这个前面已经有所提到。后面三种其实都是对于组件样式的处理。

第二种是对组件的默认样式,可能有一些组件,历史的组件,我们也给它提供了这种能力。

第三种是一种预处理,组件样式的一个预处理,基本上都要用到StyleSheet.Create,这个和React-Native保持一致。

第四种我们对样式的一个实时处理系统。

样式处理系统的任务就是处理样式的问题,包括但不限于:

1)平台间样式的差异性,比如Border,在React-Native下,它是分散的每一个属性值进行一个独立的编写,而在Web上面它的Border是一个混合制,所以这就是平台之间的差异,CRNWEB框架就会开一个任务去对它进行修复。

2)浏览器间的差异,比如有的浏览器支持FlexBox,有的不支持,而且即使是支持FlexBox,支持的程度,版本也不一样,这些都是需要具体处理的修复任务。

3)一些共性上的问题,如单位处理,颜色处理等等。

4)一些差异性样式问题,如前缀处理,视口问题。

5)Web不支持的样式,如BoxShadow的实现等。

6、事件处理

CRNWEB中还有非常重要的一大块逻辑就是事件处理,我们专门提供了一个事件处理系统来进行处理。

我们使用了PanResponder,它提供一个对触摸响应系统的Responder的可预测的包装,和React-Native保持一致的事件处理流程,所以在事件的处理流程和兼容性方面和React-Native保持了高度一致性。

四、打包系统概述

最后CRNWEB的一大重头戏就是打包系统。

1、打包任务

CRNWEB打包系统的任务非常多,从流程上看,大概分为以下几个阶段:

1)Prepare阶段,需要对它进行入口检查,版本检查,环境检查以及第三方的依赖检查等等,各种的预先准备条件都在在这个阶段进行处理。

2)进入到Webpack的打包构建流程,我们编写了很多Webpack的插件,对它打包进行各种处理和优化。

3)构建过程当中会去调到Babel,利用Babel对原代码进行编译,对语法进行处理,对于代码的同步、异步转换这样一些比较核心的内容,都是通过编写的Babel插件对原代码进行处理实现的。

4)进入到Create阶段,因为有的Bu需要生成JAVA工程,有的需要.Net的工程,还有的只需要一个Static静态工程,在这个阶段需要对它进行一个工程的一个创建。

5)对这个工程进行启动,我们提供了开发版和生产版,他们的侧重有所不同。像开发版的话,它的主要诉求是打包编译的速度要快,这样才可以提高效率。而对于生产版它最核心的需求就是,要使你的size最小化,使你的运行效果最好。我们使用了很多优化手段对它进行了处理。

6)最后涉及到的一块,需要对它的size,它的依赖进行各种各样的优化。我们实践下来发现,BU代码量是非常非常多,业务也是非常非常复杂。怎么办呢?我们对业务工程进行size的分析,依赖分析等等各种更深入到代码层面的分析和处理,从而寻找到最佳实践的解决方案。

2、一些关键优化点

随着业务蓬勃发展,页面越来越多,组件越来越大,无论对于Native还是对于Web来说,这都是无法回避的挑战,精简打包size成为重要工作,对于size这一块我们做了很多优化处理,包括但不限于:

1)对于React,进行了优化和增减,以及一些切入式的处理,只保留需要的部分。

2)使用了tree shaking技术,排除掉了很多死代码。

3)对组件进行高级别抽象,增加重用度。

4)减少组件层级,简单而有效的方案,既减少size又提升性能。

5)运用各种cache技术,提升用户体验。

另外我们使用了一些工具,能很好的将项目中的模块依赖关系呈现出来,比如说Log这个模块被哪些页面引用,首页这个页面引用了哪些具体的模块(如:FStyleSheet,Log,utils,LinearGradient.web等等),模块有多大多少个,都可以非常清晰的展示出来。这样就非常方便对代码进行优化和处理,并使数据可视化了。

我们现在项目有多大,它的主要代码组成结构是什么样的,它的每一个模块,每一个依赖,每一个组件size占比多少,都可以进行精确的数据分析。比如说最大的模块,你为什么最大,你包含了哪些业务逻辑,是不是必须的。这些数据都可以进行再一步的思考。

CRNWEB目前已经支持到了React-Native的最新版本0.54版本,React升级到16.2版本,已经有众多页面升级上线。

最后看看实际项目运行效果对比:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 携程技术中心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档