00:00
哈喽,大家好。对,我是来自腾讯云的高级前端开发工程师杨航,然后呃,之前主要是有经历过,就是云开发的相相关的一个开发,然后现在主要负责低码运行时这样的一个相关的开发工作,那就是基于我所负责的模块,今天主要就和大家来分享一下,就是威达低码平台它的一些架构仪,然后和就是我在实现这个迪玛平台的这个过程中的一些实践和思考。然后呢,今天的分享主要包括以下就是三个模块,那首先就是呃,迪马平台的一些架构相关的分析,然后另外就是我负责的这个迪码运行时它的整体架构如何是呃怎么样的一个结构,然后为什么怎么设计,然后第三块可能就是基于当前维达对于整个运行时的一个框架的约定规范,然后去详细的解释一下,就是底码的生命周期和事件这两个具体的机制。
01:08
那首先呢,就来了解一下,就是维达低代码平台,然后V大低代码平台是由腾讯云自主研发的一个低码可视化的快速构建应用的平台,然后为开发者提供了可视化开发应用的环境,并且提供了丰富的应用开发组件,将应用开发过程中所常用的一些呃技术能力,业务能力去做主件化,模块化,低码化,那就可以用户不用特别关心里面具体实现的细节,然后就可以对整个应用进行开发,在这个层面上呢,是提升开发效率,并且通过一些抽象的方式,然后可以实现呃业务的复用。那微达整个的这个平台是基于云开发的,然后利用云开发丰富的这样一些云端的能力,加上微达自己本身的客户端能力,实现了这样的一个呃,端云一体式的,一站式的这样一个开发。
02:12
那就是在整个产品的架构上,刚刚有提到就是维达,它基于了整个云原生的底座,那它后背后的是常见的一些云原生的容器,然后呃,TCB开发这样的一些技术。那云开发提供了非常丰富的server的能力,就包括呃,数据库,然后存储以及云函数,然后云调用这样的一些能力,那为大整体基于这些能力呢,对外提供了流程编排,应用权限控制,然后资源存储,编译、构建、发布托管这样的一些。产品层面上的能力,那整体的功能上呢,就包含了多人协同、可视化编辑、实时预览、独立构建发布这样的一些功能。
03:01
在系统默认的这些技术能力上呢,还有一些扩展的能力来应对各种各样的自定义的复杂的开发需求。基于底层的这些服务和功能,伟达编辑的应用,最终它是生成了一份和平台无关的DSL,我们叫做C,在维达上是这样的一份呃,描述文件,然后经过我们所提供的这样一个构建服务去生成对应平台的代码,最终发布在对应平台上,因此这个DSL,它就做到了整体的平台无关。啊,基于刚才所说的就是大家就拥有这样的一些特性,那在UI开发,尤其是组件开发这个层面上,然后为大家提供了呃,多种的这样一些兼容复用的技术,就包括了可以和传统的这样一个开发模式,就是原生写代码,或者说已有组件库这样对接的一个源码组件库开发,然后在整个页面维度上可以选择一部分的组件。
04:11
逻辑的集合,然后保存为这样的一个区块,然后在页面级别上做复用,那在更高的全局维度上也提供了包含应用,然后后端数据,然后素材资源,这样整体打包为一个解决方案的呃这样的能力来进行更高程度的复用。那就是刚刚提到这些功能,除了官方有提供一些基础的,比如说官方的组件,然后一些默认的区块实例这样的一些和解决方案模板之外呢,就是用户还可以根据自己的需求来自定义自己的就像组建区块以及模板这样的能力,来满足特异化的这样一些需求。尤其是在小程序的场景上,因为小程序它本身可能相对来说会更。
05:05
闭源一点,那在基于这个场景,面对可能已有的传统的这样一个小程序的开发的模式,那我为大家提供了这样就是低码的开发和原生代码开发相融合的这样一个混合开发模式。基本上基于小程序的呃分包这样的一个能力,可以完成低码的项目与原有原生开发的项目的一个兼容,这样就可以在原有项目上做一些增量的更新。可以助力这个应就是整体开发的这个项目应用可以快速的上线。那就是为大最近的版本,然后也对整体的开发体验,然后进行了一个优化,那在就是微达的整体的这一个编辑器中就可以完成,就是组建组织结构,然后组件的属性样式以及页面逻辑中可能会遇到的变量,然后自定义代码这些能力的开发。
06:11
那除了这些UI开发外呢,就是在资源层面上,然后编辑中也可以直接对所属的这些素材资源进行一些运运运营层面上的管控。啊,在后端接口的层面上呢,就是提供了。呃,这样的一个就是,嗯。云端的数据的这样的能力,那就是在V大这一整个编辑器中呢,就基本上覆盖了一个应用开发,可能外部和H5外部H5小程序这些一个应用开发,它完整生命周期中所遇可能使用到的各种的这样一个能力,那整个应用的全阶段全流程都可以在这一整个的维达编辑器中来完成。
07:03
啊,刚刚有提到,就是在。端上客户端上可能更多的就是客户端,就是前端的开发,那在云上更多的就是属于后端开发的这样的一个范畴,那为大家就是除了UI层面的开发之外,还提供了这样的自己内置的这样一套数据的接入以及存储,然后这些自建的这些内置的数据源,它都会有默认的CURD的方法,那在定义的对应的表结构之后,可以通过内置的这些方法对整个数据表进行操作。那当这些基础的逻辑没有办法满足需求的时候呢?我家可以在呃创建自己的自定义的as。然后在这样的as,就是连接器中,除就是有直接系统会内置一些常见的呃,常见的这样一些模块,对接了一些腾讯生态下的SaaS服务,包括腾讯文档、会议、支付这些,那直接就是通过这样的模板创建出来的应用,可以连通到对应的这些saras服务的open API,直接对对方的服务进行一个调用,对当前应用进行一些赋能,那同时就是我们常见的像呃postman,我们可能经常在postman上会去调试接口。
08:30
那在POS上所调试的接口也可以直接进行一个导入,然后导入到当前的呃微达的系统内,直接生成一个对应的接口来进行调用。那当就是已有的一些各种这样的接口。无法满足业务的一个需求时,还可以就是提供的这样的一个呃,云函数的service的这样一个环境,可以在这个云函数中来,就是通过代码的方式来编写自己的自定义代码,那在这个层面上就扩展了整个系统的边界。
09:08
从理论上来说,就可以完成各种的功能。那么再从整体上看,就是结合刚刚的自建的呃,内置的数据源和自建的这些连接器方法,然后这些结合维达所提供的流程引擎,表单引擎这样的一些嗯,基于模型模块的功能,那在特定场景下,就比如在维达中可以编辑这样的一个企业工作台的应用,来编辑常见的这个后台管理系统,那基于这些功能就基本上可以生成一个呃,具备基础能力的后台管理的功能。那可以实现基本上的一个无码开发这样的。呃,能力。那微的另一大特点呢,就是它就是和小程序的生态是嗯更加贴近的,如果在传统的模式下,就是你要去开发这样的一个小程序,在小程序中去连接自己的服务,基本上都是通过wx request的方式,通过HTP一个云端调用的方式去做自己的接口请求,那这段从小程序客户端实际上就直接走到了公网,然后在公网中,嗯。
10:25
就是在自由的这个服务上,就是为了安全,为了防刷,为了做这样的功能,可能就是需要做自己做很多的事情。那因为公网上可能这个包可能就会被篡改,然后有各种各样的安全问题,甚至被攻击的问题,那在整个维达上,维达整体复用了云开发的呃所提供的这样一个私有链路,那从就是小程序客户端直接发起的请求,会首先到达微信的一个接入点,那微信的接入点上有对应的安全防刷,然后健全这样的一些能力,直接在这里就可以获取到稳定安全的身份,那在微信到后面对微达对云开发的下面交互中,就是直接在走腾讯的内网专线,那相对来说十延体零会更低,那就是到了后面对应的API服务,就刚刚所提到的,呃,内置的数据连接器这种都可以直接信任前端传过来的一些这样身份信息,没有必要自己做其他的。
11:34
呃,图这样的机制来去做校验。那就是在端的层面上,呃,为他和就是开发者开发,微信的开发者工具也做了一个融合,打造了一个云家端闭环的这样的一个开发体验,在这个就是开发者工具创建。小程序的时候,就可以选择维达提供的这样一些已有的模板,并且就是这些模板会直接拉起维达所提供的在呃,开发者工具中所内置的一个微大的编辑插件,在这里就类似在web上的体验,可以直接对应用进行编辑,并且在小程序的预览区就可以直接预览到实时的小程序的渲染结果。
12:23
那并且通过这个插件可以直接将这个小,就是当前通过低码形式开发的小程序,直接来发布到,呃,一键发布到微信,做一个发布的能力。那就是刚刚就是提的,可能更多的是产品能力上的,那在技术的架构上,维达它本身采用的是一个嗯,比较常见的PSCS这样的架构,那在整个设计它包括了呃,编辑器,控制台以及伟大所提供的这样一个C的编程的。
13:00
可能编程用的更多的工具。那它分别对应了,呃,应用内容模块,就是模板这样的一些以及组件这些模块进行了管理,那维达的整个服务层它都部署在了。就是部署在云上。云开发作为整个的底层基础。那其中呢,就是编辑器,它核心围绕的就是刚刚所提到的CC这样我们所约定出来的一个平台,无关的DSL,基于这个DSL所就是对整个应用进行一个描述,包括了组件之间的组织方式,各个组件之间的呃原数据配置,组件之间的相互关联关系,以及自己代码所写的代码的一些时间调用这样的一些内容,那在整个构建模块,就下面的这个模块中呢,就是为了应对各个不同,就是多端不同的一些场景,整个构建系统做了从渲染render,然后代码生成监,然后构建builder,以及到最后的deploy,然后这样的一个分层,那就满足了基础的渲染,然后可能更。
14:25
高要求的生成、编译,然后发布、部署这样的一些能力。那我们就是从头来看,就是刚刚是维达的实现,那如果就是这现在要实现一个呃,最就是低码平台的最小子集,那就是我们可以来分析一下它需要拥有什么样的能力,那可能最重要的就是我认为最重要的就是低码是对传统的代码开发模式的一个抽象,因此它一定需要有一个呃。
15:02
描述来对。之前的这个代码开发的方式进行一个结构化的描述,那这这里就是一个DSL。整个DSL呢,就是我们基于DSL在往外扩展,可能就会遇到就是你在编辑阶段,你开发一个应用,可能一定需要对这个应用进行一个编辑。那在编辑阶段可能就会接下来涉及到。有组件模块,然后对组件进行属性配置。那就是有一些交互层面上的东西可能存在一个编辑区,你需要在整个编辑区内对刚刚所说到的一些操作进行响应,在编辑内对整个应用进行一个编辑,那就是类似于类似于呃,PowerPoint的PPT,这个就是你在编辑PPT的时候,为了更好的组织结构,你可能还需要就是有一个大纲,大纲数这样的结构来观测各个组件之间的一个相对关系,那有了编辑对应的铁钉会有预览,预览来看就是你当前的这个最终效果是怎么样的。
16:11
那预览它就更偏一个纯粹的运行时这样的结构,那这样在整个运行时上铁定就会就是加载,就是读取加载资源,然后做页面渲染,然后并且这个呃预览过程更好的情况下,可能你希望你在编辑。的过程中,每次修改了属性或者修改了什么之后,都需要进行一个实时的更新,那预览作为产物的上一级,那在整个开发的过程中可能会遇到各种问题,所以debug调试的这个能力可能也是比较重要的,那当我们编辑和预览就是完成之后,我们最终可能需要对呃整个应用进行一个发布,发布上线。那整个编译发布就会涉及到就是代码的生成以及部署这样的能力。
17:09
那他们整体来看就是这三块,基于刚才说的就呃,根据端就把它分为了,就是在客户端。所呃编辑台所提供的这样的一个呃编辑预览的能力,以及在主要在server端进行,然后对产物进行生成部署的这样的一个编译发布的能力。然后基于这些的分析呢,我们就可以呃得出,就是我们需要有渲染引擎来处理编辑预览这样,以及需要有一个代码生成器来完成编译发布这样的一些能力。那我们接下来就看就是这两个模块到底要怎样具体的来实现。
18:02
那首先我们看整个在编辑器中的编辑预览的模块,那整个编辑预览的核心主要在于就是与编辑器的状态交互,以及呃编辑区它这个特殊运行时的构建。那我们可以设想就是除了刚刚所提到的最基础的DSLY,整个编辑区内还会有各种各样的交互状态,并且对DSLY它拥有一个写入的能力,因此这个编辑区它整体的数据需要和呃微大编辑器就外面这个编辑器这个整体,然后进行一个频繁高度的交互。那。作为一个就是。编辑和预览都是在展示一个应用它运行态的能力,那作为一个应用,它铁定是一个独立的,它需要和宿主环境来进行一个隔离。防止。就是作用域的一个污染,嗯,通俗点来讲,可能就是你并不希望,或者说维达自己并不希望用户所开发的一个在应用中所写的样式,或者在应用中所对window,然后对呃数据的操作,或者影响到未达编辑器自身的一个央视展现或者业务逻辑。
19:24
那基于这个我们就需要将编辑预览区,然后与呃整个的编辑器的,然后做一个隔离。那就是这是要做隔离,上一步又是需要做共享,那就是显然这两件事就是是矛盾的,因此这里可能需要就是出一些呃独特的策略来选择性的处理这二者之间的关系。那在整个资源层面上呢,就是呃,包含了组件素材,然后所写的码,JS模块和表达式这样的一些资源。
20:03
那想也要就是利用这些资源,那就一定要实现对这些资源的加载,以及。呃。呃,预处理这样的能力,那预处理可能更多的就是体现在这个依赖的分析上,尤其是对于JS模块这些就是。原生写的各种本身就是有模块机制的,那可能就是需要把各个模块之间串联起来。那依靠刚刚的这些素材,结合DSL就可以生成一颗用于渲染的render tree,然后这个render tree就在编辑预览区内,用渲染引擎就可以做一个视图上的渲染,那从结果上来讲,就是可以在编辑预览的区域内所看到当前编辑应用的一个结果。
21:00
那刚刚编译构建的这个模块和呃编的预览就不是很相同,编译构建就是我们在开发过程中都会感觉到它是一个CPU内存密集的动作,在整个前端的构建工具中。会有大量的文件读取,就文件读写,然后转这样的工作,那考虑到这个CCPU内存密集,因此我们就选择将它放了流程中去构建专的流线来完成整个发布过程,对,就发布过程中对这个流程进行编排,那在这个编译构建的产物层面上,它是直接面向了。就是用户的用户,就开发者他的用户,那整个应用的性能,它就需要具备一个性能敏感性,然后并且需要更加的鲁棒稳定一点,那基于这个的情况下呢。
22:03
我们就呃,需要对整个应用的内容做一些精简,然后做预处理,需要充分的利用编译构建这样的一些能力。那这个整体上来来看,就是我们的编辑预览,它可能就是呃受限就是都是基于外部这样的一个场景的,因为你是在就是伟大的这个BS架构中去编辑器中,然后去对去看这个编辑预览,那编译构建的产物,它实际上最终不一定会跑在哪里,它可能会跑在一个外部的环境下,或者跑在小程序里,那未来很可能还有可能还会跑在原生的这样的一个APP。就是呃,安卓或者iOS这样的一些应用上,那因为它最终的target这样的目标不同,在整体设计上就需要拥有这样的一个适配层,来屏蔽掉这些不同运行时之间的差异,那基于这一点呢,就是呃,整个构建器在。
23:12
DSL这个CL之外会抽象出来了这里的一个client API,主要负责整个客户端的一些呃,公共方法,数据方法,包括路由,然后健全用户身份这样的一些能力。然后,呃。在下层的这样一个外部和小程序的模块呢,就是实现对应的接口,然后来完成对应的,就比如路由这样的,呃,每个模块可能都会有由路由跳转,然后状态管理这样的功能,然后对外暴露了相同的接口,整体在调度上就不用特别的关心下面到底是一个外部的。
24:00
外部的运行时,还是一个小程序的运行时,只要在对应的地方调相同的接口,接口的不同实现来屏蔽掉这个运行时的差异。那基于就是这样的一个设计上来讲,我们就完成了,呃,整个应用的一个编辑预览发布这样的一些需求。那我们抛开小程序的特殊模式。来来看,就是整个编辑器的编辑和预览,编辑器内的就是编辑预览,然后和构建最终生成的H5PC这样的一个应用,它都运行这样一个的器的环境,那基于就是这些端他们所面对的问题都是类似的,他们要解决的问题也都是类似的。为了减少冗余,然后提升在各个场景下表现的一致性,并且提升可维护性,那就应应该考虑将这些做一个抽象,将他们公共的部分呃提取出来。
25:05
因此这里就设计了这样的一个伟大render,这样的一个渲染引擎。这个渲染引擎就只封装了最核心的应用的外部应用的渲染逻辑。那整个模块可能就这个模块中就包括了,主要包括了C的协议解析,然后路由构建渲染,渲染数render,然后并且还提供呃,提到的一些什么,呃,生命周期啊,事件啊,变量绑定这样的一些基础的能力,那就是针对于他往前不同的。就是不同的这样的一个端上,那就是外部可能会就是在实现不同的呃加载器,就比如素材加载,然后素材加载完之后对素材进行呃,进行包裹的一个装饰器。尤其是在整个构建的场景下,然后在刚刚提到在构建会需要对整个应用进行,就是充分利用构建的这样能力,提升它的兼容性,以及呃减小它的体积,那在这里就直接对呃所需要的组件库,然后进行了组件库以及所编译的低码,然后写成了文件,然后直接通过文件引用的方式传给这样的一个渲染器,那整个项目,整个这样的一个呃项目,就是在代码层面上是生成了一个项目,这个项目直接通过WiFi的编译构建,那可以达到刚刚的一些呃基本上的诉求。
26:43
整体上就是呃渲染,渲染引擎的设计上,它应该是呃支持多插口的,就是外部的这样一些,外部的这样一些,就比如加载装饰,然后以及各个的这个功能都是可以进行呃插入写来满足各个场景的这样一些需求的。
27:07
那我们就是就刚刚的这个渲染引擎展开一些模块。整个渲染上可能最核心的就是这样的一个的机制,那就是主要是为了解决渲染的问题,那就是前端开发可能都会比较了解,就是当前在前端领域做开发的时候,可能基本上都是使用MVM框架,就像view react这些,然后那维大也同样基于这样的一个思想做数据驱动。但不能和任意一个框架来进行绑定,因为下面可能就是可能是编编成一个应用应用或者小程序的小程序的应用,那就是不能合任一个框架做深度的绑定,因此维纳就自己实现了这样的一个VM层、v model层,然后来维护数据,仅仅把下层的这样一些呃,渲染层上的东西当做一个渲染层的这些框架,当做一个feature或者就是包来使用,不是过度依赖它内部的一些实践以及逻辑。
28:15
那我们构建的这个VM节点,VM节点我们叫做它的节点,那整个应用就是要实现这个feature上,实际上就主要是在要考虑如何根据DSL来创建自己的这个VM,然后并且这个VM如何和试图做为做一个绑定。那首先就是为他设计了这样的一个嗯,VM的就是呃,Visit的结构,那基本上它就包括基本的ID,然后value用来表示这个节点上的各个数据,那这些数据再抽象一点就是传给各个组件的prop入参,那children和parent用来构建这棵用于构建整棵树的一些关系。
29:06
那像for和呃,Exit和change这样的东西,For用来处理就是我们指定式的for循环,就是一个组件渲染多个,用来记录这样的一些层级关系,Exit和change主要是为了在编辑的过程中,呃。响应的更快,做热更新所打出来的这样的一些嗯,记录的字段,那在整体的数据上呢,就会存在,就是表单容器所画出来的。这样的一个数据域。然后呃,维达的代码就是除了你写静,就是组件的属性,除了当你配静态的值之外,还可以去做一个表达式的绑定,这些表达式就都会存储在当前预下的大半子内。然后这样的基本上是这样的一个结构,那在逻辑上呢,首先就是呃创建这个visit的节点,就由当前v load的这个结构,那在这个结构的基础上,对所有的属性,尤其是这个value的value的内容,然后进行一个get s的拦截,就类似于view一样,主要是为了呃做依赖收集,以及它的那个呃响应的触发。那刚刚有提到就是静态的属性可能比较简单,直接就进行复制了,那动态的绑定它是一个字符上的表达式,那在运行时都会把这个表达式编译为一个function,就比如此处绑定的这样一个ABC的变量,那可能最终会变译成一个function ABC,这样那当每次调用这个function的时候,就可以实时的获取到这个这个这个APC的就当前的纸,然后并且付给VS上VG的value上的对应数。
30:57
那为了做到那个响应式R的这样的一些变化,这里需要实现这样的一个water,那water就包含了两部分,就主要包含了就是刚刚提到的这样,呃,绑定表达式的这样的一个和组件渲染的water,那整个就是在刚刚的那个所生成的函数调用的时候,明显会对A。
31:22
就是ABC这个变量进行一个访问,那因为对该进行了拦截,就可以做依赖收集,知道这个这个表达式中是依赖A这个变量的,那当A发生变化之后,就可以再次对,再次重新执行这个函数,然后重新得到最新的A的值,那同理就是呃。组建渲染的watch也是类似的,只不过它监听的是组建的pro,就组建的入,那当这些入的入发生变化的时候。就visit的Y6发生变化的时候,那同样的重新触发这个组件的软方法,让它根据最新的这样的一个数据进行一次渲染。
32:07
那整体上来讲,这就实现了整个组建就是组建的软方法,那就是组建不停的去递归,然后去渲染秋准定就可以,呃。页面实际上也是一个特殊类型的组件,那在这个帝国的过程当中,实际上就完成了整个页面的一个渲染,并且它是reaction,就是数据变化来更新的。那当渲染引擎的模块解决了之后,我们就需要给这个渲染引擎提供一个它可执行的区域,就是嗯,通俗来讲。通俗来讲的话,我们就是,呃。如何在编辑器中,就主要是在编辑预览中怎么样直接访问,就是看到你这样的一个结果,这样提供这样的一个区域,那常见的在业内呃使用的技术方案就是使用cos box,它提供了一个完整的运行时,并且附带了浏览器上的类似于web的一个编译打包能力,那将一些就是文件,就是字符串这样的一些代码扔给CO3BOX之后,它就可以得到最终的运行的产物,那我们引入cos之后呢,就发现可能就是。
33:24
呃,没有想的那么好,就是还是出现了一些问题,主要就存在于这个cos博斯,它的编译依赖安装和就是计算池这块。那整体呢,CO3BOX我们就对他进行了一个分析,那主要是他提供了两块能力,Parker和这个transpiler,那packer主要负责依赖的加载分析,然后并且对文件进行了一个打包编译,那它主要耗时就在于因为它。这个依赖分析是基于NPM的,那他需要串性的就加载到一个包之后再去串业性的去走这个数来构建这个依赖的,呃,构建这个依赖数,并且整个资源加载也相当耗时,那transpi这个。
34:14
他是主要负责对资源进行编译解析,然后把ES6可能更高级别代码编译为当前平台可执行的代码,那这个编译耗时,整体来讲也是一个CPU密集的动作,会比较耗时,那除此之外扣3BOOKS,呃,它相对而言,它的通用性和兼容性很好,这个确实是然后这些。这个特性就来自于它代码里面有大量的历史兼容逻辑,然后比这些兼容逻辑会加大整个运行的耗时,并且也增大了整个包的体积,在初次加载中会比较的呃慢,那面对这些问题呢,我们就决定自己来搞这个,呃,渲染的就是。来搞这个运行时,运行时的沙箱。
35:01
那刚刚有提到就是的那些问题,那首先我们看就是呃帕克它加载就解析依赖加载嘛,那针对这个模块呢,我们就只能将这个依赖数的解析前置在整个项目就是发,就是整个项目开发过程中来完成,因为它整体的依赖相对来说会比较稳定,都是系统级别的依赖,那就通过事先在的打包分析,然后通过艾诺的方式把它呃单独出来,结合CDN进行一个加速。那这块。呃主要是呃对用户的这样一个动态逻辑,就写的低码,然后写的绑定的表达式这些模块来进行,只对这些模块进行处理,因为其他的静态的大量的这样一个静态的模块,它是呃相对来说是不会变的或者固定的,那在事先把这些模块进行编译,就在运行时直接引用就可以减少这部分的压力,那此处呢,是引入了BA在运行时用transform把呃ES6这样的代码直接编译成了ES5,在浏览器中来直接直接来跑。
36:13
那刚刚就是这个编译成ES5代码之后,还要提供一个来运行的环境,这里就比较简单,是直接通过new function来动态的创建了一个函数,然后来完成刚刚所提到的这个,呃,运行取值这样的一个功能。那刚刚就是一个,呃。就是简单的这样的一个对应的问题都有了解决方式,那还有就是我们在处理这个第一码的第一码就是自定义代码的时候,然后因为自定义代码它写是基于ES6模块的这样一种写法,那为了让他跑起来,单纯的只进行一个背的转义是不够的,他还需要建立一个模块的引用机制,那我们就参考派的模块机制,然后在整个运行时。
37:04
的时候,对整个呃模块进行了加载和引用,那简单的来讲,外派实现这个模块机制主要是通过实现了这样的一个require方法,在它编译中叫require,然后require的基本逻辑就是在呃首先在引入的时候,根据这个文件路径先判断是否这个已经加载过了,如果没有的话,就呃创建出来这样的一个model的对象,然后对这个model对象进行加载,这个model对象加载就大概是。这个下面中间这块的这个代码,那它实际上就是会对。Export这个对象上的对应的东西进行一个赋值。那就是在repair后,最后就会返回这个模块的,就是它port导出的这样一个内容,那基于这套简单机制完成可以完成呃整个呃,就是前端的一个。
38:01
ES。就是呃,ES6之前的这样common JS层面上的一个模块的机制。那就是基于刚刚的这个外派的分析,我们就实现一个类似的模块加载系统,然后因为它是呃,符合这个commons规范的,我们就把它叫做一个CMD的loader,那首先呢,它的呃流程就是嗯。就we派他自己,就是他是输出了文件,然后最终会交给JS运行时来执行,但我们这个因为是运行时的,我们这个拿到文件件之后,实际上都是生成了,也呃,就是即使是转移完也都是生成了一个字符串的代码,那就需要将这个字符上的代码给。怎么样,装载机内存就是给呃,装载机内存来给执行出来,那类似的就也也是和刚刚所提供那个沙箱一样,就是通过动态创建方式的方式来执行刚刚的这个类似于这样的一个loader的中间这个loader的方法来执行最大代码,然后去获取这个model对应的值。
39:12
那在整体的流程上呢,就是首先所有的低码的这样的一个文本都经过了背转译,那经过背转移之后,其中所使用的import这样的语法就都会被转移成ES的require,那我们在当前的这个域上就可以对require做一个拦截的实现。那require的具体逻辑和刚刚类似,就是呃,进来之后,然后去拿到一个pass,将这个pass转换为转换一个绝对pass,作为一个缓存key来判断这个,来判断这个文件是否就是否有加载过,那因为就是代码写的时候,它有一个默认的resource规则啊,可能就是我们会就是先就是补充后缀,然后根据后缀来有不同的pass。来去加载这个代码,那在整个加载代码的过程中呢,它自己的这个呃,Port之前可能又会有其他的require,然后就基于这棵树进行了一个呃伸缩这样的一个。
40:12
递归的逻辑来完成整个依赖的解析。那基于这套就可以实现在前端去加载一个加载一个代码的字符串,然后并且获取这个代码它导出的对象。那刚刚讲的就是render的,Render的一些内部的实践,那我们就回到呃,更加纯粹的这样的一个运行式的环境,我们来看就是维达定义的这个框架行为是怎么样的,那这次我们就主要关心就是维达所定义的生命周期和时间机制这两件事情。那首先呢,就是在整个微拉的体系内有三个级别这样的呃实例就分别是应用,应用级别可能就是全局这样的APP实例,然后配置级别这样就是页面级别这样实例,以及单个组件级别这样,那这每个实例都会有自己的生命周期,那像APP的呃,APP配置它相关的生命周期就都可以在代码编辑器里面进行一个编辑,就代码编辑器的life,那APP就主要是有lunch show head。
41:30
然后这样的一个就是挂载显示,然后隐藏这样对应的一个生命周期。那在配置上也是对应的,就是呃,Load show ready,然后离开的时候和show对应的head,然后和load对应的lo,那在组件层面上组建,呃,就是自己在开发组件的时候,也通常就是最基本的就是。呃,Amount amount就是ach这样的一个事件。
42:02
那当。我们有这样的一个应用的时候,这些生命周期之间是怎样的一个调用顺序呢?就是我们可以是,就是我们假设就是现在存在在了一个应用,然后应用中有一个页面,页面中有一个组件,这样的三层嵌套之间的关系,那当这个访问访问发起时,首先就会进入到呃,这个before lunch是嗯。相当于内部的一个约定出来的一个before的生命周期的阶段,那它主要就会从URL上就是UR,就是不管外部还是小程序,就从页面,从参数上解析这个应用的参数,并且附给呃,APP和配置对应的值,app.data set点和和那个。配置到配置点呃data赛点PU来创建对应的参数变量。
43:00
并且在此刻会异步的发起登录,这里就是要注意这个登录是嗯异步发起的,它不会阻塞相任何相关的流程,那当应用参数被创建完之后呢,会基于这个应用参数,然后再去初始化全局的,就是除了参数变了之后,还会有状态变量,状态变量中呢,可能会存在一些。呃,就是低码,呃,那个不是那个数据源,就是已经绑定了数据源的变量,这个变量在就是它会在初始化阶段对远端的接口发起一次请求,根据请求结果来初始化这个变量。此刻会去发起这个变量的初始化,然后并且等待初始化的结果完成,那当整个的就是这些事儿都做完之后,那before的生命周期就结束了,会进入到呃,会触发APP的lunch。那就是APP的lunch和秀它。就是我们从代码上。
44:02
我从代码上看。就是APP的取和修在这里,那就是如果写法是同步的,从JS逻辑上就会呃串的调用,就是lunch取里面的内容全部都执行完之后才会直接秀,但是可以通过加a think的关键字来让它变成异步调用的,那此刻它两个之间就不会存在明显的阻塞关系,但就是一定是烂曲线触发,然后紧接着会触发秀,基本上是并发触发,但是是烂曲线,然后售后,但是两个之间就不会再有阻塞了。也就是这里所描述的可能基本上是并发触发,但并不会有对应的阻塞。那当这些事情就是在被并发触发之后呢,在被触发的同时,然后会去进入到这个before配置卡斯区的这样的一个。
45:00
也是内置的这样的一个生命周期的阶段,那他做的事情也类似,他创建了页面参数。并且此刻就开始就是根据会等待登录结束之后,然后根据当前的一些当前已登录的这个状态进行页面健全,也就是说呃,这个健全动作一定是在登录之后的。那这两步都完成之后呢,会就是接着页面整个全有权限之后,整个页面就会开始进行,呃,进行渲染。那首先就会进入到组建的attach的生命周期,就是它是嗯,相当于是while,类似于view的这个mount的一个。一个一个就阶段。然后组件呢,它是就是深的就两个组件嵌套,它可能会一就是呃,就是A的A,然后A的准,然后B的求准,然后C的求准,这样一级。
46:05
啊,A的求准,A的children准的求准,然后这样一级一级下去,然后接着再会平,再移到就是合为同级的B,然后来触发这个事件,那此刻呢,就是在组件触发的同时,然后配置的和秀也就被触发了,类似于APP的烂和秀,它也是当两个方法都是同步的时候,它load和秀之间会有明确的阻塞关系,那一步的时候他只是负责了触发。那当所有的组件全部都mount之后,会就是配置mount这样的一个事件会被触发。那配置amount紧接着触发之后,会接着按照就是呃,他组建了touch触发的顺序,对每个组件再去触发每个组件的ready事件进行一个触发,那当所有的组件ready事件都触发完毕之后,整个配置的ready事件就会触发。
47:01
那根据这样的一个生命周期的调度流程上来看,嗯,有几个在应用开发中可能会比较需要,可能比较关注的点就是你在配置的。配的这些和生命周期呢,因为它都一定会经过页面健全,页面健全又依赖于登录,所以在这些是可以通过呃多w.o and current user一定是可以获取到当前登录的用户的。对。那就是生命周期完,我们看一下就是的事件机制和的那个那个V机制一样,事件机制是为了个端的差异,所以就是自己来实现了一套实现了这个触发的一个bus的这样的一个机制啊,简单来讲就是在对应的对应的作用域,就比如APP作用域,配置作用域和单个组件的作用域内会建立,每个域内都会建立一条自己的bus,然后任何一个节点都可以向这个事件总线上去添加监听。
48:09
呃,并且也可以去触发一下事件,那就是基本上就是在例子,就是在组件上,这两个都是呃,那个image的组件,然后image在那个那个那那个啥那个加载失败,加载失败的时候会去触发L这样一个事件,那在web上就可以通过内置的词典L来触发L的事件,其中第一个参数就是要带给就是这个事件所携带的一些额外的数据,那在小程序上就使用小程序原生的trile event来进行I事件的一个触发,并且同时也是在这个第二个参数上来带它的,呃,就是这个事件所携带的一个数据。我们可以看就是刚刚的这个例子,就是当组件,呃,当image加载失败时候,这里去配了首先显示一个消息提示,那消息提示它任意一个方法都会有成功失败的两个分支,那在成功的时候去添加了一个if,当if为触的时候会返回上页,那if为的时候会返回首页,顺利就是通过。
49:18
呃,这样一个事件链条,呃,事件数吧,这样一个数的配置可以完成一些简单的。这样的一个前端流程的,呃,调用。那这个配置转成对应的节点呢,就是类似这样的一个节点,首先这个1111节点就是刚刚那个image image。就是image load error的这样的一个事件,它的事件是loud error,然后error,并且携带了一个error对象,然后一一事件,它所执行的动作是修透的,显示一个显示一个提示,那这个事件再往下它会有两,就会有一二,派生出一二和一三。
50:05
两个那一二的,呃,ID就是一二的这个疑问词。就是一点一点feel,然后一三就是一三的这个event,就是1.success,然后通过这样的一个success和feel的分支来接着进行触发。在一一节点就是修的内部,实际上当他成功或者失败的时候,就相当于在刚刚就是触发事件的方式,会去自动的触发success和fail这样的事件。来完成这个事件下一个状态的扭转。那在就是,呃。成功之后到达了这样的一三事件,一三事件类比,然后会接着走到13FAIR 13success,然后最终会走到一四的这样的一个L和这个l home,那需要呃注意的就是注意的一点是就是刚刚有提到携带数据这件事情,就是每个事件上,就是在触发事件的时候。
51:08
就是无论是。无论是就是在组件中触发事件所传的参数,还是在刚刚的这个。刚刚的这个就是所绑定的一些内置方法上。就是内置方法,它的返回值就是这个方法它。呃,Return,就它return的值就会走到success,然后他这个方法如果抛错surr了,那他就会走到fail,然后如果走到fail的话,这个传进来的就会把这个出来error对象传进来,然后success或把这个这个方法它的反馈是传进来,那在下一个节点中就是就会可以获取到上一个节点的值。就比如在E3 e3这个节点,它的event是event的name是1.success,那它携带贝塔就是呃,E3上event的detail,实际上就是一一传过来的一一点贝塔这样的一个东西,那就是在这样的情况下就完成了事件之间的一个值传递,就下方的事件是可以获取到上方事件的返回值,或者上方事件返回到error的。
52:17
那我看下就是这个事件的基础的定义就是呃,会有type detail和current target这样的一个基础的定义,那type就是所提到的事件名,就比如image,然后1.success 1.fail,然后以一三点SUCCESS13点这样的事件名,那detail就是刚刚所解释的所携带的数据,那就是target给的是当前,是就是当前,这整个事件所触发的节点,就比如呃,这以这个绑定为例,此刻它触发的节点就是那个image的组件,啊,通过这些就可以,也可以通过这个current.id来获取到这个组件的ID,可能会进行一些数据的操作。
53:05
那我们就是到此,就基本就是针对于整个渲染引擎框架上的一些固定的行为,就是circle和event这样的一个行为做了一个解释。啊,就是。我分享的内容大概就是这样,感谢聆听。是大家。大家可以看一下有没有什么问题或者其他什么想要了解的。
54:08
我看就是有同学来提到就是的。Visitch相关的就是,呃,Visit上的pattern和children主要是为了构建人和树的关系,但真正在使用的过程中呢,就是你可能需要,就是有可能,也就是有可能会需要通过当前的一个节点,就比如你,呃,你当前是一个image,你想找到这个image它上层的容器,然后就。就一个轮播中心,可能需要一个图片来往上找,找到轮播,然后或者在轮播中往下找,找到面啊,在这种情况下就是他人和丘疹,主要是构建树,并且帮助在树上游走的。然后这个实现就更多的都是。是内部的,内部的实现外部在使用的过程中可能并不太需要关心这些。
我来说两句