2020年,如何选择小程序框架

2021-01-04
来源:

一开始,这不是广告。

微信小程序证明,已经有4年了。从一开始,只选择本机语法,现在小程序框架Rax / Taro / uni-app蓬勃发展。其背后是小程序原生语法引起的生态碎片化。这也是企业对“一个代码和多个端点”的强烈需求,并且是当前繁荣的前端生态系统。 小程序 微信的诞生开始了

微信并不是第一个成为小程序的应用,而是小程序最具优势的应用,例如高流量,用户长时间停留等。从微信的角度来看,小程序更像是官方帐户在业务形式方面的发展演变。早先微信增强了开发人员通过sdk形式开发官方帐户网页的能力。 小程序的诞生是微信对于基于平台的超级应用程序的自身商业行为,它可以帮助用户更好地实现“轻量级Web应用程序”。

微信小程序在其诞生之初就定义了一组“标准”,这与前端的现有生态学不兼容。原始框架甚至都没有组件和npm,并且与Web生态严重脱节。由于特殊的双线程模型和四种不同的语法,开发人员很痛苦。 小程序的开业只是三方业务的开业。

模仿农场

其他供应商已经看到小程序业务的开放性,并试图使其成为基于平台的应用程序。支付宝小程序,百度小程序,淘宝小程序,360 小程序,Kuaiapp ...其中大多数都选择了与微信相同的体系结构和框架,而这并不是从从技术角度来看,但是要尽可能利用微信小程序,以便开发人员可以更快地将其平台投入使用。当然,其中两个略有不同。一种是早期的淘宝小程序,它不仅支持axml的编写,而且还支持用Vue开发的sfc。这种架构使开发人员有权在更大程度上进行选择,并且可以更好地连接到现有的前端生态系统。另一个是快速应用程序,该应用程序也使用类似于Vue的语法进行开发,但是由于它自己创建了一套标准而略有变形,这更像是对Vue的一次神奇更改,并且开发人员的开发成本没有得到有效改善。

小程序框架选择小程序本机语法和增强的框架小程序本机语法

不是必须拒绝原始语法吗?站在2020年的这个时间节点上,情况并非如此。仅就微信小程序或支付宝小程序而言,当前的小程序生态足以让开发人员使用部分现有前端生态来开发满足期望的应用程序。

与早期npm功能的缺乏相比,组件化只能通过模板渲染来实现。现在小程序已经能够实现前端工程并将某些现有概念嵌入到前端生态中,例如状态管理,CLI工程等。

换句话说,当仅将业务需求放在微信小程序或支付宝小程序上时,本机语法可以完全成为前端程序员的选择。您可以组成您的项目。您可以手动编写一个或使用社区中现有的状态管理库来精细地管理组件状态。您甚至可以直接在TypeScript中编写应用程序。简而言之,您几乎可以将习惯使用的所有内容都带到小程序域中。

逐步增强的框架

所谓的逐步增强框架,是在小程序中引入npm后,更多开放功能带来的更多收益。这种类型的框架通常仍基于小程序本机语法,但它在逻辑层引入了增强的语法以优化应用程序性能或提供更方便的使用方法。

以腾讯的开源omix框架为例,让我们简要了解一下它的用法:

逻辑层

