作者:闲鱼技术-羲凡

背景

随着Flutter对现有业务的不断参透,闲鱼Serverless基建的重心也倾向了dart生态,先是将dart容器打包到服务器上,实现dart编程语言的统一,在统一的容器之上实现编程框架一体化(nexus、story),以及后端领域服务一体化。基于dart生态下,前端的FaaS在研发交付其实并不高效,研发阶段主要面临的问题是:编程语言不统一 编程语言本身虽然不是最大的障碍,但这也确实给前端开发者增加不少门槛,而且更重要的是语言背后的生态、环境与体系更是一道高高的墙。工程割裂与背后环境复杂 端侧一个工程,FaaS侧也有一个独立的工程,它们背后都有着自己的一套构建、调试、集成/发布的工具链;除此之外FaaS还有自己配套的环境、runtime、框架作为支撑。开发者面对这样复杂的FaaS研发环境与双重的研发工作流是无法做到高效交付的。

编程语言一体化

Typescript作为Javascript的超集,弥补了Javascript的静态类型检查,同时扩展了很多OOP的语法特性,使得TS跟dart在语法特性上有非常多相似的地方,未后面的转换提供了可能与便利。要实现语言层面转换背后都会有一个小型的编译器在支撑着,不过幸运的是Typescript官方已经提供语法解析器,通过它我们很容易就拿到一份可靠的AST,所以我们只需要实现一个dart generator就行了。生成器大致可以分为四个层面的工作:

  • 基础语法转换
  • 原生方法差异转换
  • 业务框架桥接
  • 依赖库与头文件桥接

基础语法转换

这部分很好理解,就是最基本的语法层面转换,用个最简单的例子看下。

原生方法差异抹平

两种语言在内置原生方法上也有很大区别,举个例子:可以看到下面数组的实例方法在两种语言体系上是不一致的,除了数组插入还有很多很多原生方法是不一致的。当然也没太必要被这个难以想象的数量吓到,大多数情况:90%的场景只会用到那10%的方法,完成了10%的转换就能cover到90%的场景。

// ts
list2.push(10)// dart
list2.add(10)

要实现系统方法的差异转化首先要识别出该方法是来自于哪个类,比如说 list2.push(10) 我不可能只检查 push ,因为随便一个类/对象都可以实现一个push方法。我们必须识别出 list2.pushpush 属于 Array.push,别忘了整个typescript编译器中占比最大的类型检查器 ts.TypeChecker ,它可以很好的帮我们解决这个问题。大致思路如下:

业务框架桥接

在完成上面两块能力转换后,常规裸写一段逻辑进行转换问题是不大的;但业务是不可能裸写,业务需要框架,需要借助框架进行通讯、与容器打交道。需要借助框架进行业务抽象,更好的组织、管理业务逻辑。我们来看个例子:

DartMtopResult<String> result = await HsfServices.request(moduleName, parameter);

上面的这段代码是用于在dart侧进行内部服务请求的,从代码表明我们可以获取到三部分信息:

  1. 有一个HsfServices的类
  2. HsfServices有一个同步返回结果的request方法,接收两个参数
  3. 最终返回DartMtopResult的数据结构

我们再翻一下 request 的实现与 DartMtopResult 的申明:

// DartMtopResult.dart
class DartMtopResult <T> implements xxxx {T data;bool success;String errMsg;String errCode;// more code hidden
}// HsfServices.dart
class HsfServices {// more code hiddenstatic Future<DartMtopResult<String>> request(String moduletName, String parameter) async {// more code hidden}// more code hidden
}

就看这么多足够了,打个比方如果我希望在typescript侧编写一个能用 HsfServices.request 发请求的ts代码且不报错,那应该怎么做呢?像下面这样申明一个:

// HsfServices.d.ts
export declare class HsfServices {static request(moduletName: string, parameter: string): Promise<DartMtopResult<string>>;
}
// DartMtopResult.d.ts
export declare class DartMtopResult<T> {data: T;success: boolean;errMsg: string;errCode: string;
}// business.ts
import {HsfServices} from "HsfServices.d.ts"
import {DartMtopResult} from "DartMtopResult.d.ts"
const result: DartMtopResult<string> = await HsfServices.request<DartMtopResult<string>>('recycleGet', parameter);

非常简单就能让业务逻辑正常写下去并且不报错。但你肯定会说这样的代码也没法运行起来,是的,但我并不需要上面代码运行起来,我需要的是将它转成dart,并能在dart runtime中运行就可以了。大致的桥接思路如下:

依赖库与头文件桥接

这部分工作是从业务框架桥接中衍生出来的,我们还是用一个例子来说明一下问题产生的原因。

