當前位置:
首頁 > 最新 > Uber開源Fusion.js:一個基於插件架構的通用Web框架

Uber開源Fusion.js:一個基於插件架構的通用Web框架

作者|Addy Osmani

譯者|無明

編輯|覃雲

可能很多人都不知道,Uber 其實開發了很多基於 Web 的應用程序,可能有數百個,而且這個數字還在不斷增加中,它們中的大部分被用在公司內部,用於管理各種業務。

我們知道,Web 技術變化得很快,而最佳技術實踐也在不斷發展。為數百名 Web 工程師提供高質量的框架和功能,同時又要保持 Web 平台的動態特性,一直以來都是一個巨大的挑戰。

為了應對這一挑戰,Uber 的 Web 平台團隊開發了 Fusion.js,一個開源的 Web 框架,用於簡化 Web 開發,並構建出高性能的輕量級 Web 應用程序。

動 機

隨著 Web 最佳實踐的發展,Uber 需要改造已有的單體 Web 框架,解決長達數年的技術債務所帶來的挑戰。我們還希望讓工程師們能夠繼續使用他們喜歡的技術(例如 React 和 Redux),同時保持與 Uber 健康監控基礎設施的兼容性。

具體來說,我們希望核心框架能夠解決以下痛點:

伺服器端渲染、代碼拆分和模塊熱載入所需的複雜配置和工具樣板代碼在涉及伺服器端渲染的 React 應用程序時,缺乏用於實現和共享特性的良好抽象

不同位置的代碼緊密耦合而導致的脆弱性

測試難度攀升

單體框架缺乏靈活性

雖然現有的解決方案解決了其中的一些挑戰,但我們發現,基於框架添加新庫通常需要修改多個不相關的文件。例如,要讓可進行伺服器端渲染的應用程序支持 Redux, 通常需要在伺服器相關的文件中添加代碼,並在客戶端添加類似的代碼,還要向 HTML 模板中添加 hydration 代碼,使用 React Provider 組件等。要集成 i18n 庫或添加瀏覽器性能指標庫也是一樣。

很多特定於應用程序的代碼可能會依賴用於管理副作用的庫(例如用於日誌記錄或數據持久化的庫),工程師很難在沒有服務層抽象的幫助下以可測試的方式集成這些庫。

我們既希望能夠為與 Uber 現有庫集成提供簡單且經過實戰考驗的解決方案,也希望能夠避免使用單體框架,從而保持捆綁包的小體積。

我們傾向於選擇模塊化方法的另一個原因是,我們必須明確指定依賴關係,這樣可以更容易避免技術債務,如 God Object(https://en.wikipedia.org/wiki/God_object)、臨時內部介面和緊密耦合。

Fusion.js 是我們努力的結果。

誰應該使用 Fusion.js?

簡單地說,Fusion.js 是一個 MIT 許可的 JavaScript 框架,支持 React 和 Redux 等流行庫,並提供了很多現代特性,如模塊熱載入、數據感知伺服器端渲染和捆綁拆分支持。

除了預配置的樣板,Fusion.js 還提供了靈活的基於插件的架構。因此它非常適合用於現代單頁應用程序以及依賴複雜服務層來滿足各種質量要求的現代 Web 應用程序。

有關 Fusion.js 的更多信息,請查看項目文檔。

基於插件的架構

Fusion.js 應用程序是通用的,也就是說它有一個單入口文件,並且可以在伺服器和瀏覽器上重用代碼。在通用的應用程序中,React 組件還可以獲取數據並在伺服器上渲染 HTML,從而可以利用瀏覽器的原生 HTML 解析器和避免 JavaScript DOM API 的開銷來減少頁面載入時間。

單入口架構使 Fusion.js 插件本身也具有通用性,插件開發人員可以將代碼片段與代碼所屬的庫放在一起,而不是與代碼運行的環境放在一起。

Fusion.js 插件基於邏輯分組封裝邏輯,而不是基於需要添加代碼的位置

插件可以通過中間件訪問 HTTP 請求生命周期,也可以訪問 React 樹,以便添加 Provider 組件。它們還可以初始化瀏覽器代碼。

最後,由於這些特性,我們可以通過單行代碼將庫安裝到應用程序中,無論庫需要多少個不同的集成點。由於插件易於添加和刪除,因此在重構時也很容易推斷它們之間的耦合度、對包大小的影響以及其他代碼質量屬性。它們也可以初始化瀏覽器代碼。

類型依賴注入

插件利用了依賴注入,這意味著它們可以將定義良好的 API 作為服務暴露給其他插件,並且在測試期間可以輕鬆地模擬插件的依賴項。當依賴關係負責與數據存儲基礎設施打交道或與可觀察性(例如日誌記錄、分析和指標)相關時,這一點尤為重要。

還可以藉助 Flow.js 來確保依賴之間的靜態類型安全,如下所示:

直接在代碼編輯器中顯示錯誤有助於在代碼運行之前捕獲錯誤

中間件管理

幾年前就存在這樣的一個挑戰,流行的 HTTP 伺服器庫 Express 有一個 API 讓複雜的響應轉換變得難以封裝和測試。在 Uber 以前的架構中,應用程序開發人員經常需要採用臨時的包含 Express 請求 / 響應對象的特定補丁。自然而然地,因為子系統對時間要求的高度耦合,測試變得極其困難。

在開始設計 Fusion.js 時,我們就一直關注這個問題。經過大量調研,我們決定使用 Koa(https://koajs.com),它提供了基於上下文的 API,對單元測試非常友好,並為請求生命周期管理提供了一個基於下游和上游概念的輕量級抽象。

事實證明,採用 Koa 是一個正確的設計決策。

Koa 中間件為 React Provider 組件提供邏輯集成點,下游 / 上游抽象與 React 伺服器渲染上下文的生命周期完美匹配。網路副作用與應用程序邏輯分離,從而提高了可測性。

Fusion.js 的依賴注入和圖解析機制解決了困擾我們已久的 God Object 和操作順序問題。

Fusion.js 核心將網路副作用與應用程序狀態隔離開來,並利用 Koa 和 DI 來實現子系統之間的鬆散耦合。

可測性

在過去的幾年裡,JavaScript 生態系統中出現了大量高質量的測試工具,並提高了對測試技術的認識。

除了支持 Jest、Enzyme 和 Puppeteer 等現代測試工具外,Fusion.js 還為開發人員提供了測試插件的工具。fusion-test-utils 包允可用於模擬伺服器本身,從而可以在插件和各種樁的組合上快速運行集成測試。

前行之路

在 Uber 內部,已有 60 多個項目代碼庫在使用 Fusion.js。我們預計這個數字會繼續增加,因為新的 Web 項目也在不斷創建,同時舊項目被自動遷移到 Fusion.js。因此,框架級別的改進應該能夠顯著改善這些項目的軟體質量基準。

我們的路線圖包括添加更多的性能優化和面向測試的工具,以及更好的 Flow 支持。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 前端之巔 的精彩文章:

你可能從未聽說過這15個HTML元素方法!

TAG:前端之巔 |