大終端領域的新物種-KUN

語言: CN / TW / HK

作者:閒魚技術——吉豐

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 擴充套件標籤 的互相巢狀中(可以巢狀的非常深),我們需要定義它們的佈局邊界和上下級之間的大小約束關係。

一種簡化的脫離文件流和層疊樣式實現

  • • https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

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是一個新物種,有機會去完成這一點。