大终端领域的新物种-KUN

作者:闲鱼技术——吉丰

1、KUN的 背景/动机

即使已经到了2022年, 在面向复杂多变的用户端开发领域,我们依然绕不开一个问题 ?我们选择什么技术更适应我们的业务场景,不管是通用还是独特。 这回到一个问题的原点,每一种技术都有它的局限性(短板)。

单一技术的缺陷

  • • Native技术的局限性
    • • 尽管Native技术在用户体验上有绝对的天然优势,但在工程化,部署效率,敏捷上又有天然的短板。
    • • (1)工程化效率低
      • • 工程复杂度高,由于天然的把所有的业务集成在一个工程里,依赖复杂性,工程复杂度高
      • • 编译效率低,切环境,编译打包,效率低。 这显著影响实际的开发效率。
    • • (2)部署效率低
      • • 由必须依赖用户的安装更新,生效周期长,导致实际迭代效率慢。
  • • Web技术的局限性
    • • 尽管Web技术是当今最流行的GUI技术,但受限于浏览器架构/渲染模型, 使其在体验上有天然的劣势。特别是在强调 “图片/动画/视频控制、长列表容器、多Tab容器”等场景显得力不从心。
    • • 涉及底层基础能力,必须依赖Native技术的增强。

更广义而言,这是C/S架构和B/S架构技术对比的缩影,历史上从以C/S架构为开始,到以B/S架构的大流行。 而PC互联网时代后,Native技术和Web技术在移动互联网上的继续相爱相杀。

烟囱式多种技术并存的挑战

技术上的乌托邦,理想的情况, 我们期望日常的业务软件开发关注于业务本身的复杂度(比如前台而言关注与,核心关注于业务模型复杂度/展示复杂度/交互复杂度),而不是更多的关注于技术工具本身的复杂性。 但实际的情况却相反, 我们往往考虑技术工具的问题,比如 什么场景下适合使用什么技术? 什么时候使用 native技术, 什么时候使用web技术, 什么时候使用非web的跨端技术, 什么时候使用某些特定领域的技术,随着业务场景越来越多,越来越复杂,我们的技术工具的数量也在不断的上升 。 每多增加一种技术工具,背后需要额外的投入, 1)如何学习熟练掌握一种技术工具。 2)如果不断优化提升技术工具,使之在质量和效率上不断提升。 3)技术工具之间的耦合关系 使得复杂度进一步上升, 为了解决这部分复杂度所需要的额外的成本。 4)组织效率的降低, 容易形成更多的开发瓶颈。

技术的割裂,对中小规模的技术团队的影响更加明显,因为技术的割裂,更加容易产生因为技术本身导致的人力瓶颈。

有没有一种技术,在效率、体验、通用性取得最大化的平衡。 甚至打破传统按技术栈粒度进行划分的职能边界, 统一到普遍意义上的终端开发工程师职能上。

KUN是什么

image.png

image.png

KUN 是一个让开发者使用 Javascript,HTML,CSS进行开发,使用Flutter进行增强的跨端开发框架。

它最早的雏形是来自Kraken, 正如 鲲 这个名字所内涵的:北冥(Kraken)有鱼,其名为鲲(Kun)。 Kraken将Flutter技术引入并应用于Web技术栈,而在和Kraken团队的交流中吸取了大量的优秀知识。 但我们并不希望去做一个仅仅基于Flutter渲染带裁剪的Web浏览器。相反,我们试图去完美融合Web生态和Flutter生态。 我们希望在面向中小规模的大前端/大终端的组织中,找到一种 真正适合的, 长期性的, 通用型 解决方案。 来解决 包括我们闲鱼技术团队在内的,大前端/大终端 所面临的 前端用户体验低、客户端效能低、团队技术割裂、技术协作成本高等一系列问题。

KUN 项目组是一个技术栈高度互补的团队,包含flutter、前端、native 多技术栈的关键专家开发者, 在这个过程中,缺少任何一方都将大幅度的降低所能达到的上限。

就像KUN Logo 所隐喻的,它既像一条大鱼又像一个猫身,它是对立和统一的结合体。

2、KUN 的独特价值

既然已经有了React Native, WEEX2.0, Kraken等跨平台开发框架,我们为什么还需要 KUN ?

