18

体验的升华:Weex

 5 years ago
source link: https://mp.weixin.qq.com/s/mAUrzOVU4nFHY4QRU7EZMA?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Ur6Vr2j.gif

作者马姐姐、熊孩子(企业代号名),目前负责贝壳平台技术中心SaaS&客源的前端研发工作。

1 背景

当你打开一个H5页面时,是否讨厌等待?生硬的跳转是否让你倍感突兀?是否想要拥有更极致的体验?为了给大家提供贴近原生的加载速度与流畅度,提升大家的使用体验,最近两个月在研究weex这个框架,尝试把它接入组内的项目,并实现体验的升华,现在从理论到实践为大家介绍一下我们的心(cai)路(keng)历程。

2 WEEX初识

2.1 weex是什么

前端同学对weex这个名词一定不陌生,没用过也一定听过。它是阿里在2016年开源的跨端解决方案,通过编写一套web代码,就可以构建出可以运行在Android,iOS以及web端三个平台的应用程序,所谓"Write once, run everywhere”。可以选择使用Vue.js框架的语法开发weex代码,也可以使用Rax,无论是哪种语法,经过编译都可以被app中的weex sdk所解析,并在底层以Native的形式渲染。

weex框架提供一些内置的渲染组件(components)和模块(modules),并支持自定义扩展。开发时,渲染组件通过标签的形式被使用,如 <div> 是基本的渲染容器, <list> 是滚动列表,框架通过对组件高效的内存管理,提供平滑和流畅的渲染效果。模块则是一些功能的封装,如网络请求,路由导航,数据存储等。weex框架屏蔽了组件和模块在不同环境下的差异,例如在weex运行模式下组件以原生组件的形式存在,在h5环境下则是DOM在渲染。

2.2 编译产出

weex在开发时以web语言为基础,编译使用前端熟悉的webpack就可以完成,官方提供的weex-loader负责将源码转换成jsbundle。WEEX项目经过编译产出两部分代码:

  1. 面向Android,iOS的jsbundle,通过app的sdk进行加载

  2. 面向H5的前端代码,运行在webview或浏览器

WEEX官方提供了开发脚手架weex-toolkit,通过它可以初始化带有webpack编译配置的weex项目(create),对开发的模块(.we或.vue文件)进行预览(preview),添加ios/android平台(platform)并运行相应的平台来查看真实app中的运行效果。脚手架的使用可以在官网查看,在此不进行赘述。对weex的所有的尝试几乎都是从脚手架初始化一个项目开始的,官网这部分介绍不多,在学习的过程中也比较迷惑,因此下面简单分析一下这个初始项目。

初始项目目录如图1.1所示,与一个普通的web项目几乎一样,其中web目录存储开发及h5所用的html,configs里是webpack的配置文件,如果添加了平台会在platforms下存放相关android或ios的代码。再查看它的package.json就有点懵了(图1.2),这些命令从大体上能看出有开发用的dev和serve,生产环境构建用的build,那么pack是什么呢?build后各种参数有什么区别?构建jsbundle和h5的资源分别调用哪个命令?通过试验及分析webpack配置,总结一下各命令的作用及产出。

MbqYZ3M.jpg!web

图1.1 初始项目目录

muURVrn.jpg!web

图1.2 运行指令

rYryE3u.jpg!web

图2 预览preview效果

1)开发(dev & serve)

webpack的构建是基于入口entry的,每个.vue文件都会被作为entry, 针对每个入口都会构建出相应的jsbundle及web资源。启动server后,jsbundle通过 http://local_ip:8081/dist/entryname.js 访问,对应的web资源的js通过 http://local_ip:8081/dist/entryname.web.js 访问。如果web文件夹下存在入口同名的html模板,就可以在 http://local_ip:8081/entryname.html 查看web渲染的效果了。server命令启动时自动打开preview.html预览页面(图2),可以使用官方提供的weex-playground应用来扫码,查看jsbundle在app中被加载的效果。dev和server的区别在于,server启动了一个端口为8081的本地服务器,dev则将所有资源构建到了项目.temp文件夹下。

2)发布(build)

BnU3UvE.png!web

3)打包app(pack)及运行

脚手架weex platform add相关的命令,会在platform目录产出一份android或者ios的原生app代码,该app实现了通过weex sdk加载当前项目的jsbundle。安装好相应的运行环境、如android studio和xcode,就可以执行npm run ios或npm run android将app运行起来。pack相关的命令则是将最新的项目代码编译出jsbundle,并移入app的存储目录。

3 WEEX小试

基于上面的理论基础,尝试搭建demo来探究使用WEEX开发项目的可行性,以链家首页为参照,进行WEEX demo的开发(包括网络请求、轮播、列表、滑动、跳转,tab切换等),以下列举了在开发中遇到兼容性问题(表2),虽然过程中遇到了一些问题,但页面呈现的效果和体验也是非常优异的(图3)。

EJFBv2E.jpg!web

表2 页面构建小tip