create.Page(store, { // 声明依赖 use: ['logs'], computed: { logsLength() { return this.logs.length } }, onLoad: function () { //响应式,自动更新视图 this.store.data.logs = (wx.getStorageSync('logs') || []).map(log => { return util.formatTime(new Date(log)) }) setTimeout(() => { //响应式,自动更新视图 this.store.data.logs[0] = 'Changed!' }, 1000) } })

查看图层

<view class="container log-list"> <block wx:for="{{logs}}" wx:for-item="log"> <text class="log-item">{{index + 1}}. {{log}}text> block> view>

我们不要谈论其语法是直观还是易于使用。简而言之,它整体上保留了小程序的现有语法。但是在此基础上,它已经得到扩展和增强,例如引入了在Vue中计算出的更具代表性的代码,例如可以通过this.store.data.logs [0] ='Changed'直接修改状态。可以说,在小程序本机一半Vue一半React语法(这里一半只是一个量词)的背景下,是完全Vue的解决方案。

使用增强型框架的最大优点是,您可以使用更舒适的语法编写代码,同时仅引入最小的依赖关系并保留小程序的知识。对于仅针对特定平台的开发人员或非专业前端,这种类型的框架是更好的选择之一小程序。因为您只需要注意一些新文档和小程序自己的文档即可。毕竟,在推广某种技术的过程中,还需要考虑团队的学习成本。

转换框架

与渐进增强框架相比,转换框架的任务完全不同。转换框架的任务是使开发人员几乎不体验小程序原生语法,在更大程度上连接到前端的现有生态系统,并实现“一个代码,多个目标”的业务需求,但是最终的构建产品是小程序代码。随着过去几年的发展,转换框架的主要方面分为两种类型-编译时间/运行时间。下面将分别分析这两种情况。

Rax编译时间/芋头2.0

顾名思义,编译时解决方案的核心是通过编译和分析将开发人员编写的代码转换为小程序本机语法。以Rax编译时间和Taro 2.0为例。面向开发人员的语法是类似React的语法。开发人员编写具有一定语法限制的React代码,最后将产品1:1转换为相应的小程序代码。

以一段简单的代码为例:

Rax:

import { createElement, useEffect, useState } from 'rax'; import View from 'rax-view'; export default function Home() { const [name, setName] = useState('world'); useEffect(() => { console.log('Here is effect.'); }, []) return Hello {name}; }

转换后的

小程序代码:

逻辑层

import { __create_component__, useEffect, useState } from 'jsx2mp-runtime/dist/ali.esm.js' function Home() { const [name, setName] = useState('world'); useEffect(() => { console.log('Here is effect.'); }, []); this._updateData({ _d0: name }); } Component(__create_component__(Home));

查看图层

<block a:if="{{$ready}}"> <view class="__rax-view">{{_d0}}view> block>

编译时解决方案的最大特点是,尽管开发人员编写类似React的语法,但转换后的代码与渐进增强框架非常相似。开发人员可以清楚地看到代码在编译前后的对应关系。

简单来说,将由AST分析编译时解决方案,并将开发人员编写的JSX返回的模板部分构建到视图层中,其余代码将保留,并且然后通过运行时垫片模拟React接口的性能。

以一个简单的返回Hello world为例。如果要提取Hello world,可以编写以下分析代码:

// 省略定义 babel parser 和包装 traverse 的部分 const code = fs.readFileSync(FILE_PATH); const ast = parser(code); traverse(ast, { ReturnStatement(path) { const targetNodePath = path.get('argument'); if (targetNodePath.isJSXElement()) { // 如果 return 的子元素是一个 JSX Element 就收集 or 处理一下 } } })

targetNodePath是Hello world的节点路径。您可以自己搜索与AST相关的文章。 Babel的使用手册已经更加详细,加上此辅助工具网站基本没有门槛。

但是该程序实际上具有明显的优缺点。

优势

在此解决方案中,您可以轻松地实现与渐进增强框架相同的效果,即为开发人员提供更多的语法支持和默认的性能优化处理,例如避免使用多个setData或长列表优化等。

缺点

由于它需要在模板部分中完全使用开发人员使用的所有语法,因此这对编译时框架的实现者提出了很高的要求。因为大多数前端开发人员实际上对灵活的语法有一定的依赖性,例如使用高级组件,例如在确定条件时编写大量返回值,等等。此外,由于1:1编译转换,开发人员在开发时仍然必须遵循小程序的开发规范,例如,在文件定义中只能定义一个组件。

当前,在阿里巴巴集团内部,Rax的编译时解决方案已经实现了许多业务,包括“电影性能” 小程序等。根据开发人员的实践,如果您能够掌握编译时开发技能,那可确保最终返回模板的简洁性,语法限制实际上在可接受的范围内。

Rax运行时/ Remax / Taro下一个

与上述编译时解决方案相比,运行时解决方案具有最大的优势,可以在没有任何语法约束的情况下完成代码编写。对于开发人员来说,无疑是使用高端组件的最大吸引力!使用createProtal!但是,在小程序领域暂时不可能存在这样的好东西。这也是小程序原生语法的最后一个固执。语法限制不再带来性能上的牺牲。这与运行时解决方案的实现有很大关系。接下来,我将对其进行详细介绍。

从呈现的角度来看,此解决方案更接近于RTF呈现。逻辑层将与节点渲染信息有关的组件树传递给视图层,然后视图层判断节点类型,然后执行视图渲染。下图简要描述了整个过程:

尽管仅使用两个词进行维护,但逻辑层实际上实际上更为复杂。首先要做的是处理节点之间的关系并模拟各种行为,例如appendChild / removeChild / updateNode来操纵VDOM树。第二个更重要的事情是模拟事件。在逻辑层中,每个节点类都继承自EventTarget基类,与W3C相同。然后,将nodeId用作标识符以收集需要监视的事件。当视图层通过动作触发某个事件时,每个节点发生事件后,通过本机小程序事件中的event.currentTarget.dataset.nodeId获取目标节点的ID,最后触发目标回调。

由于本文的篇幅,我将不更详细地介绍每个部分的更具体的实现。有兴趣的学生可以通过Rax或npm init rax演示的源代码启动一个项目,以通过最终产品学习整个原理。

在此阶段,即使对于运行时解决方案,也存在不同的实现思路。通过模拟Web环境,Kbone(Rax运行时解决方案是从Kbone转换而来的)和Taro Next都完全连接到前端生态系统,而Remax只是通过react reconciler连接了React和小程序。

从业务需求的角度来看,我认为Rax和Taro Next可能比Remax更加开放。首先,有必要考虑上诉的三部分。 (1)没有语法上的限制。由于没有语法上的限制,为什么不能在前端以更熟悉的方式开发它,也就是有权操作DOM;(2)DSL耦合,尽管在阿里巴巴集团内部,React的认可度更高,但是从实现原理的角度来看,与某个框架进行强绑定绝对不是最佳解决方案;(3)旧的Web业务迁移,我们面对的许多开发人员今天,由于业务压力或其他情况,需要将其原始网页迁移到小程序,因此最好使用模拟的Web环境解决方案。根据我们的测试,大多数业务几乎可以无缝迁移。

H!说了这么多漂亮的话,运行时解决方案确实不错,但这不是救星,让我谈谈它的缺点。缺点1:数据传输量很大,我们需要将完整的组件树从逻辑层转移到视图层;缺点2:页面上有大量的侦听器,每个组件都需要一直侦听所有事件,并且事件会不断触发。在此过程中,确实需要触发的事件通过nodeId进行过滤缺点3:模板递归渲染,如果使用本机语法,则本机框架可以在渲染之前知道页面的近似结构以优化渲染,但是如果仅通过类似的信息,就很难判断其实际结构页面。

组合

虽然鱼和熊掌不能同时拥有,但每个都可以拥有一半。同样,本文不是广告。如果编译时和运行时解决方案共存怎么办?基于陶县前端高度现代化的工程积累,开发人员习惯于通过块来构建项目。更大的好处是,Rax积累了编译时解决方案和运行时解决方案,我们希望能够结合使用运行时解决方案和编译时解决方案。具有复杂基础或性能要求的模块在编译时实施。然后将其以npm包的形式引入运行时项目,这有效地减少了运行时解决方案的性能损失,并可以确保大多数业务场景可以使用不受限制的语法来完成,并且开发人员将面对Rax DSL。

通过演示查看它:

// 这是一个倒计时组件,通过编译时实现,然后发布为 rax-taobao-countdown import { createElement } from 'rax'; import View from 'rax-view'; function CountDown(props) { // 省略各种逻辑... return {day}:{hours}:{minutes}:{seconds} } export default CountDown; // 运行时项目 import { createElement } from 'rax'; import CountDown from 'rax-taobao-countdown'; function Home() { return }

假设我们的倒计时组件结构非常复杂,并且需要极高的交互性。然后,开发人员可以通过编译时解决方案开发高性能的CountDown组件,然后在运行时项目中引入并使用它。此时,视图层获得的节点树信息大致如下:

{ "tagName": "custom-component", "type": "element", "behavior": "CountDown", "children": [] }

不再有更深入的节点信息结构,可以有效避免上述运行时解决方案的缺点。

网络就是未来

小程序本机语法绝对不是小程序或下一代渲染方案。通过微信小程序现有的语法规范来绑架开发人员只会使更多的人想突破围困。 微信小程序似乎已经意识到这一点。从当前迭代来看,微信小程序引入了越来越多的Web上已经存在的事物,包括通过wx在视图层中在一定程度上操纵DOM的能力,甚至获得逻辑层组件实例等的能力,这可以为现有的转换框架提供更多的可能性。但是,如果小程序在一开始的设计不是很糟糕,我们可能会丢掉工作(开个玩笑)?

对于业务开发人员而言,“一个带有多个终端的代码”是最有效的。当今的业务需求可能只放在小程序容器上,明天的需求可能放在Web上,甚至将来也可能放在Flutter上。 Web是最接近前端开发人员的,具有组织化的保证(W3C)规范。因此,在2020年的这个时候,框架提供商和业务开发人员都应该从标准的角度考虑问题,以便业务代码具有更多的可能性。

摘要

自小程序诞生以来已经过去了很多年。如何在2020年为您的业务选择合适的小程序框架?这就要求开发人员在权衡利弊之后做出选择。因为每个业务的形式不同,并且应用程序的生存时间也不同,所以最好根据自己的需求进行选择。本文仅从全局角度分析所有类型的框架,希望让那些正在阅读本文的人不要那么纠结〜

招聘

如果您对我所说的“一个具有多个端的代码”或前端体系结构感兴趣。您可以考虑加入我们。该团队目前拥有多个方向,例如终端架构,Node架构和无服务器R&D平台。

联系电子邮件:fushen.jzw#(#=> @)

分享