React Native 试图去混合和连接 JS 生态和 OEM的GUI生态(Android生态 & iOS 生态)。但最大的问题在于其不同 OEM 生态之间天然的差异,去抹平它们之间的差异,是一件极具挑战的目标。 而舍弃操作系统 GUI生态,试图去重新构建一套 独立完整的GUI 系统去对接 JS 生态,是一件非常有抱负的目标。 它可能意味着在对齐W3C标准上的更高的上限,但同样这个方向上,挑战重重。

KUN站在巨人的肩膀上,做出独特的价值 - 开放性

image.png

image.png

(1)KUN 从一开始就不试图去达到完备的W3C的标准。

  • • 接受达到W3C标准(包括 html标签标识,CSS样式标准,WebAPI标准)的必要的子集对我们而言充分的。 我们在一开始就对我们的目标做取舍和精确的定义。

(2)KUN 基于Flutter GUI 系统和其生态,以极低的扩展成本,向上层JS运行时提供大量丰富的扩展标签/组件。

  • • KUN 不试图去构建全新独立的GUI系统, 也不去试图抹平多个操作系统GUI之间的差异。 最大程度结合JS 技术/生态和Flutter 技术/生态,取长补短,优势互补。

KUN 的开放性 是 KUN 最显著的特征。 通过更加开放和轻量化的容器设计和实现。 KUN 试图通过更加开放性的架构设计,去混合兼顾 JS & Flutter。 开放性, 技术上意味着

  - 有更广泛的通用性  - 更大的生态/社区的支持  - 有更敏捷的响应性  - 有更长期的成长性
复制代码

结合闲鱼技术在flutter技术领域的天然优势,去混合连接 JS 生态 & Flutter 生态,通过更加开放 & 更加轻量化的设计,在效率,体验, 通用性上去取的最佳平衡。

基于将Flutter生态融入到Web生态中,同时高度的开发性,有着更加广泛的通用性,使得从技术和组织的各种为政,从烟囱式的多技术栈,有机会向分层的技术融合转变,走向技术统一,最后进一步到组织融合成为可能。不再按细粒度的技术栈划分职能岗位,而是统一为职能更大类的终端开发工程师或者开发工程师转变。

这尤其在中小规模的技术团队组织中,产生更加显著的价值。

当然就这一融合目标的达成,需要考虑至少三个因素: 1、技术方案能不能行 2、组织内同学愿不愿意 3、外部环境趋势是否符合

3、KUN 的技术方案和面临的挑战

image.png

image.png

KUN项目第一语言是Dart语言,也包含少量的TS(负责WebAPI声明) & C++(负责跨语言通信)代码,以及极少的Java & OC代码(负责和操作系统相关)。

如何实现 Written in JavaScript、Html、CSS, Rendered with Flutter.

首先我们需要设定一个我们要完成的目标的边界。没有边界的目标是虚无的。我们明确,不需要实现所有的W3C标准,即使在未来也没有这一方面的企图。 所以我们在 KUN 容器诞生过程中,除了整体参照阿里巴巴集团现有的跨平台标准外,同时考虑适用性、可测性、易开发、易遵循等原则。

1. 适用。适用于闲鱼业务,满足闲鱼大前端绝大部分业务需求;适用于移动端,摒除非移动端视角,完全适用于移动端开发的容器标准;2. 可测。标准定义包含完整的功能边界,可依据标准测试用例保障单测。3. 易开放。未来非闲鱼 App 可快速接入符合标准的容器;大前端同学可快速上手,存量业务可快速迁移。4. 易遵循。定义出明确、合理的优先级,容器可按照优先级阶段性实现最符合大前端业务的 一、二、三环。
复制代码

如果从零开始完成这项工作,那无疑是非常艰巨又漫长的。好在我们可以站在巨人的肩膀上。通过借用大量的优秀的开源基础库/项目来帮忙完美更快更好的完成这一目标。

  • • 使用 开源QuickJS 解决JS 运行时问题。
  • • 使用 开源YOGA 库, 解决使用CSS布局问题。
  • • 使用 开源Kraken部分源码 和 CSSLib库 完成CSS样式的定义/解析/计算以及选择器能力。
  • • 复用 Flutter已有的Widget和API,进行灵活的组合,解决CSS 渲染问题。
  • • 使用 CDP 协议,去解决开发者体验问题。
  • • 使用 Flutter golden test 解决测试用例的效率问题。

