前端移动端框架选型摘要
调研对象目录对比图Tarouni-appMUIFlutter
公司
京东
Dcloud
Dcloud
框架/语言
Vue / React
Vue
JavaScript
Dart
性能
⭐️⭐️⭐️⭐️
⭐️⭐️⭐️⭐️
⭐️⭐️⭐️
⭐️⭐️⭐️⭐️⭐️
热更新
✅
✅
✅
生态
⭐️⭐️⭐️⭐️
⭐️⭐️⭐️⭐️⭐️
⭐️⭐️⭐️⭐️
⭐️⭐️⭐️
插件数量
在 Taro 的官方物料市场
在 DCloud 的官方插件市场
在 DCloud 的官方插件市场
更接近原生
跨平台
H5
✅
✅
✅
✅
iOS
✅
✅
✅
✅
安卓
✅
✅
✅
✅
各类小程序
✅
✅
✅
百度指数
开发体验
在满足用户业务需求的前提下,我们谈谈开发者的需求,从如下几个维度比较:
平缓的学习曲线:简单易学,最好能复用现有技术栈,丰富的学习资料高效的开发体验:现代前端开发流程、工程化支持高效的社区支持:遇到问题,可很快的寻求到帮助活跃的开发迭代:框架处于积极更新升级状态,无需担心停更
如图我们可以看出,Vue 在国内的热度远超两大前端框架,也与其学习曲线有关,Vue 只需要一小部分的学习曲线,React 则是陡峭的学习曲线,当然大家都希望 angular 简单点,编程的时候简单点。
性能分析
Flutter 作为界面库(注意它只是界面库,Dart 语言是另一个项目),它唯一要干的事情就是渲染界面。不像 HTML5,Flutter 界面库连视频、定位等都没有,就是一个纯排版引擎,绘制文字、按钮、图片等常用界面控件。
这个排版引擎的特点是简单、高性能。
在 3 大主流渲染引擎里,Webview、react native/Weex、Flutter,复杂度依次降低,渲染性能依次上升。(uni-app 是双渲染引擎,Webview 和 Weex 都内置了,随便开发者使用切换)
所以我们要清楚,提升性能是有代价的,你究竟想要灵活丰富的 css3,还是想要固定 flex 模式排版,抑或是最简单但高性能的 Flutter 排版?开发便利性和运行性能不可兼得。
同时我们要明白,性能的差别,并不是因为 Google 的 chrome 团队、Android 团队的技术比同公司的 Flutter 团队差。而是 Flutter 提供的布局写法是被限制过的,解析快,所以渲染快。别忘了 Webview 的排版引擎也是世界级工程师用 c 写的。
但通过这种方式提升性能的代价,就是布局复杂的界面时,Flutter 的代码嵌套的让人崩溃。
我们先举个例子,同样的界面,用 HTML 和 Flutter 如何实现:
HTML 代码片段
<div class="greybox">
<div class=redbox>
smaple text
</div>
</div>
.greybox {
display: flex;
align-items: center;
justify-content: center;
background-color: #e0e0e0; /* grey 300 */
width: 320px;
height: 240px;
font: 18px
}
.redbox {
background-color: #ef5350; /* red 400 */
padding: 16px;
color: #ffffff
}
DART 代码片段
var container = new Container( // grey box
child: new Center(
child: new Container( // red box
child: new Text(
"smaple text",
style: new TextStyle(
color: Colors.white,
fontSize: 18.0,
),
),
decoration: new BoxDecoration(
color: Colors.red[400],
),
padding: new EdgeInsets.all(16.0),
),
),
width: 320.0,
height: 240.0,
color: Colors.grey[300],
可以看出,Flutter 没有标签和样式的写法,更没有选择器,从头到尾只有 Dart 语言,它的界面控件是用 Dart 代码 new 出来的,每个控件的样式,是在 new 的时候设置的类 json 写法的参数。
如果我们要嵌套布局,就要循环地在 Dart 里添加 child,同时在 Dart 里设置 child 的样式参数。如图(DART 代码片段)虽然只是嵌套了一层,但实际开发中,dom 要嵌套好多层,想象那样的代码。。。所以大家都诟病 Dart 是“嵌套地狱”。
或者可以这么理解,这是一个只有 JavaScript,没有 Html 和 Css 的浏览器。你需要用 JavaScript createElement 来创建元素,用 JavaScript 的 style 方法给每个 element 设 style,反正就是不能写 Html 和 Css 代码。前端都已经发展到各种 MVC 等视图逻辑分离的架构了,也有了 Vue 组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应 Dart 这种低效的界面开发模式?从开发模式来讲,这确实是一种倒退。
浏览器的 Html 提供了标签和样式分离的写法,还有各种各样的选择器,但其实这也是有代价的。它导致 Webview 初始化时要同时先启动 Webkit 排版引擎来解析这些编写随性的 Html、Css,同时还要启动一个 JavaScript 引擎比如 V8 或 jscore 来解析里面的 JavaScript。
而 Dart 就很简单,只启动一个 Dart 引擎,解析严格的 Dart 语法,它不会去操心有些标签未闭合要如何容错,不会判断宽度 320 后面是 px 还是 rem 或者是动态计算百分比。
对比这 2 个引擎初始化时要干的事,差别简直太大了。
所以从解析效率上,Flutter 肯定比 Webview 要高。但从编码灵活性上,Flutter 写的代码,嗯,难看而低效!
Flutter 使用的也是 flex 布局思想,这是一个强嵌套布局模型,比 Web 常规排版引擎的嵌套更多。当界面复杂时,Flutter 的代码要嵌套几十层,每层的元素的 json 样式都和元素一起混写在 Dart 代码里,让人崩溃。
有人提出是否可以通过一种预编译的 DSL 来简化写法,让 Flutter 的开发不这么痛苦。但这个难度太大了,从严格转换为松散是简单的,从松散转换为严格几乎是不可能的。
什么意思呢?比如 Flutter 代码转换 Web 代码,是很简单的,Flutter 已经自带了这个功能。但是想反过来,那可难了。
类似的还有,把 TypeScript 转为 JavaScript 是容易的,反之,不是绝对不可行,但会复杂到你宁愿去重写一套 TypeScript 代码。
Flutter 的性能高,除了简单严格,还有一个特点,就是逻辑层与视图层统一,运行在同一套 Dart 虚拟机下。
我们知道 ReactNative 和 Weex,也是原生渲染的,它们的性能高于 Webview。但同为原生渲染的,怎么会慢于 Flutter 呢?其实不是原生渲染慢,而是 JavaScript 和原生通信慢。
ReactNative 和 Weex 都采用了独立的 JavaScript 引擎(iOS 是 jscore,Android 是 V8,最新版 ReactNative 开始在 Android 上搞自己的 JavaScript 引擎 Hermes),从 JavaScript 与 Dart 的比较上,性能稍逊一筹。但这不是主要问题,因为 V8 的 JIT(Just In Time,混合使用编译器和解释器的技术)不是盖的,也是编译为原生代码解析的。性能上的主要问题是:ReactNative,Weex 的 JavaScript 引擎和原生渲染层是两个运行环境。
当 JavaScript 引擎联网获取到数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,当用户在屏幕上操作原生视图层时,要给 JavaScript 引擎发送通知,也会产生这个通信折损。
不过这种性能差别,在大多数场景中,用户是感受不到的。比较影响的场景,是跟手式的 JavaScript 响应操作绘制帧动画,或者说 JavaScript 连续操作界面元素方面,Flutter 折损更少。
这个通信折损,其实普遍存在于所有逻辑和视图分离的框架中,包括各家小程序也有这个问题。
为了解决 ReactNative 上 JavaScript 绘制动画卡的问题,曾经的 ReactNative 拥趸 Aribnb 搞了一个 Lottie 的动画库,但 Lottie 只能静态执行,无法跟手交互。Weex 更进一步,搞了个 BindingX,这个技术很赞,它可以预定义规则,让用户界面在原生层交互时通过预定义规则直接响应,而无需传递给 JavaScript 层。在需要短时间内来回通信的场景时,可以使用 BindingX 这类解决方案。它的性能和灵活性比 ReactNative 更强了一些。
在 uni-app 里,nvue 页面可以直接使用 BindingX。至于 uni-app 的 vue 页面不是基于 Weex 渲染的,它遇到通信折损时,解决方案叫 WXS,WXS 是一种运行在视图层的 JavaScript,它的性能和和灵活性都非常高,完全可以达到 Flutter 的水准。
说回来 Flutter,它只有一个 Dart 引擎,没有来回通信产生的性能问题。不过任何事情都是有利有弊的,Flutter 在普通的界面绘制上效率虽然高,但一旦涉及原生的界面,反而会遇到更多问题。
前面已经说过,Flutter 只是一个基础排版引擎,缺少很多能力,当我们需要在 Flutter 界面上内嵌一个原生的视频播放扩展控件时(Flutter 没有内置视频播放能力),或者原生的高德地图 sdk,那么在拖动视频进度时、拖动地图时,Flutter 一样会产生原生和 Dart 之间的通信,造成性能损耗。
事实上,由于 Flutter 是在一个类 canvas 环境绘制的,想把一个原生控件嵌入 Flutter 的布局里某些元素之间去排版,还不是一件容易做到的事情,坑很多。
每个人都想要一个像 Css3 那样灵活写法的布局引擎,他们给 ReactNative 和 Weex 提需求,给 Flutter 提需求。殊不知,让这些产品团队实现了 css3 时,他们的性能优势已经不再了,他们相当于又实现了一遍 Webview。这种无意义的需求,他们是不会受理了。
性能好,有个度,客观地讲,ReactNative/Weex 调用原生渲染的性能,和 Flutter 的渲染性能包括 uni-app 在用户体验上并没有明显区别,甚至在很多场景下,和 Webview 渲染的小程序也没有明显区别。
也简单说说 Webview 渲染小程序,为什么性能高,核心是预载。点击一个新页面时,Webview 是提前创建好的,不会走复杂的 Webkit、V8 的初始化流程,连开发者的 JavaScript 代码,也是预载好的。所以点击新页面时,它的渲染速度和原生应用没什么差别。当然也有个坏处,就是启动慢。微信里启动小程序速度看着还行,其实是微信在启动小程序之前,就已经提前初始化了小程序运行环境。
关于构建
Android 打包,步骤和 iOS 大同小异
构建小程序
Taro 和 uni-app 都非常丝滑,一段代码即可。这里强烈推荐 uni-app,不仅支持手动发行微信小程序,还支持命令发行。
CLI 发行uni-app到微信小程序
仅编译uni-app项目到微信小程序,不发行
cli publish --platform mp-weixin --project 项目名称
编译uni-app项目到微信小程序,并发行小程序到微信平台
cli publish --platform mp-weixin --project 项目名称
--upload true --appid 小程序appid --description 发布描述
--version 发布版本 --privatekey 小程序上传密钥文件
总结
MUI 垫底,按照目前框架的趋势并不是明智的选择
Taro 在 2.0 之前一直使用的前端框架是 React, 直到 3.0 之后才开始支持 Vue 并支持最新的 Composition Api,但是基于社区支持这一方面还是比 uni-app 略逊一筹,物料市场更是少得可怜。
Flutter 用一句话来总结,如果只追求性能毫无质疑的选择 Flutter,但是如果涉及到小程序,和类似于百度地图等插件会十分让人头疼,而且开发难度是指数级增长,和前文提到的平缓的学习曲线大相径庭。
uni-app 无论是一端多用,还是性能优化都处在中上水平,虽然不能和原生直接渲染图像层那么丝滑流畅,但是瑕不掩瑜。毕竟鱼和熊掌不可兼得,你不可能又要一端多用,又要性能强悍,我相信如果真出了这样的框架那么我的这篇选型直接贴上框架的名字,后面只跟一句,还用选么?还有个重点就是开发打包需要使用 HBuilderX,其实我很排斥 VS Code 以外的代码编辑器,因为会存在很多的隐藏风险,所以下载尝试并打包了一些 APP 应用和小程序,非常丝滑且便捷,有点士别三日当刮目相待了,毕竟以前的 HBuilder 用过的都知道有多坑。
基于公司业务及团队人员技能考虑
橱窗里的衣服再漂亮,适合自己的才有用,开发框架亦是如此。
我们根据业务需求及团队成员现状,形成如下对比:
因此,我最后决定使用 uni-app 作为新项目的前端移动端开发框架。
暂无评论内容