Modern.js:Hello world!

語言: CN / TW / HK
 
 
 
 

概要

​7月,位元組跳動 Web Infra 做過一次主題為《邁入現代 Web 開發(位元組跳動的現代 Web 開發實踐)》[1]的分享,在分享中我們梳理了「傳統前端技術棧」的典型組成部分,展示了其中每個部分都存在的瓶頸問題。並介紹了在這些問題的驅動下,業x x x x界正在發生從「傳統 Web 開發正規化」到「現代 Web 開發正規化」的「正規化轉移」。在這個分享的最後預告了 Modern.js 的開源專案。

10 月 27-28 日的稀土開發者大會[2]上,位元組跳動 Web Infra 正式發起 Modern.js[3] 開源專案。在專場分享《介紹  Modern.js —— 現代 Web 工程體系》中,第一部分先介紹了業界和位元組內部的前端開發、Web 開發在發生哪些影響深遠的變革,從這些變革的角度,展示了基於 Modern.js 的現代 Web 開發。

這些變革包括:

「更多「前端開發者」成為「應用開發者 / 產品開發者」。」

先討論了什麼根本因素在驅動這種轉變,"Frontend Focused" 的意義,指出伺服器端開發門檻不斷降低的長期趨勢、原有基建的缺陷,用 Modern.js 演示了「一體化、無伺服器化的全棧開發」、「以客戶端為中心的 Web 開發」。

「從「前後端分離」到「前後端一體化」。」

分析了「前後端分離」產生的兩種前端專案,為什麼其中一種是「假分離」,另一種「不完整」,用 Modern.js 演示了「前後端一體化」在哪些地方帶來改變。

「Meta」 「Framework 取代傳統「前端三劍客」。」

分析了四代「前端三劍客」,以及每一代都被下一代的成員「吞併」的規律,結合位元組內部的真實案例,講解了 Meta Framework 的角色。

「形成基於「前端技術」的成熟 GUI 軟體研發體系。」

先明確了「前端技術」的定義, 結合 Modern.js 的功能和設計,討論瞭如何實現「充分抽象」,才能解決 DX 和 UX 的矛盾。

「智慧化、平臺化、低碼化。」

接下來第二部分系統介紹 Modern.js 的六大要素,包括:

「普及:現代 Web 開發正規化。」

回顧了這種正規化的 9 大主要特徵。

「核心:現代 Web 應用(「MWA」)。」

從 Universal App、一體化、應用架構、Runtime API 這四個角度來了解 MWA。

在應用架構部分介紹了 Modern.js 中 Model 的設計和背景。

「內建:前端工程最佳實踐。」

列舉了幾個典型的最佳實踐,包括 Post-Webpack Era 的新工具趨勢、Modern.js 的 Unbundled 開發,Modern.js 推薦的「CSS 三劍客」,Modern.js 微前端專案跟直接使用 Garfish 的微前端專案對比、模組工程方案和 Monorepo 工程方案中的最佳實踐。

「包含:Web 開發全流程。」

演示了 Modern.js 在「編碼」環節的微生成器功能、在「除錯環節」的微前端除錯。

「提供:工程標準體系。」

「鼓勵:定製工程方案。」

末尾介紹了除已經發布的開源專案,還有哪些對現代 Web 開發者有幫助的事情在發起和推進中。也介紹了 Modern.js 當前高優的社群計劃。

 

歡迎大家掃碼入群,一起討論交流

分享實錄

大家好,我是來自位元組跳動 Web Infra 的宋振偉,在位元組跳動,我們部門負責打造和發展「Web 技術中臺」和「前端研發體系」。

今年7月,我們做過一次主題是《位元組跳動的現代 Web 開發實踐》[1]的分享,在分享中我們梳理了「傳統前端技術棧」的典型組成部分,展示了其中每個部分都存在的瓶頸問題。

也介紹了在這些問題的驅動下,業界正在發生從「傳統 Web 開發正規化」到「現代 Web 開發正規化」的「正規化轉移」。

在這個分享的最後也預告了 Modern.js 開源專案。

昨天上午的主題演講[6]中,位元組跳動正式釋出了 Modern.js[7]。今天的專場分享,我想結合位元組內部的變革和實踐,介紹基於 Modern.js 的現代 Web 開發,和所帶來的實際效果。

議程

今天的分享可以分成三個部分。

昨天的主題演講有說到,整個業界和位元組內部的前端開發、Web 開發,都在發生著影響深遠的變革,我們首先從這些變革的角度,看下基於 Modern.js 的現代 Web 開發是什麼樣子,有什麼區別。

然後,我們整體看下 Modern.js 有哪些要素和收益。

最後再看下除了已經發布的開源專案,還有哪些對現代 Web 開發者有幫助的事情在發起和推進中。

我們先來看第一部分「現代 Web 開發」

一、基於 Modern.js 的現代 Web 開發

1.1 更多「前端開發者」成為「應用開發者 / 產品開發者」