尽管以上并不解决所有问题,但已经覆盖很多了,给我们更大的空间去解决其他更关注的问题点。

关于 CSS样式 的绘制:

如何使用已有的Flutter组件和API的组合,来完成对CSS样式渲染和事件的支持能力

  • • 典型代码举例:

  • image.png

    image.png

  • • 备注:其中任意的一小段函数,比如 增加Appear/Disappear事件

  • image.png

    image.png

绘制 CSS样式 的复杂度远小于去实现 CSS样式的布局的复杂度。 使用Flutter已有的Widget和API去使得我们避免侵入到Flutter Render-Object层去做非常繁重的工作。同时我们必须承认,在任意阶段,我们对W3C的标准对齐是不完善的,所以需要我们不断通过更小粒度的组合去逐步完善。而某种意义上,我们发现Flutter技术和Web技术的很深渊源的部分,这使得我们完成这件工作变得简单。

关于布局:

  • • CSS 样式布局
    • • 基于 yoga & FFI, 我们能快速实现必要的基本子集。
  • • Flutter 扩展标签布局
    • • 并不需要额外的设计和处理,走原生Flutter Layout。
  • • 混合边界和约束处理
    • • 在 标准html标签 和 Flutter 扩展标签 的互相嵌套中(可以嵌套的非常深),我们需要定义它们的布局边界和上下级之间的大小约束关系。

一种简化的脱离文档流和层叠样式实现

image.png

image.png

备注:KUN的DOM-Tree/Layout-Tree/Render-Tree 本质上是三组不同的指针形成的三棵树,而其Element是同一份。当DOM-Tree首Driver驱动发生变化时,Layout-Tree和Render-Tree 会同时发生变化。

关于更新机制:

  • • 更新主要包含两个动作:标脏、刷新
  • • 标脏:
    • • 基于以JS驱动的主动变更的标脏
    • • 基于以Flutter驱动的被动变更的标脏
    • • 基于运行时Widget构建的自动依赖收集的标脏
  • • 基于标脏后的最小化刷新机制
    • • 最小化必要的yoga layout的重新计算
    • • 很好地借用了Flutter已有的刷新机制,只有真实参与布局/绘制/事件有变化的Widget才会重新构建,触发最小化的刷新。

如何实现 ,几乎零成本的扩展

KUN 试图通过设计强大的开放系统, 将Flutter生态完整的提供给JS生态。

除了在架构分层上,显著的将微内核和开放层做了明晰的边界划分,在具体组件的开发性上做了很多具体的设计和取舍。

具体有几点: 1、在KUN的标签/组件系统里, 一个自定义标签和一个标准html标签是平等的。 它们都对应一个或一组flutter-widget, 它们都是扩展的组成部分。 2、自定义标签 和 标准html标签 之间的相互嵌套、约束关系,也是开放标签/组件系统的组成部分。 3、一个标准的html标签不是一个复合的巨型 flutter-widget。 它是由一系列可组合的flutter-widget构成。 原因是对W3C标准的实现,是一个过程,更细粒度的组合关系,有利于不断引入Flutter生态已有的部分,更高效的迭代演进。 4、引入一个自定义标签/组件,应该几乎是0成本的。 包括标签/组件的内部实现本身,以及去组合通用能力(比如style渲染,常用事件等),应该快速0成本的实现。

而基于丰富的Flutter组件生态, 和极低的扩展成本,极好的弥补了Web技术的天然缺陷。

四个步骤扩展并使用一个组件

  • • 创建组件
  • • 注册标签
  • • 生成文档
  • • JS使用

以一个简单的图片组件为例: (1)新建flutter组件 可以创建一个flutter组件,或引入一个已有的flutter组件。

image.png

image.png

(2)通过统一扩展接口KunDefs,注册标签

image.png

image.png

备注 >> 是一种能力组合方式, 用于让自定义标签快速获得额外的能力,比如通用的style的样式渲染能力或点击事件能力。

image.png

image.png

image.png

image.png

(3)在组件上加上必要的注解,用于自动生成组件文档和组件的TS定义(d.ts) 自动化完成,文档的更新发布 & 组件TS定义 npm 发布。

image.png

image.png

(*)可选的一码多端 在W3C标准上KUN容器是Web容器的一个子集, 在自定义标签上KUN容器是Web容器的一个超集。 一码多端是前端 为了适配 KUN容器和Web容器之间的差异,(想象一下历史上为不同浏览器做的兼容处理),但要简单得多,主要负责了如何将KUN容器上的增强标签能够降低到H5版本。可选。