// business.ts
import {HsfServices} from "@ali/faas-hsf"
import {DartMtopResult} from "@ali/faas-mtop-result"
const result: DartMtopResult<string> = await HsfServices.request<DartMtopResult<string>>('recycleGet', parameter);
// business.dart
import 'package:hsf_services/hsf_services.dart';
import 'package:dart_mtop_result/dart_mtop_result.dart';
DartMtopResult<String> result = await HsfServices.request(moduleName, parameter);

可以看到上面逻辑除了发请求部分要转成dart,还有业务引用头文件需要桥接过去,而头文件的引入通常是靠pub依赖包(pubspec.yaml)安装进来的,就意味着转换器需要拿到 @ali/faas-hsf 对应dart侧的pub包与引入头文件。我们的解决思路大致是这样的:在@ali/faas-hsf 模块中放入 faas.yaml 文件来指定对应的映射关系。

@ali/faas-hsf
|--lib/
|--faas.yaml
|--package.json// faas.yaml
faas_pub:# 映射的dart侧依赖包hsf_services: ^1.1.7# 映射引入头文件index: hsf_services.dart

研发过程中再通过工程脚手架来自动完成这之间的映射关系的提取:头文件映射与依赖包映射。头文件映射最终会交给转换器,而依赖包映射会交给背后自动维护着的dart工程(后面会提到背后自动维护的dart工程)。大概的思路如下图所示:

研发工程一体化

编程语言一体化只是整个FaaS一体化研发的第一步,也只有统一了编程语言之后,背后的生态(npm)、工具链(build)与工程才可能一体化。我们看下现状:开发者面对的是两个割裂的工程,两套不同的环境、生态。这正如文章一开始所说的:编程语言本身不是最大的障碍,但语言背后的环境与生态却是一道高高的墙。在我们统一编程语言之后,研发工程一体化就变得可行了。

正如上图所示,FaaS工程本身的复杂在于整个工程需要运行在一个本地容器之中,因为容器要为工程提供runtime、相应的工具链、框架依赖等能力。所以本地容器本身是必不可少的,我们能做的只是尽可能让开发者无感容器的存在;除此之外还要对两个工程的逻辑做一定的融合,大致可以抽象成四部分工作:

研发代码层面融合

代码层面融合包括两部分:业务逻辑融合、业务逻辑所依赖编程框架融合。分别体现在 faas_src 存放业务逻辑的ts版,package.json 存放业务逻辑所依赖的编程框架(前面我们介绍到业务框架桥接最终就体现在端侧的依赖包上)

├── faas_pub.yaml
├── faas_src
│   └── Home
│       └── index.ts
├── package.json
├── src
│   ├── components
│   └── pages
│       └── Home
│           ├── index.css
│           └── index.js
└── README.md

FaaS侧的工程黑盒化

使端侧脚手架全权接管FaaS侧的工程初始化、热部署、调试信息,暴露出来给开发者的只有一套工具链,只有两个指令 init dev ,让开发者0门槛初始化出一套统一而可靠环境的FaaS工程。

对接编译器进行研发实时编译

这部分主要负责对接转换器实时将ts编译成dart,并同步到黑盒中的FaaS工程。在实时编译过程有两部分内容:一部分是纯ts逻辑编译成dart,另一部分是依赖包的同步安装,其中 faas_pub.yaml 由脚手架通过探测端侧package.json中的faas依赖包来进行提取生成的,并不需要人工维护。

串联调试阶段的编译流

从保存每一个改动到在浏览器上能成功发起一个faas函数请求,这之间大致经过这些步骤:监控改动、编译代码、产物部署的流,由统一的端侧脚手架进行串联起来。

总结

经过编程语言的一体化后,我们不仅为开发者提供一种熟悉的技术栈,也为后面工程一体化提供了可能性;再经过工程一体化后,我们为开发者解决了工程割裂,解决背后复杂的FaaS本地运行环境,带来与原研发模式基本一致的研发体验。

后续

一体化之路还很多要去建设的,调试、发布、回滚等等;除此之外,FaaS毕竟还是运行在后端,最终通过网络协议与端侧通讯,那在两份代码中必然存在两份数据结构申明,两套封包解包逻辑;这为后面数据结构的一体化与自动化建设提供了很好的发挥余地。