Vfmaeyz.jpg!web

图3 效果图

一般项目流程中,我们需要对不同的构建环境进行逻辑区分,比如接口的域名。在weex中由于相对路径是基于JSBundle或是本地(缓存后)的,所以我们不能使用相对路径调用后端接口,需要区分构建环境来进行配置。官方只给出开发环境(dev)与发布环境(prod),测试环境(test)需要自行添加,在区分构建环境时也遇到了一个小问题,webpack的配置文件对构建环境设置发生了相互覆盖,无法正确的区分的构建环境(已提issue,官方已修复)。

aMNFjey.jpg!web

图4 环境区分小tip

经过了这两个步骤,页面的本地构建部署就可以完成了。那怎么真正的实施上线呢?

4 WEEX实施

4.1 更新缓存方案

当每次功能上线时,会进行CND刷新,更新资源。并且考虑到weex页面渲染可能失败,就要回退到相应的h5页面,我们设计了weex项目的协议形如 wx://jsbundle_url?h5_url 。借鉴H5的离线包的思想,jsbundle应该被缓存在app本地,下次渲染时如果远程内容没有更新,则使用本地版本,从而减少网络请求大小,加快展示速度。构建后的jsbundle是不带md5后缀的,所以起初我们想做一个版本控制平台来管理各个jsbundle的版本,但是这样会增加app端的请求次数,需要先请求版本平台获取最新的版本号,如果与本地版本不一样、再去请求jsbundle的资源,反而得不偿失。

后来想到了可以利用HTTP缓存,还记得200和304状态码吗?让我们复习一下HTTP缓存策略:

  • 强缓存:请求不会发送到服务器,直接从客户端缓存中获取。

  • 协商缓存:请求发送到服务器,由服务器判断是否从缓存中获取。

我们可以利用协商缓存,让app端通过构造不同的请求Header,去cdn检查版本更新。请求jsbundle时记录Response Header的ETag值,该值是服务器生成的每个文件的唯一标识,资源更新该值就会改变。再次请求时,在Request Header里用If-None-Match头把存储过的etag值携带给服务器,服务器会根据该值判断返回304 Not Modified还是200 OK。返回304时响应body没有数据,从而减少了传输时间,200时响应body为最新的文件内容。无论返回304还是200时,response header都会携带新的Etag,即使文件可能没有变化,app端需要重新记录该值。

因此,app客户端加载jsbundle、降级h5、及资源缓存的整体流程如下图所示:

vQfeqyV.jpg!web

图5 weex渲染流程

4.2 屏蔽差异

一般的H5页面与native交互主要使用JSBridge提供的一些API,native则为weex页面提供了自定义module,那么weex在三端运行时,为了保证与native交互的统一性,我们对native提供的moudle与JSBridge进行了封装,称为weexBridge。保持了一致的调用方式,屏蔽不同运行环境下与native交互的差异。下图展示了weexBridge中通过weex.config.env.platform来判断当前运行环境,从而调用底层API提供相同的功能。

Eneu2uF.jpg!web

图6 WeexBridge

5 尾声

5.1 WEEX vs RN vs Flutter

看了这么久,大家一定会有一个疑问,为什么选择了weex,下图简单的对Weex与RN、Flutter进行了简单的对比,由图可以看出weex相较其他而言简单易上手,学习成本低,性能与可维护性比较高,所以相对简洁的H5页面,weex更适合,当然大家可以根据兴趣结合自己业务特性选择最适合的框架。

aAB7vyM.jpg!web

图7 WEEX vs RN vs Flutter对比

5.2 总结

经过过一系列的实践,我们已经成功推进了一个B端WEEX项目的上线。基于公司已有的工具之上,探究了WEEX项目的开发、构建、发布等流程;输出了开发中屏蔽多端交互api的Bridge工具。在性能上,通过缓存机制达到了一次加载后续秒开的效果。

我们还有一些后续计划如下:

1)模板融入公司构建工具

2)性能的测量及优化

3)业务组件库

4)RAX语法的尝试

希望通过不断更新优化实现更加极致的用户体验。

6 参考资料

1)WEEX官方文档:
http://Weex.apache.org/cn/guide/

2)WEEX官方UI库:
https://alibaba.github.io/weex-ui/#/cn/packages/wxc-tab-page/

3)stackoverflow上Weex讨论:
https://stackoverflow.com/questions/tagged/weex

4)WEEX与RN:
https://blog.csdn.net/aptentity/article/details/68488585

5)WEEX/RN/Flutter:
https://www.jianshu.com/p/e747f64b8d38?from=singlemessage

6)浏览器缓存参考:
https://www.cnblogs.com/wonyun/p/5524617.html

7)缓存方案参考:
https://www.jianshu.com/p/c8f1fbf1db5e

作   者:马姐姐、熊孩子(企业代号名)

出品人:漠北鹰、丸九(企业代号名)

---------- END ----------

推荐阅读

为什么前端监控要用GIF打点

service worker实现离线缓存

fEV3imE.gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK