邁入現(xiàn)代 Web 開發(fā)(GMTC 2021 演講《字節(jié)跳動(dòng)的現(xiàn)代 Web 開發(fā)實(shí)踐》全文)
時(shí)間:2023-09-06 16:18:01 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2023-09-06 16:18:01 來源:網(wǎng)站運(yùn)營
邁入現(xiàn)代 Web 開發(fā)(GMTC 2021 演講《字節(jié)跳動(dòng)的現(xiàn)代 Web 開發(fā)實(shí)踐》全文):
前言:希望像做游戲一樣做 Web 開發(fā)的 dexteryy 同學(xué)今天在 GMTC 技術(shù)大會(huì)上又搞了一場「跨年演講」(內(nèi)容超多的意思),不但現(xiàn)場爆滿、超時(shí)嚴(yán)重,而且一如既往的講完之后只要把講稿和幻燈片拼起來就能發(fā)出來,大家可按需取用。
亮點(diǎn):為了方便大家理解,dexteryy 同學(xué)為這次分享畫了 90 張圖(工具是 Keynote),其實(shí)在內(nèi)部版《Modern Web Stack》里有 120 多張圖…
大家好,我是來自字節(jié)跳動(dòng) Web Infra 部門的楊揚(yáng)。在開始分享前先解釋下:
可以看到幻燈片上的標(biāo)題,跟會(huì)議日程里的標(biāo)題有些不一樣,「現(xiàn)代 Web 開發(fā)」這幾個(gè)字加上了引號(hào),做這個(gè)修改是因?yàn)?,原文很容易被斷句成「現(xiàn)代的,Web 開發(fā)實(shí)踐」,「現(xiàn)代」看上去只是一個(gè)普通的形容詞,其實(shí)「現(xiàn)代 Web 開發(fā)」是作為一個(gè)整體的專有名詞,來代指現(xiàn)在全球技術(shù)社區(qū)和全行業(yè)里,越來越重要的一個(gè)「大趨勢(shì)」(Megatrend)、一場正在進(jìn)行中的「范式轉(zhuǎn)移」。
今天這場分享的主題,就是字節(jié)跳動(dòng)如何把「現(xiàn)代 Web 開發(fā)」轉(zhuǎn)化成具體的技術(shù)棧和研發(fā)工具體系,在內(nèi)部廣泛落地和從中獲益。
這次分享的內(nèi)容可以分成三個(gè)部分。
第一部分,先整體回顧「傳統(tǒng) Web 開發(fā)」范式中的「前端開發(fā)」技術(shù)和工程體系,有哪些瓶頸問題。
第二部分,對(duì)于在這些問題的背后、在這些問題的驅(qū)動(dòng)下,正在發(fā)生的轉(zhuǎn)變,做一下歸納和比較。
第三部分,介紹字節(jié)跳動(dòng)在落地和推動(dòng)這種轉(zhuǎn)變中,發(fā)展和建設(shè)出的技術(shù)體系。對(duì)于字節(jié)這個(gè)「App 工廠」來說,這種發(fā)展相當(dāng)于一場「引擎升級(jí)」的過程。
大家都知道字節(jié)跳動(dòng)在業(yè)界有一個(gè)既含貶義也含褒義的外號(hào),叫作「App 工廠」,如果我們從軟件研發(fā)的角度來看待這個(gè)外號(hào),那其實(shí)在字節(jié)內(nèi)部,各種產(chǎn)品、工具、軟件應(yīng)用的開發(fā),比大家從外部看到的更像「App 工廠」:無論數(shù)量還是多樣性,形態(tài)和場景的豐富度,都是非常高、海量的。
而這些軟件項(xiàng)目中,基于 Web 技術(shù)、前端技術(shù)的,占了大部分(這并不是因?yàn)樽止?jié)有特殊的技術(shù)選型,而是行業(yè)的大背景和必然規(guī)律,我在19年一次關(guān)于「現(xiàn)代 Web 開發(fā)」的分享里有介紹過)。
由于字節(jié)有這種特點(diǎn),所以前端技術(shù)和工程體系中的問題和瓶頸,在字節(jié)會(huì)體現(xiàn)的很全面、很典型,很多時(shí)候也會(huì)體現(xiàn)的更明顯。
* 現(xiàn)代 Web 開發(fā)的現(xiàn)狀與未來:https://zhuanlan.zhihu.com/p/88616149
傳統(tǒng)的前端技術(shù)體系,無論在字節(jié)內(nèi)部,還是在全行業(yè),都可以總結(jié)為圖上這個(gè)樣子。
圖中從下到上,代表抽象層從底層到頂層。最右邊三個(gè)方塊,都從最下面延伸到了最上面,代表它們都是端到端的解決方案,跟左邊的體系,以及彼此之間,都是割裂的,包含大量重復(fù),這次分享因?yàn)闀r(shí)間關(guān)系,不講這幾個(gè)部分。
藍(lán)色的方塊都是代碼層面的,綠色的方塊都是平臺(tái)層面的。
這套體系是字節(jié)曾經(jīng)的主流,是從業(yè)務(wù)中自然發(fā)展出來的,但隨著這種發(fā)展趨于停滯,這套技術(shù)棧正在同樣自然的演變成歷史遺留的「祖?zhèn)骷夹g(shù)?!梗渲忻總€(gè)部分都有比較大的瓶頸問題。
我們逐個(gè)看一下圖里的每個(gè)問題域,首先是大家最熟悉的「前端腳手架」。
不管哪種形式的腳手架,本質(zhì)都是復(fù)制粘貼一堆樣板代碼,組成新的項(xiàng)目。
雖然跟建筑行業(yè)使用的腳手架一樣,都是在搭建過程中使用,用完就放到一邊,只留下搭完的項(xiàng)目。但建筑腳手架拆掉之后留下的建筑,有一套不能動(dòng)的鋼筋混凝土骨架,而腳手架生成的前端項(xiàng)目,是混雜在一起的樣板代碼,雖然有文件結(jié)構(gòu),但可以隨意修改,而且因?yàn)榛ê褪纠a混在一起,所以不僅是「可以改」,而且經(jīng)常是「必須改」樣板文件的內(nèi)容和結(jié)構(gòu),才能完成真實(shí)項(xiàng)目的完整搭建。
假設(shè)一個(gè)腳手架包含 A、B、C 三塊功能,用這個(gè)腳手架創(chuàng)建出的三個(gè)項(xiàng)目,最初都是一樣的,也都包含 A、B、C 功能。
接下來,三個(gè)項(xiàng)目必然需要在腳手架的生成結(jié)果上,做各種增刪改,可能是因?yàn)闃I(yè)務(wù)需求,也可能是因?yàn)榧夹g(shù)沉淀和工程改進(jìn)。時(shí)間長了之后,三個(gè)項(xiàng)目之間會(huì)差別非常大,如果要做統(tǒng)一的改進(jìn),或者把一個(gè)項(xiàng)目的沉淀和改進(jìn),應(yīng)用到另一個(gè)項(xiàng)目里,都會(huì)很困難。有時(shí)甚至要推遲需求開發(fā),先對(duì)這些項(xiàng)目做一輪統(tǒng)一的重構(gòu),但這也只能應(yīng)付眼下,之后這些項(xiàng)目仍然會(huì)繼續(xù)分裂和腐化。
另一方面,腳手架本身也在迭代改進(jìn),但因?yàn)槟_手架是一次性的,一用即拋,這些改進(jìn)不能對(duì)原先創(chuàng)建的項(xiàng)目帶來好處,引入這些改進(jìn)的成本,跟從其他項(xiàng)目里引入改進(jìn)的成本差不多。
進(jìn)一步看看腳手架中「項(xiàng)目模板」的問題。
腳手架的必然結(jié)果,是需要各種項(xiàng)目模板。不但腳手架建設(shè)者需要提供多種模板,覆蓋不同的需求,使用者也經(jīng)常需要復(fù)制原有模板,修改成新的模板,比如產(chǎn)品的技術(shù)形態(tài)是 SPA 還是 MPA,都會(huì)產(chǎn)生不同的模板。
圖上每個(gè)方塊,都代表一個(gè)真實(shí)存在的模板,可以看到這些模板中有大量重復(fù)、又不會(huì)完全相同的內(nèi)容,升級(jí)維護(hù)模板、在模板之間同步技術(shù)沉淀,都有成本。很多模板會(huì)缺少更新,長期停滯,把成本留給搭建項(xiàng)目的人。
如果從項(xiàng)目場景的角度出發(fā)來設(shè)計(jì)和維護(hù)模板,也有相同的問題。圖中的方塊是一些最基礎(chǔ)、最典型的場景,和場景中的技術(shù)需求,可以看到,不同場景之間的技術(shù)需求,重合度很高。
除了場景類型,一個(gè)項(xiàng)目還有很多類型維度,圖中的每個(gè)方塊,代表一種維度,比如按照?qǐng)D上的第三種維度,不同項(xiàng)目之間僅僅因?yàn)椤附M件庫」和「設(shè)計(jì)系統(tǒng)」不同,就要設(shè)計(jì)和建設(shè)不同的模板。
這些維度之間的排列組合,要么會(huì)導(dǎo)致模板進(jìn)一步分裂和數(shù)量爆炸,每種模板的維護(hù)成本更高,應(yīng)用場景更小,ROI 因此變低,更加傾向于停滯;要么會(huì)導(dǎo)致模板對(duì)很多維度中的需求,不做考慮,只覆蓋小部分需求,對(duì)項(xiàng)目開發(fā)的支持,局限在比較低的水平。
「傳統(tǒng)技術(shù)?!沟牡谌齻€(gè)問題域,來自前端工程化建設(shè)中常見的對(duì) Webpack 的「包裝」。
為了避免每個(gè)前端開發(fā)者都成為「Webpack 工程師」, 很多腳手架、工程化建設(shè),都會(huì)對(duì) Webpack 做圖上這樣的包裝,在最上層,提供圍繞編譯構(gòu)建的兩個(gè)命令 dev 和 build,搞出不同「規(guī)范」的配置文件和插件機(jī)制。
這種包裝的第一個(gè)問題,是抽象程度很有限,配置 API 的設(shè)計(jì)也五花八門,體現(xiàn)不同的個(gè)人偏好和業(yè)務(wù)經(jīng)驗(yàn),這種配置雖然被稱作「規(guī)范」,但在真實(shí)業(yè)務(wù)項(xiàng)目中存在感不高,業(yè)務(wù)項(xiàng)目還是要直接靠 Webpack 來解決很多問題,項(xiàng)目中包含很多 webpack 配置,腳手架模板也包含大量相關(guān)的樣板代碼,避免不了前面說的問題。
圖中這段話來自 Redux 作者 Dan 寫的一篇文章,講 JS 工具的配置 API 的設(shè)計(jì),這段話就是在講這方面的抽象和設(shè)計(jì)能帶來巨大的影響,有很高的門檻,需要非常嚴(yán)肅專業(yè)的對(duì)待,這種工作也需要高度的集中,而不是交給「Webpack 工程師」們搞各種各樣的「規(guī)范」。
* The melting pot of JavaScript: https://increment.com/development/the-melting-pot-of-javascript/
業(yè)務(wù)項(xiàng)目深度依賴 Webpack、包含很多 Webpack 配置,還帶來另一個(gè)問題:
JS 開發(fā)工具從去年開始又出現(xiàn)新一輪更新?lián)Q代的征兆,有人把這種趨勢(shì)稱作 「JS 的第三紀(jì)元」,新范式的項(xiàng)目涌現(xiàn),開始進(jìn)入到日常業(yè)務(wù)的開發(fā)實(shí)踐,很多場景下已經(jīng)沒有 Webpack。
* The Third Age of JavaScript: https://www.swyx.io/writing/js-third-age
圖中右側(cè)的 esbuild 和 swc 這樣的構(gòu)建工具,把編譯、構(gòu)建、打包、壓縮等在 Webpack 里屬于不同環(huán)節(jié)的部分,合并在一起,加上非 JS 的系統(tǒng)編程語言的幫助,大幅提升構(gòu)建速度。另一方面,也能支持 ESM 優(yōu)先的、不需要打包的構(gòu)建場景。
Snowpack、Vite 這樣的工具,在此基礎(chǔ)上實(shí)現(xiàn)了開發(fā)者體驗(yàn)(DX)優(yōu)先的、不打包(Unbundled)的開發(fā)調(diào)試模式。
這些工具和模式跟 Webpack 的設(shè)計(jì)有一些本質(zhì)矛盾,目前已經(jīng)被用于公共庫的構(gòu)建、業(yè)務(wù)項(xiàng)目的開發(fā)調(diào)試等真實(shí)場景里。
基于 Webpack 包裝的工程化建設(shè),第三個(gè)問題是:對(duì)項(xiàng)目開發(fā)的工程支持只停留在比較低的水平,比如就像 dev 和 build 命令一樣,局限于跟編譯構(gòu)建有關(guān)的環(huán)節(jié)。
而隨著行業(yè)和業(yè)務(wù)的發(fā)展,隨著前端技術(shù)的發(fā)展,一個(gè)前端工程的完整需求,就像圖中一樣,會(huì)包含藍(lán)色方塊代表的整個(gè)研發(fā)鏈路的每個(gè)環(huán)節(jié),以及每個(gè)環(huán)節(jié)下面,綠色方塊代表的工程需求。這些都超出了 Webpack 的能力范圍。
剛才說的這個(gè)問題,其實(shí)也是傳統(tǒng)前端工程化建設(shè)本身的問題。
傳統(tǒng)的工程化建設(shè),就像圖中文字說的,只能實(shí)現(xiàn)「代碼層面」的基礎(chǔ)建設(shè),在創(chuàng)建項(xiàng)目的時(shí)候,做的事情大部分都屬于「代碼初始化」。
現(xiàn)代的 web 工程和前端工程,越來越多的包含「代碼層面」之外的「平臺(tái)層面」。
圖中綠色方塊代表的,是靠「代碼層面」來實(shí)現(xiàn)工程需求,橙色方塊代表的,是要靠「平臺(tái)層面」才能更好實(shí)現(xiàn)的需求。
第五個(gè)問題域是,很多前端開發(fā)場景,比如像字節(jié)內(nèi)部的前端開發(fā),都在統(tǒng)一收斂到 React 技術(shù)棧,但 React 本身也是有局限的。
在 Web Infra 部門建立之前,字節(jié)內(nèi)部的業(yè)務(wù)方向,比如今日頭條和抖音,就已經(jīng)在推進(jìn)統(tǒng)一到 React 技術(shù)棧,目前字節(jié)的現(xiàn)代 Web 研發(fā)體系建設(shè),也有意收斂和圍繞著 React 來進(jìn)行。
選擇 React 的原因可以歸納為圖上這四個(gè),其中,符合技術(shù)趨勢(shì),設(shè)計(jì)演進(jìn)更快,走在最前面,這兩點(diǎn)讓 React 在基礎(chǔ)建設(shè)中,在有基礎(chǔ)建設(shè)團(tuán)隊(duì)支持的業(yè)務(wù)場景中,都具備很大的優(yōu)勢(shì)。
圖上高亮的這句話,很好的表達(dá)了 React 引領(lǐng)業(yè)界和社區(qū)發(fā)展的特點(diǎn)。
剛才在選擇 React 的原因里,還提到 React 龐大的生態(tài)紅利或驗(yàn)證規(guī)模。圖中可以看到,在比較貼近實(shí)際使用情況的依賴下載數(shù)據(jù)里,React 在絕對(duì)數(shù)量遙遙領(lǐng)先的情況下,增長勢(shì)頭也是更快的,React 生態(tài)下的 CRA、Next.js,單獨(dú)拿出來都達(dá)到或接近其他非 React 技術(shù)的使用量。
* https://www.npmtrends.com/@babel/preset-react-vs-@vue/cli-shared-utils-vs-next-vs-nuxt-vs-react-vs-react-scripts-vs-vue-vs-vue-loader-vs-vite
這種生態(tài)和規(guī)模上的差距,在國內(nèi)環(huán)境中也回避不了,國內(nèi) JS 開發(fā)者的數(shù)量差不多是全球的十分之一,所以單靠國內(nèi)開發(fā)者,影響不了整個(gè)行業(yè)和技術(shù)社區(qū)的生態(tài)和基建,導(dǎo)致在業(yè)務(wù)支持和工程建設(shè)中,React 目前都無法取代。
* 「全球的 JS 開發(fā)者已經(jīng)上千萬了」:https://zhuanlan.zhihu.com/p/111204309
但在工程體系中只靠 React 自己是遠(yuǎn)遠(yuǎn)不夠的,React 本身只解決視圖層的問題,距離一個(gè) Web 框架還缺很多東西,在框架層面上,React 是無偏見的,比如沒有限制路由實(shí)現(xiàn)、組件類型、SSR 解決方案等,也沒提供默認(rèn)的配置和工具體系,跟一個(gè)真正框架的必備要素,是完全相反的。
* Advancing the web framework ecosystem (Chrome Dev Summit 2019): https://youtu.be/QDljY2I1Pfw
由于 Webpack、React 都不解決全鏈路的問題,缺乏框架級(jí)別的解決方案,很多前端項(xiàng)目會(huì)把目光轉(zhuǎn)向發(fā)展時(shí)間更長、已經(jīng)形成框架級(jí)別基建的服務(wù)器端框架領(lǐng)域,但這方面的 Node.js 框架,也有瓶頸問題。
業(yè)界主流的 Node.js 框架 NestJS 的作者,在文檔首頁的設(shè)計(jì)理念部分,就指出 React、Vue、各種開發(fā)工具,都沒有解決「應(yīng)用架構(gòu)」的問題,而 NestJS 就是要提供開箱即用的應(yīng)用架構(gòu)。
傳統(tǒng)的前端開發(fā)局限于視圖層,跟完整的軟件開發(fā)、產(chǎn)品開發(fā)相比,最缺的就是「應(yīng)用架構(gòu)」。
* NestJS Philosophy: https://docs.nestjs.com/#philosophy
但是 Node.js 框架能提供的,只是「服務(wù)器端應(yīng)用架構(gòu)」,是以服務(wù)器端開發(fā)為中心的。
有些情況下,比如活動(dòng)頁面,客戶端部分本來就很薄,談不上「客戶端應(yīng)用架構(gòu)」,但這種情況下的業(yè)務(wù)關(guān)注點(diǎn)仍然在客戶端部分,如果基于有完整服務(wù)器端應(yīng)用架構(gòu)的 Node.js 框架去開發(fā)這種項(xiàng)目,對(duì)前端開發(fā)者來說有些偏離重點(diǎn)。
在另一些情況下,客戶端部分比較厚,這種情況下需要的「客戶端應(yīng)用架構(gòu)」,就像圖中右邊的藍(lán)色部分,跟左邊代表「服務(wù)器端應(yīng)用架構(gòu)」的橙色部分,是完全不同的,如果使用 Node.js 框架,藍(lán)色部分仍然需要自己摸索和搭建。
不管什么軟件架構(gòu),核心都是「分層」和「關(guān)注點(diǎn)分離」,完善的現(xiàn)代 Web 工程里,「服務(wù)器端應(yīng)用架構(gòu)」和「客戶端應(yīng)用架構(gòu)」不會(huì)割裂,而是混為一體的。
* The Clean Architecture: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
除了架構(gòu),Node.js 框架也解決不了前面說的其他問題,同時(shí)還引入了圖中右邊的新問題:
業(yè)務(wù)邏輯既分散割裂,同時(shí)又重復(fù),導(dǎo)致項(xiàng)目變得「低內(nèi)聚高耦合」。
在「前后端分離」之后從「后端項(xiàng)目」里獨(dú)立出來的「前端項(xiàng)目」,使用 Node.js 框架之后,又混入了很重的后端業(yè)務(wù)邏輯和研發(fā)需求。而 Node.js 框架隨著發(fā)展,本質(zhì)也越來越清楚:還是服務(wù)于專業(yè)服務(wù)器端開發(fā)的,降低不了前端開發(fā)者的服務(wù)器端開發(fā)門檻,這是一個(gè)最大的瓶頸。
從這張圖可以看到,包含服務(wù)器端部分的「前端項(xiàng)目」,并不是真正的「全棧」,只是包含了服務(wù)器端最上面的、很薄的一層,解決 Web 和 BFF 需求(注意這里說的 Web 是指處理 HTML 請(qǐng)求,而 BFF 這個(gè)詞在國內(nèi)有很多誤用,實(shí)際上是專指面向特定 UI 的 API 服務(wù))
對(duì)于前端項(xiàng)目里的這些服務(wù)器端需求,用 Node.js 框架來開發(fā),很多時(shí)候帶來的問題比解決的問題更多。
* The BFF Pattern (Backend for Frontend): An Introduction: https://blog.bitsrc.io/bff-pattern-backend-for-frontend-an-introduction-e4fa965128bf
最后,看下最底層的 IaaS 和 PaaS 部分。
傳統(tǒng)云計(jì)算中的 IaaS 和 PaaS,就像圖中的綠色部分,從最底層到最上層,有這樣幾層,最上面這層,有不同的平臺(tái)和服務(wù)形態(tài),傳統(tǒng)上,前端項(xiàng)目跟后端項(xiàng)目一樣,直接部署這一層上,比如字節(jié)內(nèi)部后端技術(shù)棧的項(xiàng)目,都部署在被稱作 TCE 的 PaaS 上,而前端技術(shù)棧的項(xiàng)目,以前也只能這樣部署。
* 《容器云在頭條的落地和實(shí)踐》:https://time.geekbang.org/dailylesson/detail/100016772
但是在這種 PaaS 上或直接在 IaaS 上做部署和運(yùn)維,對(duì)前端開發(fā)者來說,不但復(fù)雜低效,而且在很多前端部署需求上,沒有獲得任何支持。
比如圖中粉色部分中這些前端部署方面的通用需求。由于 IaaS 和 PaaS 都源自后端開發(fā)場景,是后端研發(fā)技術(shù)的平臺(tái)化沉淀,設(shè)計(jì)和演進(jìn)都天然的受到局限,對(duì)前端研發(fā)場景缺乏理解,就算理解,也無法在相同的基礎(chǔ)設(shè)施里去兼顧這些前端部署需求。
也就是說,多數(shù)前端項(xiàng)目和底層的 IaaS 和 PaaS 之間,存在一大片空白,也就是圖中粉色的區(qū)域。
在真實(shí)業(yè)務(wù)中,為了避免每個(gè)前端項(xiàng)目都直接跟 IaaS 和 PaaS 打交道,很多業(yè)務(wù)都會(huì)有意無意的做一些集中建設(shè),填補(bǔ)這片空白。
比如字節(jié)的一些 web app 項(xiàng)目,會(huì)由后端負(fù)責(zé)的 go server 來運(yùn)行。
很多有 SSR 需求的業(yè)務(wù),會(huì)搞一個(gè)統(tǒng)一的 SSR server 項(xiàng)目,在開發(fā)各種前端倉庫的時(shí)候,需要本地有 SSR server 的倉庫,才能運(yùn)行和調(diào)試這些前端項(xiàng)目。
像這樣的集中建設(shè),要么把前端項(xiàng)目中的正常組成部分,放到了前端開發(fā)者無法掌控的地方;要么反復(fù)重復(fù)的建設(shè)出被業(yè)務(wù)需求扭曲的部署方案,難以沉淀和演進(jìn),最大化的提效。
所以圖中粉色這片區(qū)域的空缺,該由什么來填補(bǔ),是傳統(tǒng)前端技術(shù)棧里的一個(gè)大問題。
回顧了「祖?zhèn)骷夹g(shù)?!沟倪@些問題,接下來我們看下在這些問題的驅(qū)動(dòng)下,業(yè)界和技術(shù)社區(qū)里已經(jīng)形成的趨勢(shì),這些趨勢(shì)帶來的發(fā)展和優(yōu)勢(shì),也反過來,讓前面說的這些問題變得更明顯,更急需解決。
這種趨勢(shì)可以歸納為「傳統(tǒng) Web 開發(fā)」范式到「現(xiàn)代 Web 開發(fā)」范式的轉(zhuǎn)變。我在圖中這兩次技術(shù)活動(dòng)上,分別介紹過「現(xiàn)代 Web 開發(fā)」范式的起源、背景和發(fā)展?fàn)顟B(tài),這里不再重復(fù)了。
* 現(xiàn)代 Web 開發(fā)的現(xiàn)狀與未來(JSDC 2019 演講全文):
https://zhuanlan.zhihu.com/p/88616149
* 理解現(xiàn)代 Web 開發(fā)(JSConf China 2017):
https://youtu.be/515pkXWHgnE
https://2017.jsconfchina.com/files/02-modern-web-dev-dexteryy.pdf
這種轉(zhuǎn)變,可以稱得上是一場「范式轉(zhuǎn)移」,原有的理解和習(xí)以為常的假設(shè)被打破,在原有的東西上小修小補(bǔ)解決不了問題,需要建一套新的東西,做出根本性的變化。
圖中左邊藍(lán)色部分是最能代表「傳統(tǒng) Web 開發(fā)」的一些技術(shù)棧和規(guī)范,右邊橙色部分是在「現(xiàn)代 Web 開發(fā)」趨勢(shì)下出現(xiàn)的技術(shù)棧和技術(shù)形態(tài),接下來把它們展開看看包含哪些要素,就會(huì)看到左邊的東西跟右邊的東西,差別非常大。
* 「范式轉(zhuǎn)移」:https://wiki.mbalib.com/wiki/%E8%8C%83%E5%BC%8F%E8%BD%AC%E6%8D%A2
Ruby on Rails 是「傳統(tǒng) Web 開發(fā)」范式的一個(gè)典型代表, 本質(zhì)上是以服務(wù)器端開發(fā)為中心的、MVC 架構(gòu)的「服務(wù)器端 Web 框架」,就像圖上右邊這樣,產(chǎn)出網(wǎng)頁和 API。
網(wǎng)頁部分需要的前端代碼和工程化,一般包含在同一個(gè)倉庫里,框架本身也會(huì)內(nèi)置一些前端相關(guān)的工程化,經(jīng)常會(huì)需要被專業(yè)全面的前端工程化替代掉。
* The Asset Pipeline: https://guides.rubyonrails.org/asset_pipeline.html
* Hotwire: https://github.com/hotwired/hotwire-rails
「十二要素應(yīng)用宣言」本質(zhì)上是一種工程標(biāo)準(zhǔn),是進(jìn)入云計(jì)算時(shí)代之后,服務(wù)器端應(yīng)用和工程項(xiàng)目中形成的規(guī)范,這套標(biāo)準(zhǔn)可以保證應(yīng)用能很好的運(yùn)行在「后端 PaaS」或其他的傳統(tǒng)云計(jì)算平臺(tái)上。
可以看到,在 Node.js 幫助下形成的前端工程規(guī)范,不管有沒有服務(wù)器端代碼,也都受到了這個(gè)規(guī)范很大影響。
* The Twelve-Factors App: https://12factor.net/
MERN 技術(shù)棧,是前端代碼和工程,從其他技術(shù)棧的服務(wù)器端框架中「分離」出來之后,又融合相同技術(shù)棧的服務(wù)器端框架,形成的「全?!归_發(fā)方案。
組成 MERN 的 4 個(gè)首字母,能體現(xiàn)這套技術(shù)棧的本質(zhì),也就是圖上右邊的 4 個(gè)組成要素,整體上還是以服務(wù)器端的研發(fā)方式、應(yīng)用架構(gòu)、平臺(tái)基建為中心的。
* MERN Stack: https://www.mongodb.com/mern-stack
在「現(xiàn)代 Web 開發(fā)」趨勢(shì)下,在國外被稱作「JAMstack」的技術(shù)棧,變得越來越清晰和主流。它還有另一種命名建議是圖中第二行的「SHAMstack」。
這兩個(gè)縮寫的首字母組合雖然不同,但就像圖中的推導(dǎo)結(jié)果,本質(zhì)是一樣的,都是由 4 個(gè)要素組成。
* JAMstack: https://jamstack.org/
* SHAMstack: https://css-tricks.com/jamstack-more-like-shamstack/
* "Content Mesh": https://www.gatsbyjs.com/blog/2018-10-04-journey-to-the-content-mesh/
再展開看這 4 個(gè)要素。
跟剛才說的 MERN 技術(shù)棧比較,Serverless 模式和基建取代了 M 代表的傳統(tǒng)后端基建;前端應(yīng)用的構(gòu)建產(chǎn)物 、 服務(wù)器端渲染、靜態(tài)網(wǎng)站生成、前端程序中的 BFF、等等,取代了 E 代表的服務(wù)器端 Web 框架和服務(wù)器端代碼。
這種技術(shù)棧的項(xiàng)目仍然是「全?!沟?Web 項(xiàng)目,但變成以客戶端研發(fā)方式、客戶端應(yīng)用架構(gòu)為中心,看上去很像是純靜態(tài)的、純前端的項(xiàng)目。
* ooooops I guess we’re* full-stack developers now: https://css-tricks.com/ooooops-i-guess-were-full-stack-developers-now/
還有人歸納了這種叫「STAR」的技術(shù)棧,本質(zhì)上是圖中右邊這4個(gè)要素組成。
同一個(gè)現(xiàn)代 Web 項(xiàng)目,可以同時(shí)符合 JAMstack 和 STAR,JAMstack 強(qiáng)調(diào)的是前后端架構(gòu)和開發(fā)范式,STAR 強(qiáng)調(diào)的是專業(yè)的編程方式。
特別要注意的是,STAR 其實(shí)體現(xiàn)了一個(gè)現(xiàn)代 Web 項(xiàng)目中的「前端工程化」,除了編譯環(huán)節(jié),也需要 Runtime 環(huán)節(jié)和代碼編寫環(huán)節(jié)的支持,除了視圖層,也需要完整的應(yīng)用架構(gòu)和 Model 層的支持。
* STAR Apps: A New Generation of Front-End Tooling for Development Workflow: https://css-tricks.com/star-apps-a-new-generation-of-front-end-tooling-for-development-workflows/
在「現(xiàn)代 Web 開發(fā)」趨勢(shì)下,國外技術(shù)社區(qū)里越來越多的提到 meta-framework,本質(zhì)上是把 JAMstack 和 STAR 強(qiáng)調(diào)的部分加起來,用以客戶端為中心的、包含更上層抽象的、通用的 Web 框架的形式,整體系統(tǒng)的滿足這些需求,抽象、簡化這里面的各種模式。
在「現(xiàn)代 Web 開發(fā)」里,這種 meta-framework 是更合適的基礎(chǔ)抽象層,取代了以腳手架和構(gòu)建工具為代表的更原始的基礎(chǔ)。
「S 型曲線」是一種事物「發(fā)展成長規(guī)律」的表示方法,這張 JS 框架的 S 型曲線圖,很好的表達(dá)了 meta-framework 在 JS 技術(shù)發(fā)展中的意義。
在圖中左側(cè)的早期階段,各種 UI 框架在行業(yè)和技術(shù)社區(qū)里不斷涌現(xiàn),包含各種各樣的嘗試和破壞性創(chuàng)新,隨著發(fā)展,UI 框架不再是快速發(fā)展的前沿了,選擇也不再那么多,技術(shù)發(fā)展逐漸穩(wěn)定和收斂成了基于 React 做上層的整合和框架建設(shè),這種框架變成了新的發(fā)展前沿,也產(chǎn)生了大量選擇,同時(shí)作為更成熟的技術(shù),以更快的速度被采納使用,之后又逐漸穩(wěn)定和收斂,形成主流技術(shù)。
* React Distros and The Deployment Age of JavaScript Frameworks: https://www.swyx.io/react-distros/
比較了「傳統(tǒng) Web 開發(fā)」和「現(xiàn)代 Web 開發(fā)」中的不同現(xiàn)象,最后我們來歸納和定義一下這兩種范式的本質(zhì)特征和組成要素。
從框架和 UI 的角度來看,「傳統(tǒng) Web 開發(fā)」是以服務(wù)器端框架為中心來做全棧開發(fā),客戶端是圍繞 HTML 和對(duì)象樹的編程范式。
「現(xiàn)代 Web 開發(fā)」是以新一代客戶端框架為中心來做全棧開發(fā),客戶端同樣圍繞專業(yè)、通用的軟件開發(fā)語言和編程范式。
從架構(gòu)的角度來看,「傳統(tǒng) Web 開發(fā)」中存在兩套比較獨(dú)立和欠缺融合的程序,「前后端分離」改善了分工協(xié)作,但對(duì)于分離出來的「前端技術(shù)棧的 Web 項(xiàng)目」,在架構(gòu)和開發(fā)范式上沒有真正實(shí)現(xiàn)「分離」,前端開發(fā)者需要跟服務(wù)器代碼打交道。
「現(xiàn)代 Web 開發(fā)」實(shí)現(xiàn)了在同一套程序里一體化開發(fā),在開發(fā)、調(diào)試、運(yùn)行、部署等環(huán)節(jié)都能做到「無服務(wù)器化」,讓前端技術(shù)棧的開發(fā)者更容易成為真正的「產(chǎn)品開發(fā)者」。
從抽象的角度來看,「傳統(tǒng) Web 開發(fā)」中前端部分的基礎(chǔ)抽象是原始、初級(jí)的,比如腳手架、樣板代碼、基本的 Webpack 包裝和 CLI 工具、React 和 JS 生態(tài)中的海量選擇,很有「前端特色」,跟成熟的軟件開發(fā)有顯著差距。圖中的 DX 是指開發(fā)者自身的效率,UX 是指開發(fā)出的應(yīng)用的能力和質(zhì)量,傳統(tǒng)范式中的抽象杭州始,導(dǎo)致 DX 和 UX 沒法同時(shí)提升,提升其中一個(gè),就會(huì)損害另一個(gè)。
「現(xiàn)代 Web 開發(fā)」中有了一體化的、更成熟的、框架級(jí)別的基礎(chǔ)抽象,能同時(shí)追求和確保 DX 和 UX 的最大化。
* What Is DX? (Developer Experience): https://medium.com/swlh/what-is-dx-developer-experience-401a0e44a9d9
* What is developer experience?: https://www.tiny.cloud/blog/developer-experience/
從部署的角度來看,「傳統(tǒng) Web 開發(fā)」的項(xiàng)目,要么純靜態(tài)托管,要么作為服務(wù)器端應(yīng)用來部署和運(yùn)維。不同部署方式,會(huì)導(dǎo)致整個(gè)工程都不同,需要不同的腳手架模板。
「現(xiàn)代 Web 開發(fā)」的項(xiàng)目有更多樣強(qiáng)大的運(yùn)行和部署方式,但在 meta-framework 的支持下,項(xiàng)目模板的變化變少了,申請(qǐng)有機(jī)會(huì)完全融合、收斂成一個(gè)模板,成為「Universal App」。
* "SPR": https://vercel.com/blog/serverless-pre-rendering
* "SSG": https://www.freecodecamp.org/news/static-site-generation-with-nextjs/
* "ISG": https://www.smashingmagazine.com/2021/04/incremental-static-regeneration-nextjs/
* "Micro Frontend": https://micro-frontends.org/
最后,從平臺(tái)角度來看,「傳統(tǒng) Web 開發(fā)」基于后端的云基礎(chǔ)設(shè)施,由于代碼層面缺乏抽象,客戶端代碼的復(fù)雜性容易停留在很基礎(chǔ)的程度,有些時(shí)候會(huì)干脆直接改成 JSON 之類的配置。
「現(xiàn)代 Web 開發(fā)」基于新一代 Serverless 平臺(tái)。在 Serverless 的支持下,能實(shí)現(xiàn)以前難以實(shí)用化的云研發(fā)。由于代碼層面有統(tǒng)一的、上層的抽象,在開發(fā)中能引入更多低代碼模式。
針對(duì)這些問題和趨勢(shì)背景,字節(jié)在起步比較晚的 Web Infra 建設(shè)中,主動(dòng)發(fā)展和建設(shè)了整套「現(xiàn)代 Web 技術(shù)棧」的研發(fā)體系,建立了「MWA」 —— 也就是「現(xiàn)代 Web 應(yīng)用」—— 這種工程標(biāo)準(zhǔn),形成了新一代「研發(fā)引擎」,支持了大量、多樣的真實(shí)業(yè)務(wù)項(xiàng)目。
之前第一部分里我們講了前端的「傳統(tǒng)技術(shù)?!故菆D上這樣子。
可以看到「現(xiàn)代 Web 技術(shù)棧」的這張圖,發(fā)生了非常大的變化,所以說這種轉(zhuǎn)變是一場「范式轉(zhuǎn)移」。
有幾個(gè)需要注意的變化是:
圖中綠色代表的平臺(tái)化基建,占比超過藍(lán)色代表的純代碼層面的基建。
沒有割裂,中間的研發(fā)平臺(tái)建立在「前端云」之上,工程框架基于研發(fā)平臺(tái)支持研發(fā)全鏈路,右邊的工程方案跨越上中下三層,是指可以通過工程方案,定制左邊這三層的需求。
這套技術(shù)棧在字節(jié)內(nèi)部,是一套被稱作「Goofy」的研發(fā)體系,可以看到圖中有多個(gè)名字里 Goofy 開頭的產(chǎn)品,既可以整體使用獲得更多高級(jí)能力,也可以單獨(dú)使用,其中最早推出、應(yīng)用最廣泛的,就是最下層的「前端部署平臺(tái)」,提供了 Serverless 的「前端云」模式,明天下午有一場分享是專門介紹這個(gè)部分的。
這次分享以圖中藍(lán)色部分代表的代碼層為主,這個(gè)部分的解決方案,形成了一套被稱作 Jupiter 的研發(fā)框架。
先通過視頻演示直觀的看一下。
屏幕上的這個(gè)應(yīng)用,是 Goofy 前端研發(fā)工作臺(tái)的 SaaS 版。
先在團(tuán)隊(duì)里創(chuàng)建一個(gè)工程項(xiàng)目。
默認(rèn)會(huì)推薦用這套基于 Jupiter 框架的、標(biāo)準(zhǔn)化的工程方案體系,這里選擇了 符合前面提到的 MWA 工程標(biāo)準(zhǔn)的「MWA 工程方案」。
后面會(huì)介紹這個(gè)工程方案非常強(qiáng)大,能力很多,但創(chuàng)建過程中需要做的配置很少,這里我們什么都不需要改就可以繼續(xù)創(chuàng)建。
可以看到除了初始化代碼,也會(huì)一站式的完成各種底層平臺(tái)的初始化和配置。
剛創(chuàng)建出來的項(xiàng)目,已經(jīng)是一個(gè)完備的工程,可以馬上執(zhí)行一次上線發(fā)布。
可以看到發(fā)布成功了,點(diǎn)擊自動(dòng)生成的域名,可以看到 Jupiter 框架的初始運(yùn)行效果。
接下來看看開發(fā)環(huán)節(jié)。
在一個(gè)開發(fā)任務(wù)里,進(jìn)入「代碼」面板,可以看到項(xiàng)目代碼的可視化展示和低碼編輯界面,這個(gè)界面顯示之前,會(huì)先初始化任務(wù)專用的 Web IDE 研發(fā)環(huán)境。
接下來直接進(jìn)入 Web IDE。
可以看到一個(gè) MWA 工程的代碼,是極簡、輕量的,只要在 src 下默認(rèn)導(dǎo)出一個(gè) React 組件,就能得到完善的 web 應(yīng)用,項(xiàng)目默認(rèn)是零配置的,看不到 webpack.config.js 之類的工程配置和樣板代碼。
接下來直接執(zhí)行 dev esm 命令,可以看到瞬間就啟動(dòng)了調(diào)試命令,幾乎沒有編譯耗時(shí),就生成了開發(fā)環(huán)境的訪問地址。
接下來快速做一段前后端一體化的開發(fā),可以看到我們?cè)?api 目錄下準(zhǔn)備了一個(gè) BFF 函數(shù)文件。
可以在 web app 代碼中直接導(dǎo)入這個(gè)函數(shù)文件,像普通函數(shù)一樣調(diào)用。
可以看到輸入代碼的過程中,我完全不關(guān)心代碼風(fēng)格問題,保存的時(shí)候,會(huì)自動(dòng)生成規(guī)范的、符合最佳實(shí)踐的代碼。
這里我寫錯(cuò)了 API,會(huì)自動(dòng)提示錯(cuò)誤。
這個(gè) useLoader 是 Jupiter 框架的運(yùn)行時(shí) API,能支持一體化的 SSR。
查看剛才打開的調(diào)試頁面,可以看到修改的效果,這段文本實(shí)際上是通過 BFF API 獲取到的,這個(gè)視頻忘記錄相關(guān)的演示。
接下來回到工作臺(tái)的低碼編輯界面,可以看到 MWA 工程的配置狀態(tài)。
把服務(wù)器端渲染功能開啟。
回到 Web IDE,可以看到 package.json 里已經(jīng)自動(dòng)增加了相關(guān)的配置。
打開調(diào)試頁面,從 HTML 文件可以看到整個(gè) UI,包括通過 BFF API 獲取到的內(nèi)容,都已經(jīng)在提前渲染好了。
可以看到這個(gè) MWA 工程的代碼雖然極簡,但能力已經(jīng)比很多代碼復(fù)雜的傳統(tǒng)前端工程都要更強(qiáng)。
剛才演示中的工程項(xiàng)目,在傳統(tǒng)前端開發(fā)里,是一個(gè)模糊、虛的概念,不止包含代碼,還包括研發(fā)環(huán)境和各種平臺(tái)上對(duì)應(yīng)的注冊(cè)和配置。
在字節(jié)前端研發(fā)體系里,「工程」被實(shí)體化了,在研發(fā)平臺(tái)上,「工程」是「看得見摸得著」的對(duì)象,可以創(chuàng)建和管理,在里面做所有研發(fā)相關(guān)工作,每個(gè)工程都包含全鏈路每個(gè)環(huán)節(jié),和一體化的工作流。
「工程」可以通過「工程方案」來一鍵創(chuàng)建,「工程方案」相當(dāng)于「工程」的「模板」,取代了傳統(tǒng)前端開發(fā)中的腳手架,而「工程方案」都有一個(gè)「工程類型」,這種類型相當(dāng)于「模板的標(biāo)準(zhǔn)」。
建立和維護(hù)工程標(biāo)準(zhǔn),推進(jìn)圍繞這些標(biāo)準(zhǔn)的基建和技術(shù)生態(tài),是 Web Infra 部門的工作重點(diǎn)之一。
目前的建設(shè)已經(jīng)基本完成了「工程類型」的收斂,形成了少量的、數(shù)量固定的「默認(rèn)工程類型」,能支持體系中各平臺(tái)的更多功能。Jupiter 框架實(shí)現(xiàn)了這些「工程類型」在代碼層面的要求。
每種「工程類型」,除了直接提供「默認(rèn)工程方案」,也支持開發(fā)者創(chuàng)建屬于這種類型的、自己的「業(yè)務(wù)工程方案」,能跟標(biāo)準(zhǔn)保持兼容和同步。
以 MWA 為例,這是默認(rèn)工程類型中唯一的 Web 項(xiàng)目類型,滿足所有 Web 項(xiàng)目的開發(fā)需求,傳統(tǒng)前端開發(fā)中的各種 Web 項(xiàng)目的模板,都被收斂成同一個(gè)「模板」。
MWA 之所以能承擔(dān)唯一 Web 項(xiàng)目類型的責(zé)任,是因?yàn)橛?MWA 框架的支持,MWA 框架不但是前面說過的 meta-framework,而且在 JAMstack 技術(shù)棧的基礎(chǔ)上繼續(xù)發(fā)展,把微前端、傳統(tǒng) Web 開發(fā)范式中的 Node.js Web 框架、等等,抽象融合到了一起。
這種融合不但不是簡單的疊加,導(dǎo)致工程變得大而全、更重。反而通過抽象變得更輕量更簡單,所以是 1+1<1,另一方面因?yàn)槟芤惑w化的考慮多種需求,能交付原本單個(gè)項(xiàng)目類型不好實(shí)現(xiàn)的功能,所以也是 1+1>2。
目前收斂得到的默認(rèn)工程類型,有圖上這些,每種類型都覆蓋一個(gè)在研發(fā)方式和工程需求上有本質(zhì)差別的場景領(lǐng)域,解決這個(gè)場景下的工程標(biāo)準(zhǔn)問題。
雖然工程類型要收斂,但業(yè)務(wù)工程方案的數(shù)量不做任何限制,比如圖中是字節(jié)GIP 部門做的叫作 GHome 的內(nèi)部研發(fā)門戶,其中包含大量子平臺(tái),這些子平臺(tái)之間有共通的業(yè)務(wù)邏輯和額外的工程要求。
在這種情況下,可以基于 MWA 標(biāo)準(zhǔn),定制出 GHome 子平臺(tái)工程方案。
圖上右邊還列舉了其他一些業(yè)務(wù)工程方案。
進(jìn)一步介紹下 Jupiter 和 MWA 框架。
一個(gè)最簡單的 MWA 項(xiàng)目,可以只包含圖上左邊這樣的兩個(gè)文件,這樣的MWA 已經(jīng)有完善的工程能力,能馬上做產(chǎn)品級(jí)的部署。圖上右邊列出了一部分能力。
我們接下來對(duì)這個(gè)項(xiàng)目做些小調(diào)整,就能實(shí)現(xiàn)傳統(tǒng)上需要很多配置和樣板代碼,或是需要不同腳手架才能實(shí)現(xiàn)的效果。
這個(gè)項(xiàng)目當(dāng)前是圖中左上角這樣的「單入口」模式,改成左下角這樣的「多入口」結(jié)構(gòu),就自動(dòng)變成了 MPA,自動(dòng)得到了服務(wù)器端路由和多個(gè) HTML。
如果像右上角這樣,把 landing-page 的 App.tsx 入口組件,換成 pages 目錄,就可以啟用約定式路由功能,基于文件路徑自動(dòng)得到客戶端路由。
如果像右下角這樣增加 index.ts 和 head.html,可以啟用高級(jí)的自定義能力,定制或掌控原本由框架自動(dòng)處理的環(huán)節(jié)。
之前的演示里,我們通過低碼界面啟用了 SSR 功能,其實(shí)也可以在代碼里增加 Jupiter 配置文件,用代碼來控制配置。
一個(gè) MWA 項(xiàng)目自帶產(chǎn)品級(jí)的 web server,稱作 Jupiter Server,項(xiàng)目自己就可以運(yùn)行自己。
第一方 Serverless 平臺(tái)使用相同的 web server,但還能基于 MWA 標(biāo)準(zhǔn)來理解項(xiàng)目的代碼,自動(dòng)生成更復(fù)雜的多進(jìn)程的集群化的系統(tǒng)。比如 SSR 部分會(huì)獨(dú)立部署,業(yè)務(wù)開發(fā)者寫出來的 app 代碼,容易在 SSR 中出現(xiàn)異常報(bào)錯(cuò)或內(nèi)存泄露,這時(shí)前面的 web server 會(huì)讓應(yīng)用自動(dòng)降級(jí),變成兜底的純 CSR 模式,保證用戶請(qǐng)求不會(huì)出錯(cuò)不會(huì)超時(shí)。
要實(shí)現(xiàn)這種自動(dòng)兜底,不但平臺(tái)和框架的協(xié)同,也需要 MWA 提供的一體化 SSR 開發(fā)方式,用同一套 app 代碼開發(fā)前后端業(yè)務(wù)邏輯,讓業(yè)務(wù)邏輯始終支持 CSR,否則兜底就無效了。
MWA 支持用一體化的方式,開發(fā)同一套 app 代碼,在圖上這三個(gè)環(huán)節(jié)中以不同模式運(yùn)行,也支持根據(jù)業(yè)務(wù)需求,讓 app 代碼中的不同部分,在不同環(huán)節(jié)以不同模式運(yùn)行。
這種收斂后的開發(fā)方式,符合業(yè)界的一個(gè)發(fā)展趨勢(shì),就是讓代碼的運(yùn)行盡可能「前置」,優(yōu)先在編譯時(shí)運(yùn)行,剩余的才在服務(wù)器端 SSR 環(huán)節(jié)運(yùn)行,最后剩下的才在瀏覽器里運(yùn)行。
比如可以像圖上左邊這樣,app 整體做 SSR 或 SSG,把局部留到 CSR。
也可以像圖上中間這樣,反過來,整體默認(rèn) CSR,允許對(duì)局部做 SSR 和 SSG。還可以進(jìn)一步實(shí)現(xiàn)右邊這樣更復(fù)雜的效果。
要實(shí)現(xiàn)前面說的 1+1 < 1,除了合適的抽象,MWA 框架也通過插件和微生成器等方式,把核心功能拆分出來,可以按需啟用??梢韵駡D上這樣運(yùn)行 new 命令,選擇啟用這兩個(gè)功能,微生成器會(huì)自動(dòng)重構(gòu)項(xiàng)目代碼,增加必要的依賴和配置。
也可以在工作臺(tái)的界面上,查看項(xiàng)目可選功能的開關(guān)狀態(tài),做修改調(diào)整。
之前的演示里,我們提前開啟過 Unbundled 開發(fā)模式功能,可以用 dev esm 命令取代默認(rèn)的 dev 命令,耗時(shí)可以從幾秒減少到1秒不到。
* What is Unbundled Development: https://medium.com/habilelabs/snowpack-what-is-unbundled-development-8562205d0539
這么快的編譯速度,是因?yàn)楸澈笠呀?jīng)完全沒有 webpack,也不做任何打包,只用 esbuild 編譯 ESM 模塊,用自研的類似 Snowpack 和 Vite 的方案運(yùn)行項(xiàng)目,也會(huì)自動(dòng)從 Goofy PDN 平臺(tái)上加載預(yù)編譯的依賴包,進(jìn)一步優(yōu)化性能。
之前的演示里,還開啟了一體化 BFF 功能,可以在項(xiàng)目里寫「BFF 函數(shù)」文件,這種函數(shù)文件可以實(shí)現(xiàn)任意的 REST API,同時(shí)自動(dòng)生成一體化風(fēng)格的客戶端 SDK,通過 SDK 調(diào)用,就像調(diào)用普通文件里的函數(shù)。
用這種一體化 API 調(diào)用 BFF,不但更直觀、安全,也因?yàn)槎嗔丝蚣艿某橄?,框架可以自?dòng)做更多事情,比如在 SSR 中運(yùn)行的時(shí)候,自動(dòng)把 BFF 請(qǐng)求切換成內(nèi)網(wǎng)方式。
Serverless 平臺(tái)也會(huì)自動(dòng)對(duì) BFF 做優(yōu)化,做獨(dú)立部署,BFF 和 Web 之間不會(huì)互相干擾。
MWA 實(shí)現(xiàn)了圖上這種「三位一體」應(yīng)用,圖上右邊三種開發(fā)方式之間,可以無縫切換。
比如可以從現(xiàn)代 Web 開發(fā)范式,切換成傳統(tǒng)的 Node.js Web 應(yīng)用。也可以把 MWA 項(xiàng)目中的 BFF 拆分成獨(dú)立的純 API 服務(wù)項(xiàng)目。一個(gè)純 API 服務(wù),也可以隨時(shí)切換成包含 web 的 MWA 項(xiàng)目。
這種能力有利于業(yè)務(wù)項(xiàng)目從傳統(tǒng) Web 開發(fā)范式向現(xiàn)代 Web 開發(fā)范式的轉(zhuǎn)換。
前面說的這種「三位一體」,實(shí)際上是 MWA 最重要的「Universal App」功能的一部分。
「Universal JS」是指同一份 JS 代碼既支持在瀏覽器端運(yùn)行,也支持在服務(wù)器端運(yùn)行。而「Universal App」是進(jìn)一步發(fā)展,讓同一份 app 代碼,可以用圖上中間這一排的方框代表的任意方式來運(yùn)行,也支持同時(shí)部署多個(gè)不同運(yùn)行方式的版本。
比如一個(gè)靜態(tài)網(wǎng)站切換成 SSR,或啟用 SPR 的時(shí)候,不需要調(diào)研技術(shù)選型和考量成本收益,幾乎什么都不用改。也可以隨時(shí)退回原來的方式。
比如為中后臺(tái)項(xiàng)目同時(shí)提供 SaaS 版、桌面安裝版和私有化部署版。
比如讓微前端子應(yīng)用,既能在主應(yīng)用里訪問,也能獨(dú)立訪問。
前面提到過 Node.js Web 框架只能提供「服務(wù)器端應(yīng)用架構(gòu)」,MWA 提供開箱即用的、符合現(xiàn)代 Web 開發(fā)范式、以客戶端應(yīng)用為中心、前后端一體化的應(yīng)用架構(gòu),類似圖上這樣。
可以用 createModel、useModel 這樣的 API,輕易實(shí)現(xiàn) React 開發(fā)中欠缺的 Model 層和 Controller 層??梢岳?Redux 的 FP 編程優(yōu)勢(shì)和生態(tài)紅利,同時(shí)不需要關(guān)心創(chuàng)建和配置 store,如何組織和組裝 reducer、action 等。
前面說過,在抽象不足的情況下,前端開發(fā)中一直存在 DX 和 UX 不可兼得的問題,比如如果降低了開發(fā)成本,產(chǎn)品功能上可能會(huì)不靈活,性能不夠好,反之把業(yè)務(wù)需求和性能做到位,開發(fā)體驗(yàn)就會(huì)很差。
MWA 框架在盡可能多的環(huán)節(jié),實(shí)現(xiàn)最大化的抽象,類似圖上這樣,幫助前端開發(fā)者脫離「軟件開發(fā)的石器時(shí)代」,獲得更成熟的軟件開發(fā)范式。
Jupiter 和 MWA 框架在字節(jié)內(nèi)部,經(jīng)歷了半年的內(nèi)測(cè),和一年的正式使用,在內(nèi)部已經(jīng)進(jìn)入推廣普及階段。
這個(gè)項(xiàng)目也很快會(huì)開源出來,幫助行業(yè)和社區(qū)里的更多項(xiàng)目,落地「現(xiàn)代 Web 開發(fā)」范式。
這個(gè)開源項(xiàng)目叫作 Modern.js,目前我們已經(jīng)創(chuàng)建了 Github 項(xiàng)目,上線了開源內(nèi)測(cè)主頁,和一個(gè)現(xiàn)代 Web 開發(fā)者問卷調(diào)查,希望大家?guī)兔μ顚懞娃D(zhuǎn)發(fā)下這個(gè)問卷,調(diào)查報(bào)告之后會(huì)公開出來。
(由于 modernjs.dev 這個(gè)域名還沒備案,沒辦法部署在我們自己的 Serverless 平臺(tái)上,目前是用 Github Pages 部署,似乎有被墻的問題,正在解決)
* https://modernjs.dev/
* https://github.com/modern-js-dev/modern.js
* https://webinfra.org/
關(guān)鍵詞:現(xiàn)代,跳動(dòng),實(shí)踐,演講