可以從這五個方面的變革,來展示「現代 Web 開發」是什麼樣子。

這五個變革之間是承前啟後的關係。首先最根本的推動力,不是來自技術側,不是前端開發者一廂情願的發展自己主觀的技術偏好,而是在網際網路和 IT 行業、市場需求、使用者產品這一側的大趨勢,需要更多「前端開發者」成為「應用開發者」或「產品開發者」,鼓勵和倒逼著技術領域,不斷產生更有利於這種需求的技術形態和基礎設施。

當傳統技術正規化遇到瓶頸,不再能進一步適應需求,就會發生「正規化轉移」,出現從一開始就針對這種需求重新設計的、新一代的技術正規化。

這種轉變推動前端技術領域出現了「從分離到一體化」、新一代「前端三劍客」的變革。

這種變革帶來的新一代技術標準和基礎設施,開始形成完全基於「前端技術」的成熟 GUI 軟體研發體系,並且進一步朝著平臺化、低碼化的方向發展。

1.1.1 "Frontend Focused" 的意義

我們剛才一直在說「前端」,「前端」這個概念似乎一直是隻有開發者才關心的技術細節,但最近幾年,卻變成了商業領域、投資機構也都很關心的事情,全球市場上湧現出越來越多的新一代雲平臺和研發工具產品,多數都涉及前端研發特有的需求和模式,其中還有很多像 Vercel 這樣明確「專注於前端」的產品。

就像幻燈片上這張圖,雲端計算和研發產品最初是從最接近機器的底層開始發展,從虛擬化,到容器編排,到基於容器技術的各種平臺化、服務化的研發工具形態,這個階段是後端技術主導的,整個趨勢是越來越向上層發展,越來越接近市場和商業價值最終所在的地方——也就是面向使用者的產品,因此必然會發展到前端技術主導的抽象層,讓應用開發和產品開發能更專注於使用者需求,而越來越不需要關心伺服器端的複雜性和專業技術細節。

所以市場需求會趨向於推動應用開發方式往「專注於前端」的方向的發展,專注於前端就是專注於使用者,而專注於使用者是多數企業、產品的根本利益所在

1.1.2 最大的開發者群體

另一方面,從進入移動網際網路時代開始就不斷大幅增加的應用開發需求,現在不但沒減弱,反而還在加強,比如幻燈片上 IDC 的預測,要滿足這麼龐大的應用開發需求,傳統開發方式和人才儲備是很不夠的,需要讓儘可能多的開發者能獨立、完整的開發這些應用,而前端技術棧的開發者,正是最大的開發者群體和技術社群。

所以在使用者、產品、市場這一側,一直有趨勢和壓力,需要更多「前端開發者」成為「應用開發者」或「產品開發者」,鼓勵和倒逼著技術領域,不斷產生更有利於這種需求的技術形態和基礎設施。

1.1.3 伺服器端開發門檻不斷降低

在這種客觀趨勢的推動下,基於 Web 技術的應用開發中,伺服器端的佔比和門檻一直在不斷下降,國內大廠的中臺建設,提供了大量不跟特定客戶端捆綁、專注於資料需求和底層業務邏輯的 API,讓產品開發更聚焦在上層的客戶端業務邏輯。還有 BaaS 和基於雲函式的後端雲 Serverless,也進一步降低伺服器端的門檻,讓前端開發者能更獨立的、端到端的完成產品開發。

但要進一步降低門檻,提高效率,這些基礎設施的一個缺陷就暴露出來,就是他們都把應用依賴的 API,放在應用專案之外維護,跟前端研發是割裂的。

還有一個缺陷是它們不解決 API 之外的伺服器端需求,比如路由、SSR 等。

有一個位元組內部的典型例子,前端開發者在自己實現的 SSR 專案中,始終用 HTTP 方式請求外網域名的 API 來獲取資料,導致 SSR 頻繁超時,HTML 響應慢嚴重影響使用者體驗。可以給前端開發者做培訓,讓他們具備足夠的伺服器端開發思維和知識,知道要在 SSR 環節切換成內網的請求方式,還要考慮快取機制等,但更根本的解決方法是遮蔽這種伺服器端問題和實現細節,自動處理這些問題。

1.1.4 一體化、無伺服器化的全棧開發

因此伺服器端門檻不斷降低的趨勢,自然會發展到「一體化、無伺服器化的做全棧開發」的階段,讓前端開發者直接開發 「接近純前端的專案」而不是 「Node.js 框架專案」,感覺就像沒有伺服器一樣。

幻燈片上是這次分享中第一個 Modern.js 的 demo, 左側是一個 Modern.js 應用專案的完整目錄結構,src/ 目錄下的應用主體,可以像呼叫普通函式檔案一樣訪問 api/ 目錄下的 BFF 函式,不需要了解網路細節,Modern.js 會自動基於 BFF 函式的路徑、引數等自動生成 REST API,在 CSR 過程中自動請求。

接下來我們在 package.json 的 modernConfig 配置裡啟用 SSR、「差異化分發」和「自動 Polyfill」,可以看到這些功能不用增加程式碼邏輯,只需要靜態開關配置。

構建後,幻燈片左側可以看到產物裡的 HTML 和 JS 都有 es6 和 es5 兩個版本,使用者訪問時應用的時候,Modern.js 的 Web Server 會根據瀏覽器 UA 選擇分發 es6 版本還是 es5 版本,也就是「差異化分發」。

右邊上面的圖是現代瀏覽器的訪問結果,不會返回任何 polyfill 程式碼, 下面的圖是低版本瀏覽器的訪問結果, Web Server 會自動提供這個 UA 需要的 polyfill 程式碼。

可以看到 Modern.js 不但支援一體化的開發 BFF,也滿足 BFF 之外的伺服器端需求,儘可能自動利用自帶的 web server 去做效能優化和提供產品級的相容性,同時開發體驗仍然是無伺服器化的

之前我們啟用了 SSR, 左側圖上高亮的 HTML 片段,已經包含了通過 BFF 請求到的資料,會根據應用執行的方式自動選擇最高效的請求方式。

這種自動優化不會阻礙開發者對技術細節的掌控,右邊這張圖展示了 BFF 函式也會生成標準的 REST API,可以手動呼叫。

1.1.5 以客戶端為中心的 Web 開發

這種一體化、無伺服器化的全棧開發進一步發展,自然會得到一種客戶端為中心的 Web 開發方式。

比如在傳統 Web 開發中,要實現常見的許可權識別和重定向,除了前端頁面的邏輯,還需要在伺服器端的路由中,新增實現跳轉的業務邏輯。比如圖上,在訪問 home 頁面的時候根據 cookie 的值決定要不要重定向到登陸頁面。

同樣的需求,在以客戶端為中心的 Web 開發方式中,可以一體化的在客戶端程式碼裡實現,比如前面已經啟用 SSR 的 Modern.js 專案,只需要新增 Redirect 元件,就可以實現和剛才完全相同的許可權識別和重定向效果,訪問頁面時會根據 cookie 決定要不要返回 302 狀態碼。整個實現過程是客戶端思維的。

以客戶端為中心,不代表不能掌控伺服器端,不能直接寫伺服器端業務邏輯。

如果已經習慣 Node.js 框架的開發方式,可以 server 目錄的鉤子檔案裡,對框架自帶的 Web Server 新增自定義邏輯,比如自由新增中介軟體,可以在這個區域性,用自己熟悉的傳統 Web 開發方式實現許可權識別和重定向。

1.2 從「前後端分離」到「前後端一體化」

Web 專案的技術棧也在轉變,相當於是先發展出「前後端分離」,然後又用新方式迴歸了 「前後端一體化」

1.2.1 「前後端分離」

以前的 Web 開發就像圖上這個 Ruby on Rails 專案,圖中粉色的前端程式碼,「寄居」在圖中綠色的後端 Web 框架專案中的,前端和後端會互相干擾互相拖累,做工程建設也比較麻煩。

之後 Web 開發普遍轉變到「前後端分離」的模式,分離後的前端專案和後端專案,都傾向特定的型別。

後端專案不傾向包含 Web 的功能,而這時的前端專案可以歸納為兩種型別。

MERN 這種專案型別相當於又回到了分離前的狀態,整個專案是基於 Node.js 框架的,前端被嵌在裡面。這種結果其實反映出「前後端分離」實現的更多是分工上的分離,而不是技術架構上的分離,在技術架構上仍然沒有擺脫以伺服器端框架為中心的 Web 開發。

從 MERN 專案的結構可以看到,它不但是假分離,而且也不算一體化,React 代表的前端部分和 Node.js 框架代表的後端部分,在專案裡是涇渭分明的,沒有真正融合到一起去。

使用 Node.js 框架的專案,多數屬於這個型別。

「前後端分離」模式中另一種前端專案型別,我們稱作「老一代 JAMstack」,這種型別沒有假分離問題,就是純粹的前端專案。可以實現 SPA 和 MPA,也能基於編譯工具實現 SSG(靜態網站生成)。靠靜態託管來執行,鼓勵在 CSR 中呼叫 API 滿足動態的應用需求。

「老一代 JAMstack」最大的問題是,雖然分離成了獨立的專案,卻不足以承擔完整的應用開發,只能產出靜態檔案,依靠外部的 Web 伺服器去執行,無法實現 SSR,三大組成部分裡的 API,也需要在專案之外,用雲函式、獨立後端專案等方式來實現,不能跟著專案一起迭代。

用 CRA 或直接用 webpack 搭建的專案,多數屬於這個型別。

1.2.2「前後端一體化」

在前面說的需要更多「前端開發者」成為「應用開發者」的背景下,新一代的 JAMstack 專案用「客戶端為中心」的「前後端一體化」方式,解決了上面說的問題

新一代 JAMstack 的三大組成部分雖然沒變,對應的內容卻有很大變化,JS 部分更加函式化和元件化、以 JS 為中心,HTML 可以完全不在專案中出現,自動生成。BFF API 變成專案自包含。和之前簡單的靜態託管相比,基於前端 Serverless 平臺可以實現 SSR、SPR 等動態能力,即使是靜態頁面,也可以獲得很多好處,比如前面展示的 「差異化分發」。

圖上是用 Modern.js 的 demo 來展示新一代 JAMstack 專案。在開發中只需要聚焦在 JS 程式碼上,不論是 SPA 還是 MPA,HTML 都是自動生成的。不論是 SSR 渲染的程式碼,還是 API 邏輯,構建之後按照規範輸出到 dist 下的不同目錄,構建產物規範是 Serverless 友好的,支援把 Web、SSR、BFF 等拆分成不同伺服器。

前面提到 Modern.js 傾向於 JS 為中心、自動生成 HTML。但不阻礙開發者自己掌控 HTML。圖上是 Modern.js 渲染 HTML 的預設模板。

一體化 BFF 的呼叫,在前面的例子演示過,這裡可以看到 BFF 函式的檔案路徑是有約定的,可以實現任意設計的 REST API。

構建產物會針對 BFF、Web、SSR 分別生成獨立可執行的 Server,這是對前端 Serverless 平臺更友好的,Serverless 平臺可以自主選擇讓 BFF、Web、SSR 用不同方式在獨立程序中執行,不會互相干擾。比如在 SSR 環節遇到 app 程式碼的的記憶體洩露導致 SSR 超時,Web Server 不受影響,可以自動降級到 CSR 模式,返回靜態的 HTML 給使用者作為兜底,使用者的 HTML 請求始終不會超時或掛掉。

對於 SSR,同樣可以前後端一體化的開發,圖裡高亮的 useLoader 函式中的程式碼,同時適用於 SSR 和 CSR,如果這個 Loader 在 SSR 中已經預載入,CSR 就會自動跳過,否則會執行。

SPR 相當於有快取機制的 SSR,在 Modern.js 裡也可以一體化的開發,只要使用這個預渲染元件。

SSG 實際上就是在編譯時執行的 SSR,在 Modern.js 裡只要配置 SSG 路由,就會自動啟用這種編譯邏輯,給路由生成靜態 HTML。CSR、SSR、SSG 都是用同一份程式碼。

1.3 新一代「前端三劍客」和 Meta Framework

除了在技術棧層面向「前後端一體化」轉變,在工程層面,傳統的「前端三劍客」也在轉變成元框架這種新的工程基建。

1.3.1  傳統「前端三劍客」

先來回顧下傳統的「前端三劍客」,第 1 代和第 2 代如圖上所示,也被大家熟知。而第 3 代「前端三劍客」由檢視框架、Node.js 命令列、Node.js 框架三個方向組成。

其中 Node.js 命令列代表了工程化,其中最典型的是像 Webpack 這樣的打包工具,以及 Babel、PostCSS 這樣的編譯工具。

檢視框架和 Node.js 框架很好理解,就是之前討論的 MERN 專案中的前端和後端部分

1.3.2  第 4 代「前端三劍客」

隨著現代 Web 開發正規化的發展,第4代「前端三劍客」的輪廓已經越來越明顯,由元框架、前端 PaaS、低程式碼三個方向組成。其中低程式碼方向在昨天晚上稀土大會的低碼專場已經介紹過,而 Modern.js 就屬於元框架這個方向。

從這張圖可以清楚的看到,每一代前端三劍客中,都有一個方向,把上一代前端三劍客完整包含在自己裡面,變成不需要太關心的底層,讓自己取代他們成為前端開發的新地基。

第 3 代中的檢視框架,就扮演這樣的角色,把第二代的 HTML、CSS、JS 封裝在自己裡面,而第 4 代中的元框架,又對檢視框架、Node.js 框架、Node.js 命令列做了整合和抽象,成為前端開發和工程建設性起點,元框架扮演了過去 Webpack、React 扮演的角色

這張 JS 框架的 S 曲線圖,也能體現這種轉變。在左邊這個時期,發展的前沿、開發的起點,都是 React、Vue、Svelte 這樣的檢視框架,新的檢視框架專案也層出不窮。現在已進入右邊這個時期,前沿收斂到基於 React 發展更上層的元框架。

Modern.js 作為現代 Web 工程體系,是由元框架組成的,提供三大工程型別,鼓勵開發者基於工程型別建設自己的業務工程方案。

以位元組內部的「火山引擎子應用工程方案」為例,初始化的目錄結構沒有什麼變化,只在配置中預設載入了自己的框架外掛,外掛中通過 server 提供的 hook 修改渲染後的 HTML ,在原來的 HTML 上套了層殼,也就是右下角截圖中火山引擎統一的頂欄和左側導航欄。

這樣建設出來的工程方案,既能滿足垂直場景的需求或自己的偏好,又能保持跟三大工程型別的相容,自動獲得 Modern.js 的能力和收益

1.4 基於「前端技術」的成熟 GUI 軟體研發體系

在「前端開發者」成為「應用開發者」的大背景下,技術棧、工程基建的發展,開始形成基於「前端技術」的成熟 GUI 軟體研發體系。

1.4.1  什麼是「前端技術」

先明確一下我們一直說的前端技術,不是指做 UI 的技術,而是由 Web 原生語言、Web Runtime、Web 技術生態組成的技術棧,不是隻在瀏覽器裡才有前端技術,而是有 Web Runtime、有 Web 語言的地方,就有前端技術

1.4.2  DX 和 UX 同樣重要

傳統前端開發不是成熟的軟體研發體系,缺乏足夠的抽象和基建,導致 DX 和 UX 始終存在矛盾,此消彼漲。以往的產品開發中,習慣更重視 UX,這有兩方面的原因,一來是因為產品是由產品主導,因此更重視 UX, 不會過多關注開發者體驗,再就是缺乏足夠的抽象和基建,導致 DX 和 UX 之間必須犧牲一個。

在新一代更成熟的研發體系的支援下,已經可以實現 DX 和 UX 的同時最大化了,也從「更重視 UX」轉變為「DX 優先」的方式

要實現 DX 和 UX 的同時最大化,需要充分的抽象。比如前面提到的 Modern.js 的這個例子,專案裡只有三個檔案,就具備全面的能力,包括自動 Polyfill、差異化分發、SSR 等,既具備產品級的 UX,有保持了 DX 的簡單、開箱即用等

1.4.3  充分抽象

\

要實現充分抽象,需要讓專案從基於「庫、工具」發展成基於「框架」,這兩者的區別在圖上表現的比較好。藍底白邊部分是專案開發者自己寫的程式碼。左邊是傳統前端專案,由開發者手寫整個應用,把庫和工具當做積木來組裝,填補專案裡的空白。而右邊是 Modern.js 專案,整個應用是框架本身,開發者手寫的程式碼,是按照框架的要求填充到框架預留的位置上

要實現充分抽象,也需要在儘可能多的環節實現最大化的抽象,圖上體現了 Modern.js 除了像常規的框架一樣,在執行時和編譯時做抽象,也會在 IDE 編寫程式碼的環節,和部署產物的環節,引入最大化的抽象

\

要實現充分抽象,也需要解決前端模板的問題,Modern.js 把各種研發場景、專案型別,收斂和標準化成了始終固定的三個工程型別,其中「應用」工程方案,也就是 MWA,支援所有需要部署和執行的專案,「模組」工程方案支援所有需要實現程式碼複用的專案

1.5 智慧化、平臺化、低碼化

Modern.js 代表的現代 Web 開發,也在繼續朝著智慧化、平臺化、低碼化的方向發展

智慧化方面,當前可用的功能,是用 Modern.js 的初始化工具建立的專案,會開箱即用的在 VSCode 裡做好配置,啟用幾千條規則組成的 ESLint 全量規則集,加上按最佳實踐內建在 ESLint 裡的 Prettier,期望儘可能多自動修正問題,而不是僅僅提示問題。也追求儘可能多的讓 IDE 負責生成真正的原始碼,讓開發者手寫的程式碼變成跟 IDE 溝通的語言

在平臺化方面,Modern.js 的目標之一就是形成「工程標準」,讓各種前端 PaaS 平臺可以圍繞標準實現高階能力,比如圖上粉色部分列出的產品級 Web Server、差異化分發、SSR 兜底、ESR、微前端等,都需要結合程式碼層面的工程標準。

除了部署執行環節方面的平臺,有了工程標準之後,研發環節也可以引入更多低碼提效。

目前我們內部使用的研發平臺,可以直接在圖形介面上簡單操作完成 專案的建立、開發、部署。圖上右側可以看到圖形介面上展示了當前專案的的狀態: 入口數量、專案配置等,藍色框內新增應用的入口,一鍵從 「單入口」 轉變為 「多入口」 。右側在 Web IDE 中也能看到 src 目錄結構下的變化。

低碼化有兩個方向,一個是剛才說的跟研發工具結合,另一個就是研發從某些工作中解脫出來的低碼搭建,昨天的低程式碼專題中有介紹

總結

到目前為止,我們從這些變革的角度,展示了很多 Modern.js 的 demo 和效果

二、Modern.js 的六大要素

接下來我們系統的看一下 Modern.js 是什麼,Modern.js 提供了什麼。

2.1 普及:現代 Web 開發正規化

可以用這六大要素來說明 Modern.js 。

首先這個專案是希望能推動現代 Web 開發正規化的普及,發展完整的現代 Web 工程體系,突破應用開發效率的瓶頸。

前面討論「現代 Web 開發」的時候,已經展示過這種正規化的 9 大主要特徵。

其中 Serverless 正規化、平臺化、低碼化這三個特徵,在當前版本的 Modern.js 裡還沒什麼體現,需要後續會跟一些平臺配合提供。

2.2 核心:現代 Web 應用(MWA)

繼續看第二個要素。Modern.js 三大工程型別中最核心的就是 「現代 Web 應用」,簡稱 MWA,或直接叫「應用」。

2.2.1 從 Universal JS 到 Universal App

前面提到過,「應用」工程方案支援所有需要部署和執行的專案,把這些專案收斂成用同一套框架、同一套約定、同一套模板、同一套架構、一套 API 來開發。

反過來,我們也可以從 Universal App、一體化、應用架構、Runtime API 這四個角度來了解 MWA。

Universal JS 指同一份 JS 程式碼,既能在瀏覽器端執行,也能在伺服器端執行。Universal App 是它的進一步發展,同一份 App 程式碼可以在不同環節執行,也可以用不同的模式來執行。

首先是常見的 MPA 和 SPA 的需求,本質上是「伺服器端路由」和「客戶端路由」的需求。

在 Modern.js 裡它們可以隨意組合。

我們之前的例子都是單入口應用,只需要把 App.tsx 元件、pages 目錄這樣的入口標識放到 src 的子目錄裡,就能將單入口應用變成多入口的 MPA。會基於入口名稱,自動生成伺服器端路由,比如圖上的 admin-app 和 landing-page 兩個入口的 URL。

admin-app 和 landing-page  也分別都是 SPA,根據入口標識不同,一個使用基於元件的客戶端路由,一個使用基於檔案系統的客戶端路由。

然後是 MWA 中的「動靜一體」

之前演示過,一個靜態的 CSR 專案如何直接開啟 SSR、SPR、SSG 功能。

Modern.js 也支援 CSR 和 SSR/SSG 混用,比如圖上右側紅色高亮部分會在服務端被渲染到 HTML 中,藍色區域的日期時間,在 CSR 階段動態展示在頁面上。也就是整體 SSR + 區域性 CSR。

整體 CSR + 區域性 SSR的能力後續會加入。

在 BFF 支援方面,Modern.js 中還提供了型別友好的方式,可以通過 Type Schema 實現執行時自動校驗介面的引數和返回值。比如右下角請求時,引數 text 型別為 number 時,response 中會自動提示相應的錯誤。

Modern.js 還支援不同型別應用的開發和執行。

Modern.js 原生支援微前端,底層解決方案是 Web Infra 之前開源的 Garfish 微前端解決方案。一個 MWA 可以隨時變成微前端主應用,在配置中指定子應用列表的載入地址,Modern.js 就會自動在 Web Server 中預載入子應用資料,注入到執行時。在 Runtime API 的幫助下,可以像普通 React 元件一樣使用子應用。

MWA 也可以分別作為獨立的 Web 和微前端子應用的執行和部署。

MWA 在啟用 Electron 支援之後,能作為桌面應用來執行,專案裡會新增 electron 目錄用於寫主程序相關程式碼。除了開箱即用的 Electron 構建等能力,也提供執行時 API 支援 Electron 的常見需求和最佳實踐,進一步提升開發效率。

2.2.2 前後端一體化

第二個看待 MWA 的角度是 「前後端一體化」

之前已經演示過 BFF 函式,api/ 目錄下每個檔案就是 BFF 路由,當伺服器端邏輯更重的時候,可以加入 Node.js 框架元素,目前支援了 4 種不同的框架,還可以自己開發 Modern.js 外掛支援更多框架。

前面提到過:以客戶端為中心,不代表不能掌控伺服器端,不能直接寫伺服器端業務邏輯。

比如之前演示過的火山引擎子應用,除了通過框架外掛來實現,我們也可以在專案裡建立 server 目錄和鉤子檔案,新增修改 HTML 渲染結果的邏輯。

\

在只有 src 目錄,或有 api 目錄的情況下,MWA 類似 JAMstack 專案。

如果增加了 server 等鉤子檔案,MWA 就能像傳統 Node.js App 一樣直接寫伺服器端業務邏輯,使用 Node.js 框架外掛、中介軟體等。

如果刪掉 src 目錄,MWA 就是一個純 REST API 的專案。

我們把這三種模式之間隨意遷移的能力,稱作「三位一體」

2.2.3 應用架構

接下來,我們從「應用架構」的角度看看

傳統 Web 開發中的應用架構,等同於伺服器端應用架構,前端部分的架構要麼缺失,要麼需要專案開發者自己摸索、搭建,缺乏 API 支援和一致的抽象,難以跨專案複用業務邏輯。

如上圖,MWA 提供的開箱即用的、客戶端為中心的應用架構,可以通過標準化的 Runtime API,輕易實現 React 開發中缺少的 Model 層和 Controller 層。Model 作為封裝 UI 無關業務邏輯的積木,跟 UI 元件一樣可以複用和組裝。

之前 Web Infra 舉辦的 React 核心開發者線上訪談裡,Redux 作者 Dan 提到,狀態管理最重要的是理解狀態的型別,根據需要處理的狀態是什麼種類,來選擇對應的方案,

常見的狀態管理方案,都有適合的狀態型別和場景,很多時候需要混合使用,而不是一把錘子錘所有釘子,要麼所有狀態都放到全域性應用狀態裡,要麼所有狀態都在區域性狀態裡。

\

很多開發者不用 Redux,是因為 Redux 本身只能算底層 API,需要手動建立和維護 store,業務邏輯被 reducer,action 等分散在不同的地方,提高了維護成本。其實 Redux 社群一直有解決方案,比如 Ducks Modular 設計模式會把業務邏輯聚集在一起,Redux 官方支援的主流庫 RTK 也為解決這樣的問題而生。

Modern.js 的 Model 基於 Redux 進一步提高抽象程度,保留了 Redux 在不可變資料、資料流等方面的收益,對整個 Redux 生態相容,讓使用和不使用 Redux 的開發者都能受益。支援多種狀態型別,也支援不同的 Model 寫法

2.2.4 Runtime API 標準庫

最後看下 MWA 的 Runtime API 標準庫。

相當於「應用」層級的基礎 API,不止能在 MWA 裡使用,在 Modern.js 的模組工程方案裡,同樣可以使用這些 API,開發可複用的業務元件,支援獨立除錯和測試。

圖中最上面藍色方塊是業務開發中常用的 API,比如 useLoader,useModel 等 API。中間綠色部分就是前面提到的定製 web server、BFF 函式需要用到的 API,最底層的外掛 API,是整個框架的基礎,框架裡所有的包都是用外掛 API 來實現的,也可以用外掛 API 來擴充套件框架、定製工程方案。粉色部分包括很多重要的工具 API,比如 useLocalModel。

\

當應用中的元件需要拆分成獨立的模組複用時,實現中用到的 Runtime API  還能正常除錯、測試嗎,答案是肯定的,這套 API 相當於「應用」領域的 API 標準庫,不止能在 MWA 裡使用,在 Modern.js 的「模組」工程方案裡,同樣可以使用這些 API,開發可複用的業務元件,支援獨立除錯和測試。上圖右側是模組工程的目錄結構。左側 TableList 元件中使用了 useLoader API,除錯時只需要提供對應的 story 檔案,模組工程方案支援我們在 Storybook 視覺化測試以及單元測試中測試使用了 Runtime API 的元件。

2.3 內建:前端工程最佳實踐

對於第三個要素,簡單列舉幾個 Modern.js 內建的前端工程最佳實踐

2.3.1 Post-Webpack Era

傳統前端工程建設都是基於 Webpack 的配置封裝, Webpack 配置複雜和編譯緩慢的問題,大家應該都有比較深的感受, 但是從去年開始業界湧現很多新的工具,完全不涉及 Webpack,比如 Snowpack、 Vite、wmr 等,有人把它稱為 JS 第三紀元。

從第三紀元開始 esbuild、swc 這種編譯打包工具使用非 JS 的系統程式語言開發,顯著提高編譯速度。編譯時間的縮減也意味著不打包,按需編譯的 ESM 場景可以實現,

Snowpack、Vite 這樣的工具,就是在 esbuild 的基礎上實現的、開發者體驗優先的、不打包的開發除錯模式。在 Modern.js 中不打包的模式目前已經被用於公共庫的構建、業務專案的開發除錯等真實場景。

Modern.js 中也內建類似 Snowpack、Vite 的不打包開發除錯模式,圖中左側啟用該功能之後,執行效果就像圖中右側那樣,開發伺服器在秒級啟動。

為什麼可以做到速度這麼快?主要是因為業務程式碼只有在請求時使用 esbuild 按需編譯,第三方依賴自動從 Goofy PDN 載入已經預編譯好的產物。

2.3.2 CSS 最佳實踐

在 CSS 開發方面,Modern.js 預設推薦圖上「CSS 三劍客」搭配使用,有需要也可以開啟 LESS/SASS 等前處理器和 CSS Modules 支援。

2.3.3 預設零配置、樣板檔案最小化

和以前把功能作為樣板檔案塞到專案裡相比,現代 Web 開發正規化下的最佳實踐是預設零配置的,同時樣板檔案儘可能簡潔最小化。之前我們也通過例子看到 Modern.js 專案手動建立非常簡單,只需要應用根元件和 package.json。

跟直接使用 Garfish 開發微前端主應用的專案做對比, 上圖可以看到直接使用 Garifish 的專案,需要手動執行 Garfish 框架、處理公用模組、路由等邏輯。除了執行時,還需要編譯環節自定義一大堆配置。直接使用還是有一定的成本。

\

之前的例子已經說過,在 Modern.js 中使用微前端,只需要在 web 應用的基礎上啟用微前端功能,提供子應用列表即可,每個子應用載入後就是元件,路由可以自己靈活組織。

2.3.4 構建產物規範

Modern.js 的模組工程方案,會並行編譯出多種符合社群主流規範的構建產物。

模組的編譯也是不打包的,更容易引入速度更快的工具比如 esbuild、swc 等。

2.3.5 Monorepo 工程方案

應用和庫如果分散在不同專案中開發的話,通過 npm link 除錯也比較麻煩,業界的主流方案通過 Monorepo 管理多個子專案, Modern.js 本身就是基於 pnpm monorepo 開發的,同時也將這部分最佳實踐收斂到 monorepo 工程方案,預設使用 pnpm 進行包管理, 左側是它的目錄結構, apps 對應的是 MWA 應用 、features/packages 對應是可複用的模組。

右側內部模組指的是不會發布到 npm、僅在當前倉庫下複用的庫。它本身不需要構建,同倉庫下的應用直接使用它的原始碼即可。monorepo 我們也提供了 new 命令,可以選擇建立應用或者模組。

2.3.6 更多

除了上面提到的一些最佳實踐,Modern.js 還提供了單元測試、整合測試、Visual Testing 等、ESlint 全量規則集等最佳實踐。這裡不一一展開介紹。可以查閱 Modern.js 文件進一步瞭解。

2.4 包含:Web 開發全流程

Modern.js 不只是在上述執行時、構建、除錯等方面提供了支援,它本身就覆蓋了 Web 開發的全流程。

在編碼環節,可以通過微生成器啟用某個功能或者新增入口,從 SPA 遷移到 MPA。和前面提到的通過研發平臺 「低碼提效」類似,還可以像圖上那樣在專案目錄下執行 new 命令選擇要啟用的功能。這個命令會自動重構我們的程式碼。

通過微生成器按需自動啟用的方式,可以放心的將一些功能作為外掛提供,也可以控制 Modern.js 初始化專案的體積。

在微前端子應用開發時,通常情況下主應用已經部署上線了,這時候開發子應用就需要結合線上的主應用一起除錯,解決方式之一是通過全域性代理子應用 JS 到本地,比較麻煩。

在 Modern.js 中,只需要主應用像圖中右下角那樣啟用 DEBUG 模式,之後開啟主應用線上連結,在 header 中設定需要開發的子應用資訊,server 會自動替換注入到 html 中的子應用列表資料。這樣也就可以讓線上主應用載入本地子應用。

在執行環節,傳統的 Web 開發模式,通常沒有提供生產環境執行專案的方式,MWA 專案本身自帶產品級的 Server,自己就能產品級的執行自己,比如圖上的自動 Polyfill 服務。之前也提過,結合 serverless 平臺,可以自動做一些優化,也可以在本地執行模擬生產環境的效果。

2.5 提供:工程標準體系

Modern.js 不只是一個現代 Web 應用開發框架,而是提供了整套的現代 Web 工程體系。

前面已經介紹過,我們將前端開發中涉及的場景收斂到 3 種:應用、模組和 monorepo。

不僅解決了業務模板數量爆炸的問題。融合後的工程型別,比如 MWA 不是多個場景簡單疊加,導致工程變的大而全,通過抽象可以做到很輕量,也能更容易交付一些之前不好實現的功能。

2.6 鼓勵:定製工程方案

Modern.js 鼓勵業務結合自身場景定製垂直的工程方案。

就像前面提到的火山引擎例子一樣,封裝外掛、微生成器、定製出自己的業務工程方案。

關於 Modern.js 六大要素的更多解釋和例子,可以到 Modern.js 官網進一步查閱。

三、Modern.js 社群和現代 Web 研發體系

最後我們一起看下除了已經發布的開源專案,還有哪些對現代 Web 開發者有幫助的事情在發起和推進中。

Modern.js 開源專案現在是剛起步的狀態,昨天上線的官網,以及最新發的 1.0 版,都是公測狀態,還需要更多意見、測試和實踐,希望大家多參與社群建設。

Modern.js 的起點是位元組內部的現代 Web 工程體系專案,現在大部分程式碼已經完全轉到 Github 上開發,工作流還在建設中。

雙月計劃、每週計劃、缺陷管理等,也都會全面轉到 Github 上公開推進。

當前版本還沒有包含 Roadmap 上一些重要功能,計劃以每週發版的節奏,把這些功能補上。

昨天的分享介紹了 「現代 Web 研發體系」中的其他部分,這些部分也都算是 Modern.js 的重要功能,後續會陸續對外開放,歡迎大家關注。

最後,歡迎大家掃碼入群交流,也可以在官網上通過快速上手和實戰教程瞭解更多 Modernjs 的細節使用部分。\

謝謝大家。

官網:https://modernjs.dev/

Github: https://github.com/modern-js-dev/modern.js

Reference

[1]《邁入現代 Web 開發(位元組跳動的現代 Web 開發實踐)》:https://zhuanlan.zhihu.com/p/386607009

[2]稀土開發者大會: http://conf.juejin.cn/xdc2021

[3]Modern.js: https://modernjs.dev/

[6]昨天上午的主題演講: https://conf.juejin.cn/xdc2021

[7]Modern.js: https://modernjs.dev/

點選直達官網,瞭解更多資訊。