dart js转换_基于dart生态的FaaS前端一体化建设相关推荐

  1. 闲鱼基于Dart生态的FaaS前端一体化建设

    背景 随着Flutter对现有业务的不断参透,闲鱼Serverless基建的重心也倾向了dart生态,先是将dart容器打包到服务器上,实现dart编程语言的统一,在统一的容器之上实现编程框架一体化( ...

  2. 博途v15模拟量转换_基于博途V15 西门子S7-1200 + 模拟量SM 1234 正反转变频调速实例...

    一.准备工作 所需设备:西门子CPU 1215C AC/DC/Rly6ES7 215-1BG40-0XB0 SEW变频器MDX61B+通信模块DFE32B SM12346ES7 234-4HE32-0 ...

  3. java js 转换_[Java教程]javascript 类型转换。

    [Java教程]javascript 类型转换. 0 2016-10-11 18:00:06 目录: 1 : 伪对象 2 : 转换为字符串 3 : 数字转字符串 4 : 转换为数字 5 : 转换为Bo ...

  4. vue拆分js文件_基于Vue+Webpack拆分路由文件实现管理

    事实是,如果你的项目不是特别大,一般是用不着分拆的.如果项目大了,那就需要考虑分拆路由了.其实,这个操作并不复杂. 当我们用 vue-cli 工具,创建一个新的 vue 项目时,就已经给大家新建好了一 ...

  5. qiankun 微前端_基于qiankun落地部署微前端爬”坑“记

    ❝ 前沿:前半年微前端火得一踏糊涂,刚好业务需求上有这样的应用场景,针对目前的微前端解决方案做了技术选型,qiankun作为蚂蚁金服内部孵化出来的微前端解决方案,经过线上应用充分检验及打磨最后开源,最 ...

  6. video 微信 标签层级过高_基于大数据的用户标签体系建设思路和应用

    在大数据时代,数据在呈现出海量化.多样化和价值化变化的同时,也改变了传统IT行业的市场竞争环境.营销策略和服务模式.如何在ZB级的海量数据中获取并筛选有价值的信息,是对IT企业的一大挑战,通过构建客户 ...

  7. 大数据 客户标签体系_基于大数据的用户标签体系建设思路和应用

    如何设计一个完善的用户标签体系?怎么打标签?打哪些标签?谁来打?怎么使用用户标签创建商业价值? 在大数据时代,数据在呈现出海量化.多样化和价值化变化的同时,也改变了传统IT行业的市场竞争环境.营销策略 ...

  8. 大数据 客户标签体系_基于大数据的用户标签体系建设思路

    如何在ZB级的海量数据中获取并筛选有价值的信息,是对IT企业的一大挑战.通过构建客户标签,支撑精准营销服务,是应对上述挑战的有效解决方案. 但是怎么设计一个完善的用户标签体系?怎么打标签?打哪些标签? ...

  9. flutter图片聊天泡泡_基于 Flutter+Dart 聊天实例 | Flutter 仿微信界面聊天室

    1.项目介绍 Flutter是目前比较流行的跨平台开发技术,凭借其出色的性能获得很多前端技术爱好者的关注,比如阿里闲鱼,美团,腾讯等大公司都有投入相关案例生产使用. flutter_chatroom项 ...

最新文章

  1. poj 1085 Triangle War 博弈论+记忆化搜索
  2. android开发岗_android应用开发
  3. 通信协议——HTTP、TCP、UDP
  4. 蓝桥杯——机器人行走
  5. shell timeout
  6. Python教学视频(六)关系及逻辑运算
  7. C++密钥生成和数据加密
  8. UVM-1.1学习(一)——uvm代码的分类
  9. detach()函数的用法
  10. idea配置php开发环境以及配置debug
  11. 七牛云刷新缓存(cdn刷新)
  12. DEPICT实现基因优化(gene prioritization)、gene set富集分析(geneset enrichment)、组织富集分析(tissue enrichment)...
  13. 坚果新款 N1 评测
  14. 计算机内存采用什么存储模式,计算机内存模型
  15. 【ps】如何编辑*.psd文件中的已有文字
  16. CycleGAN在医学图像中的应用
  17. [ github ] 使用GitHub
  18. hypermill后处理构造器安装_NX后处理直白易操作教程
  19. 智能网联技术 英文_五分钟看懂通用V2V智能网联技术
  20. 无人驾驶汽车系统入门(三十二)——ROS2概述和实践入门(一)

热门文章

  1. f4 stm32 神经网络_STM32神经网络开发工具箱将AI技术引入边缘和节点嵌入式设备...
  2. java 获取js变量类型_JavaScript 的数据类型及其检测
  3. python多线程教程_Python多线程编程教程【2小时学会】
  4. ansible 安不安全_如何向您的安全团队介绍Ansible
  5. 来自Curriki和SankoréWiki的免费教育资源
  6. 搭建负载均衡器nginx_为什么要使用NGINX作为负载均衡器?
  7. ES6/06/ES6简介,ES6新增语法,let声明变量,const声明常量,var,let和const总结,数组解构,对象解构,箭头函数,剩余参数
  8. 高性能网站建设指南——网站优化的14条建议
  9. 推荐一个Python的开源小工具大合集!
  10. Bootstrap3 表单静态控件