React團隊回應使用Vite替換Create React App的建議
大家好,我是 CUGGZ。
最近,網(wǎng)友 t3dotgg 建議把 React 官方文檔中關于建議使用 Create React App 來創(chuàng)建新項目更換為建議使用 Vite 來創(chuàng)建新項目。該建議引起了網(wǎng)友的熱議,多數(shù)網(wǎng)友對此表示贊同:
新的 React 官方文檔發(fā)布在即(目前顯示已完成 99%),Beta 版文檔中仍然推薦使用 Create React App 創(chuàng)建新項目。另外提供了兩個備選方案:Vite、Parcel。
查看 Create React App 的 Github 倉庫可以發(fā)現(xiàn),其已經(jīng) 5 個月沒有更新了,積累了 1500+ 個 issues。
1 月 31 日,React 團隊核心成員 Dan Abramov 對此建議進行了回復,解釋了 React 團隊成員對此建議的權衡并提供了一些選項,下面就來看看詳細內(nèi)容吧(可以跳到最后看結論)!
Create React App 的演變
在 2016 年發(fā)布 Create React App 時,工具的環(huán)境是分散的。如果想要將 React 添加到現(xiàn)有應用,需要添加一個 <script> 標簽或從 npm 中導入,然后調(diào)整現(xiàn)有的構建工具配置。但是,如果要從頭開始創(chuàng)建一個僅使用 React 構建的新應用,則沒有明確的方法可以做到這一點。
在 Create React App 之前,必須安裝一堆工具并將它們連接在一起,提供正確的預設以使用 JSX,為開發(fā)和生產(chǎn)環(huán)境進行不同的配置,為資源緩存提供正確的設置,配置 linter 等,想要正確完成這一系列工作非常困難。人們通過創(chuàng)建和共享可以克隆的“樣板”存儲庫來解決了這個問題。然而,這產(chǎn)生了另外一個問題:一旦在項目中調(diào)整了克隆的樣板文件,就很難再拉取樣板的更新。這樣,項目的設置會變得舊,要么放棄更新,要么花費大量精力讓所有工具再次協(xié)同工作。在快速發(fā)展的生態(tài)系統(tǒng)中,這非常困難。
Create React App 通過將多個工具組合在一個包中解決了這個問題?,F(xiàn)在,如果想用 React 開始一個新項目,有一個明確的推薦方法(Create React App)可以做到這一點!然后,每隔一段時間,可以更新這個包,以獲得所有底層工具的更新。這種模型變得很流行,以至于今天有很多工具都以這種方式工作。Vite 確實是擁有相似愿景的最佳工具之一,并且在在某些方面更進一步。
Create React App 的目標是為大多數(shù) React 用戶提供啟動新 React Web 應用的最佳方式,它支持一組協(xié)同工作的精選功能。隨著時間的推移,它提供的開箱即用的“baseline”會隨著我們找到正確的權衡而擴大。例如,為運行時錯誤添加了一個遮罩層,添加了對不同樣式選項的支持,默認添加了快速刷新,它允許保存組件的代碼并查看更改而不會丟失狀態(tài)。對于默認的 React 開發(fā)體驗來說,這是一個巨大的里程碑??偟膩碚f,由于 Create React App 完全控制了編譯管道,因此添加編譯相關的功能是很容易的。
有這樣一個精心策劃的設置對生態(tài)系統(tǒng)仍然很有價值。當 React Hooks 出現(xiàn)時,React 團隊將 React Hooks lint 規(guī)則添加到默認設置中。除此之外,Create React App 還允許 React 團隊向盡可能廣泛的受眾部署重要的工具更改(快速刷新支持、React Hooks lint 規(guī)則)。如果沒有 React 團隊策劃的流行模板,將很難如此廣泛地推出這些工具更改。
Create React App 的問題
隨著時間的推移,Create React App 停滯不前。許多人指出它比替代品慢,并且不支持人們?nèi)缃裣胍褂玫囊恍┝餍泄ぞ?。原則上,React 團隊可以解決這些問題。例如,可以更新Create React App 內(nèi)部,以使用更快的 bundler,甚至在內(nèi)部使用 Vite。或者可以建議人們從 Create React App 遷移到 Vite 這樣的應用。然而,React 團隊還想解決一個更深層次的問題。
按照設計,Create React App 會生成一個純客戶端應用。這意味著用它創(chuàng)建的每個應用都包含一個空的 HTML 文件、一個帶有 React 的 <script> 標簽和應用包。當加載空的 HTML 文件時,瀏覽器會等待 React 代碼和全部應用包下載。這在低帶寬連接上可能需要一段時間,并且此時用戶在屏幕上看不到任何內(nèi)容。然后,加載應用代碼。此時用戶會在屏幕上看到一些內(nèi)容——但通常還需要加載數(shù)據(jù)。所以代碼發(fā)送了加載數(shù)據(jù)的請求,用戶需要等待它返回。最后,數(shù)據(jù)加載,組件重新渲染數(shù)據(jù),用戶看到最終結果。
這是非常低效的,盡管如果只在客戶端運行 React 很難做得更好。將其與 Rails 這樣的服務端框架進行對比:服務端將立即啟動數(shù)據(jù)獲取,然后生成包含所有數(shù)據(jù)的頁面。在這種情況下,用戶會看到包含所有信息的 HTML 文件,而不是等待加載腳本的空白文件。HTML 是Web 的基石——那么為什么創(chuàng)建React 應用會產(chǎn)生一個空的 HTML 文件?為什么不利用 Web 最基本的功能——在所有交互代碼加載之前快速查看內(nèi)容的能力?為什么要等到所有客戶端代碼加載完成后才開始加載數(shù)據(jù)?
Create React App 只解決了問題的一方面,它提供了良好的開發(fā)體驗,但它沒有強加足夠的結構來幫助我們利用 Web 的強大功能獲得良好的用戶體驗。開發(fā)者可以嘗試自己解決這些問題,但這違背了 Create React App 的宗旨。每個真正高效的 React 設置都是自定義的、不同的,并且是 Create React App 無法實現(xiàn)的。
這些用戶體驗問題并不是 Create React App 特有的。它們甚至不特定于 React。例如,從 Preact、Vue、Lit 和 Svelte 的 Vite 主頁模板創(chuàng)建的應用都會遇到相同的問題。這些問題是沒有靜態(tài)站點生成 (SSG) 或服務端渲染 (SSR) 的純客戶端應用所固有的。
React 框架的興起
有些人可能不喜歡完全使用 React 進行構建。例如,可以在服務端或在構建過程中使用不同的工具(如 Jekyll 或 Astro)生成 HTML 頁面。這解決了空 HTML 文件的問題,但是必須混合使用兩種渲染現(xiàn)技術。隨著時間的推移,想要添加的交互性越多,這種技術割裂就越明顯。
這種割裂不僅會損害開發(fā)人員的體驗——用戶體驗也會受到影響。使用真正以 HTML 為中心且未充分利用 React 的工具,每個頁面導航都會變成完整的頁面重新加載,從而清除了所有客戶端狀態(tài)。如今,許多用戶希望在應用內(nèi)導航順暢,而不是 90 年代風格的整頁重新加載。同樣,許多開發(fā)人員更喜歡使用單一的渲染模型而不是混合兩種不同的模型來構建他們的應用。開發(fā)者想用 React 構建整個應用。
如果使用 React 構建整個應用,那么能夠使用 SSG/SSR 很重要。在 Create React App 中缺乏對它們的支持。除此之外,經(jīng)過多年的生態(tài)系統(tǒng)創(chuàng)新,React 的許多其他問題現(xiàn)在都有了成熟的解決方案。例如,network waterfalls 和 bundle 大小。
即使應用沒有像面向內(nèi)容的網(wǎng)站那樣從 SSG 或 SSR 中獲益,它也可能會受到網(wǎng)絡瀑布的影響。如果在掛載時獲取數(shù)據(jù),則在加載所有代碼并渲染組件之前,第一次數(shù)據(jù)獲取甚至不會開始。這是一個 waterfall:如果應用知道如何在代碼仍在加載時開始獲取數(shù)據(jù),那么就可以并行完成。在導航中,如果父組件和子組件都需要獲取某些內(nèi)容,則會產(chǎn)生更糟糕的 waterfall。當我們談論 React 性能時,無法回避一個事實:對于如此多的應用來說,waterfall 是性能的瓶頸。要解決這些 waterfall,需要將數(shù)據(jù)獲取與路由集成起來,而Create React App 無法做到這一點。
我們的應用代碼會隨著添加的每個新功能和額外依賴項而不斷增長。如果經(jīng)常部署,應用在每次使用時加載速度可能會變得非常慢,因為它總是需要加載所有代碼。有幾種方法可以解決這個問題;可以移動一些代碼以在服務端或在構建期間運行(如果工具允許)。理想情況下,還可以按路由拆分代碼。然而,如果嘗試手動進行代碼拆分,通常會使性能更差。要解決這一問題,需要將數(shù)據(jù)獲取與路由和打包相結合,而 Create React App 無法做到這一點。
React 本身只是一個庫,它不規(guī)定如何使用路由或數(shù)據(jù)獲取,Create React App 也沒有。不幸的是,這意味著單靠 React 和最初設計的 Create React App 都無法解決這些問題。服務端渲染和靜態(tài)生成、數(shù)據(jù)獲取、打包和路由都是相關聯(lián)的。當 Create React App 發(fā)布時,React 還很新,如何讓這些功能獨立工作都還有很多東西需要弄清楚,更不用說如何完美地將它們組合在一起了。
時代在發(fā)展,現(xiàn)在,越來越難以推薦無法獲得這些功能的解決方案。即使不立即使用它們,它們也應該在需要時可用,并且不必遷移到不同的模板并重新構建所有代碼即可利用它們。同樣,并非所有數(shù)據(jù)獲取或代碼拆分都需要基于路由。但這是一個很好的默認設置,應該適用于大多數(shù) React 應用。
雖然可以自己整合所有這些功能,但很難好。就像 Create React App 本身集成了與編譯相關的幾個功能一樣,Next.js、Gatsby 和 Remix 等工具跟進一步——將編譯與渲染、路由和數(shù)據(jù)獲取集成在一起。這類集編譯、渲染、路由和數(shù)據(jù)獲取于一體的工具被稱為“框架”(或者,如果喜歡稱 React 為框架的話,可以稱它們?yōu)椤霸蚣堋保?。這些框架提供了更好的用戶體驗。
React 作為一個架構
我們喜歡 React 的靈活性,可以使用 React 構建單個按鈕,也可以使用它構建整個應用??梢允褂盟谝延?20 年歷史的 Perl 網(wǎng)站中構建儀表板,或者可以使用 React 制作混合 SSG/SSR 的電子商務網(wǎng)站。這種靈活性是必不可少的,用戶也很喜歡它。
React 團隊也希望為完全使用 React 構建的新應用提供更好的默認設置。如果默認建議的創(chuàng)建 React 應用的方法支持 SSG 和 SSR、自動代碼拆分、路由預加載、保留客戶端 UI 狀態(tài)的導航以及其他可實現(xiàn)出色用戶體驗的功能,就太好了。至少,創(chuàng)建 React 應用的默認建議方式不應該完全被排除在這些功能之外,因為現(xiàn)有的僅客戶端架構沒有實現(xiàn)這些功能。
React 面臨著挑戰(zhàn),幫助 React 框架提供出色用戶體驗的最佳方式就是專注于 React 的底層。React 本身可以在渲染層做一些獨特的事情,這些事情大大提高了框架在其他層的能力。例如,與<Suspense>一樣,一個 React API 可以在幕后為框架解鎖一系列框架優(yōu)化。
React 是一個庫,它提供了一些 API,可讓定義和組合組件。React 也是一種架構,它提供了讓框架作者充分利用其渲染模型的構建塊。我們可以在沒有框架的情況下使用 React。但需要確保,如果將它與框架一起使用,框架能夠充分利用 React。在過去幾年中構建的許多功能(<Suspense>、useTransition?、流式 API(如 renderToPipeableStream 和實驗性的服務端組件)都是面向框架的。它們讓框架通過集成打包、路由和數(shù)據(jù)獲取來充分利用 React。
可以看到,Next 13、Gatsby 5 和 Remix 1.11 中采用了其中一些功能。還有很多工作要做,其中一些工作正在從實驗階段結束。盡管如此,React 團隊還是很高興看到多年的努力得到了回報,并使 React 框架(及其用戶)能夠發(fā)布更快的應用。
一個庫,多個框架
React 生態(tài)系統(tǒng)更適合擁有眾多競爭,有多種競爭的數(shù)據(jù)獲取解決方案和路由解決方案。這些選擇每年都會變得更好。也有多種集成路由、數(shù)據(jù)獲取、渲染和編譯的解決方案——即多個 React 框架。
我們希望保持這種狀態(tài),也希望在可能的情況下鼓勵融合并使 React 生態(tài)系統(tǒng)從中受益。例如,不同的框架可能使用不同的機制來加載數(shù)據(jù)。但是,如果它們都采用 <Suspense>? 作為加載指示器,那么在 <Suspense> 中的更高級別的功能將適用于所有框架。
如果大多數(shù) React 應用的最佳方式是從一個框架開始,那我們應該建議使用哪個框架?我們應該選擇一個嗎?我們?nèi)绾螞Q定選擇哪一個?如果它隨著時間的推移停滯不前怎么辦?這就引出了上面提到的問題。
我們應該用 Create React App 做什么?
Create React App 最初的目標是:
- 提供一種無需配置即可啟動新 React 項目的簡單方法;
- 集成編譯相關依賴,方便升級;
- 讓 React 團隊盡可能廣泛地部署工具更新(例如快速刷新支持、Hooks lint 規(guī)則)。
然而,它不再滿足最初的目標,即成為創(chuàng)建 React 應用的最佳方式。通過提高標準并將編譯與渲染、路由和數(shù)據(jù)獲取相集成,框架可以讓用戶創(chuàng)建 React 應用時:
- 充分利用 Web API 來默認提供快速的應用和網(wǎng)站,無論大??;
- 充分利用 React 及其框架級功能;
- 提供路由和數(shù)據(jù)獲取。
React 生態(tài)系統(tǒng)值得推薦一種默認的方法,它可以充分利用 Web 和 React 本身。這甚至并不意味著一定要依賴于 Node.js 服務器。許多流行的框架不需要服務器并且可以在 SSG 模式下工作,因此它們也可以解決“完全靜態(tài)”的用例??蚣艿暮锰幘褪?,如果以后需要 SSR,不需要進行遷移,它和其他功能一樣開箱即用(例如,Remix 提供了開箱即用的 mutation API)。
那該如何實現(xiàn)這一愿景?有以下選擇:
選項 1:從頭開始創(chuàng)建一個新框架
可以嘗試將 Create React App 重新設計架構成為一個集成數(shù)據(jù)獲取、路由、打包和 SSG/SSR 的框架。構建一個高質(zhì)量的新框架是一項艱巨的任務,需要大量的生態(tài)系統(tǒng)專業(yè)知識,即使停止其他項目來實現(xiàn)這一目標,也會存在著隨著時間的推移出現(xiàn)停滯不前的重大風險,就像 Create React App 一樣。它還會進一步分裂生態(tài)系統(tǒng),盡管沒有真正的用戶。所以認為這個選項目前不實用。
選項 2:棄用 Create React App,維護一個Vite模板
可以棄用 Create React App,維護自己的 Vite 模板。為了實現(xiàn)這個目標,該模板必須非常復雜。事實上,它必須像 React 框架一樣復雜——并且需要集成路由、數(shù)據(jù)獲取等功能。這導致了同樣的問題:實際上是在創(chuàng)建另一個框架。
選項 3:棄用 Create React App,建議使用 React 框架
可以不再強調(diào)或反對將 Create React App 作為工具,而是更積極地強調(diào) React 框架。這并不意味著必須使用其中一個React框架,但建議在大多數(shù)應用中使用其中一個框架。不利的一面就是,這將影響 React 的品牌(“為什么不推薦創(chuàng)建 React 應用?”)。
選項 4:讓 Create React App 使用單一框架
可以選擇一個指定框架,并更改 Create React App 以默認使用該框架創(chuàng)建應用。這種方法的主要問題是它使其他解決方案很難競爭——尤其是當它們的權衡略有不同,但在流行度、功能集和質(zhì)量方面大致相同時。這種行為上的改變也是具有破壞性的,因為所有的舊教程都會以一種不明顯的方式中斷。
選項 5:將 Create React App 變成啟動器
可以將 Create React App 保留為命令,但將其變成啟動器。它將建議一個推薦框架列表,然后是“經(jīng)典”無框架方法。“經(jīng)典”方法將產(chǎn)生一個像 CRA 現(xiàn)在這樣的客戶端專用應用(以避免破壞已有教程),但內(nèi)部最終可能會使用 Vite。
要想進入精選框架列表,React 框架必須滿足特定條件。需要考慮社區(qū)的流行度和采用率(以保持列表簡短)、功能集、性能特征、充分利用 Web 平臺和 React 本身的能力、它是否得到積極維護以及是否清楚如何在各種托管服務和環(huán)境中托管它。每個框架的入門模板將由 React 團隊維護,以確保它們具有一致的設計和品牌,不鏈接到商業(yè)服務,并且結構相似。需要向社區(qū)清楚地傳達是如何做出這些選擇的,并且會定期重新評估它們。
React 團隊的建議
React 團隊目前傾向于選項 5(“將 Create React App 變成啟動器”)。Create React App 的最初目標是為大多數(shù) React 用戶提供啟動新的 React web 應用的最佳方式。重新調(diào)整它的用途,啟動器明確傳達了我們認為最適合大多數(shù)新 Web 應用的轉(zhuǎn)變。與選項 3 不同,它避免了“創(chuàng)建一個 React 應用”在某種程度上被棄用的看法。
React 團隊將制定更詳細的 RFC 提案,以充實這些要點。同時,希望聽到對這些問題的更多反饋。
對于使用 Vite 替換 Create React App,你有什么看法?歡迎在評論區(qū)分享~
參考:https://github.com/reactjs/reactjs.org/pull/5487#issuecomment-1409720741