(4)前端工程导入 d.ts 定义后,可以像React组件一样使用,带Lint检查和代码提示。

image.png

image.png

备注, 任意内置能力以相同的api进行扩展

image.png

image.png

如何实现 更好的面向更广泛的 Web开发者 和 Flutter开发者的体验

面向Web开发者

  • • 运行时面向标准Web-API 设计和实现

image.png

image.png

在这一层的标准上,我们高度借鉴了Kraken的理念,面向WebAPI设计而不是绑定具体一个前端框架。

对不同语言的指责做了明确的定义和划分: (1)Typescript 用于对WebAPI的声明部分; (2)C++ 用于跨语言通信的部分; (3)Dart 用于对接动态库的驱动的部分以及具体的KUN实现部分; 所以(1)(2)非常薄。

  • • 工程链路复用前端工程化
  • • DevTools 对齐 Chrome DevTools

基于 Chrome DevTools Protocol , 对齐常用的日志查看/元素审查/盒模型查看/CSS调试/样式锚点/属性查看/控制台输入输出/Source源文件和定位/网络/存储/事件联动等

image.png

image.png

而基于FlutterForWeb技术,未来有机会将KUN开发调试环境集成进浏览器环境。

面向Flutter开发者

  • • 原生的flutter开发环境

    • • 运行KUN只需要最简单的flutter开发环境就够了, 它的依赖非常少。
  • • 极简的playground

    4、KUN的进展和规划

    KUN 目前支持 超过100 个 Web-API(包含DOM-API & BOM-API)

    • • 超过 30 种 html 标签。
      • • 覆盖 文档节点/文档元信息节点/片段节点/内容组/语义内容组标签/语义文本标签/嵌入式内容/脚本等
    • • 超过 30 种自定义开放组件/标签。覆盖内容/容器/动画/输入等
    • • 支持超过100个属性定义的CSS样式,覆盖
      • • 覆盖布局/盒模型/字体、文本/颜色、背景/边框、圆角/变形、过渡/动画/效果处理(滤镜、遮罩等)/@规则支持/层叠上下文 等属性。
      • • 覆盖包括绝对单位/相对单位等15种单位,和包含继承等在内的5种值属性.
      • • 覆盖至少3种基础选择器。
      • • 较好支持 层叠上下文
    • • 支持63个BOM-API,覆盖定时/跳转/URL/环境/Location/屏幕/存储/日志等
    • • 并为此建立了超过1100个test-cases的高效的自动化测试系统。
      • • 基于flutter golden test,5分钟内完成像素级截图对比。
      • • 微内核和扩展,行覆盖分别超过80%和70%。

KUN的业务进展介绍 基于极强的业务需求驱动,KUN 已经在闲鱼导购场景/基础链路场景, 灰度或已经全量。 以闲鱼典型的“我发布的”页面为例:

image.png

image.png

通过技术升级从H5升级到KUN, 降价交互组件体验升级,显著大幅提升了业务的重点指标。

后续包括新版闲鱼号等核心基础链路和双11核心互动场景都将基于KUN落地。

KUN的规划

这个项目的从最初是一个带有一点验证性的项目, 但随着项目逐步在业务中的落地应用, 它让我们的理想变得更加触手可及。一种技术适合闲鱼前端&客户端,覆盖全业务域场景。

2022 Q4 Roadmap ,会重点关注一下几个方面: 1、支持包括双11在内的更多的重点业务; 2、更多维的性能优化; 3、基于KUN的组件库建设; 4、开发者体验; 5、CI & Test & Document 的持续建设;

最后, 如果你会Web应用开发,你可以通过KUN创建一个原生性能的移动应用程序。 如果你会Flutter应用开发,你可以通过KUN创建一个动态化的移动应用程序。 如果你的团队同时会Web应用开发和Flutter应用开发,你可以通过KUN,使用Web技术开发,Flutter技术增强你的移动应用程序。 结合Web技术和Flutter技术各自的优势互补,以及它们背后良好的生态和社区支持,你有机会使用一种技术来来覆盖你的所有上层业务。 KUN是一个新物种,有机会去完成这一点。

猜你喜欢

转载自juejin.im/post/7145655999439831071