2019年9月30日 星期一
Next.js 9.0.7
發布者Next.js 9.0 大約在兩個月前發布。從那時起,我們一直忙於 7 個較小但非常重要的版本:9.0.1、9.0.2、9.0.3、9.0.4、9.0.5、9.0.6 和 9.0.7。
讓我們深入了解這些版本為您的網站和應用程式帶來了哪些功能,絕對沒有任何重大變更。
- 改善 Windows 環境中的並行處理:
next build
流程在 Windows 上現在更加可靠,並且可以更好地並行處理工作。 - 預設啟用 Gzip 壓縮:現在預設新增了 Gzip 壓縮,以減少所需的最佳化步驟。
- 僅針對作用中頁面報告 TypeScript:擴展了內建的 TypeScript 支援,使其僅監看作用中頁面上的變更,從而使其更快且更可靠。
- 遙測:將協助我們專注於 Next.js 的哪些部分需要最佳化,並驗證最佳化是否達到預期效果。
- 改善
next/head
元素追蹤:已移除next-head
類別,這使得實作某些驗證其部署的工具更加容易。 - 防止 Pages 目錄中出現非頁面檔案:透過防止意外發布非頁面檔案,最佳化您的應用程式安全性及
next build
時間。 - 執行階段改善:當未使用 Next.js 的某些部分時,例如
next/dynamic
,它們將不再於執行階段中需要,從而縮減套件大小。
改善 Windows 環境中的並行處理
Next.js 在 next build
流程期間的多個位置執行並行工作。主要用途是使用 Terser 並行縮減組建輸出。
先前,這項工作是使用名為 worker-farm
的套件在多個 CPU 上處理。但是,我們注意到許多 Windows 使用者已使用自訂 webpack 設定停用最小化。經過進一步檢查,我們發現 worker-farm
在 Windows 機器上無法穩定運作。
為了解決這個問題,我們從 worker-farm
遷移到 jest-worker
。這確保組建在 macOS、Linux 和 Windows 機器上都可靠且一致。
jest-worker
,顧名思義,是 Jest 測試執行器的一部分。它是 Jest 用於並行處理測試案例的套件。這表示這個套件經過充分的實戰測試、可靠且維護良好。
jest-worker
也支援 worker_threads
,這是 Node 12 中的一項新功能。與 child_process
不同,worker_threads
可以共用記憶體 — 這表示在新的 Node 版本上組建時間更快。
透過切換到 jest-worker
,我們能夠為 Windows 使用者重新啟用組建並行處理。
預設啟用 Gzip 壓縮
在調查公司為何使用自訂伺服器時,我們發現最常見的原因是為了壓縮。公司會新增一個名為 compression
的 Express Middleware,它會處理 HTTP 回應的 Gzip 壓縮。
這個中介軟體會壓縮回應,以便透過網路傳送給使用者的位元組更少。通常,這應該由 Nginx 等反向 Proxy 處理。反向 Proxy 會將 CPU 密集型工作從單執行緒 Node 處理序中移除。
但是,當檢查網路上 Next.js 的使用情況時,我們發現很大一部分公司沒有設定任何壓縮。
在 Vercel 等平台上,gzip
和 brotli
會在 Proxy 層級自動處理。
當自行託管時,公司必須自行新增 gzip(透過 compression
或反向 Proxy)。
從 Next.js 9.0.4 開始,當使用 next start
或自訂 server.js
時,預設會包含 gzip
壓縮。
brotli
支援即將 推出,因為 Node.js 現在原生支援 Brotli。
如果您的應用程式已透過自訂伺服器啟用壓縮,Next.js 將不會新增自己的壓縮器。
Next.js 預設不包含 serverless 目標的壓縮,因為當使用 serverless 目標時,資產會個別上傳,而不是透過 Node.js 提供服務。
如果您部署在處理壓縮的平台上,例如 Vercel,則無需進行任何變更。
僅針對作用中頁面報告 TypeScript
Next.js 9 包含對 TypeScript 的內建支援。所有必要的操作都是將單一頁面從 .js
重新命名為 .tsx
。Next.js 將自動處理或引導您完成任何剩餘的設定。
Next.js 也透過平行於開發流程執行 tsc --watch
來處理類型檢查。在開發期間,Next.js 有一個稱為 隨需載入項目 的概念。此功能僅編譯您正在積極處理的頁面。

從 9.0.4 開始,Next.js 現在僅針對隨需載入項目正在積極編譯的頁面報告類型錯誤。這減少了大量的類型檢查雜訊,同時專注於一組特定的頁面。
完整應用程式類型檢查仍然在 next build
期間執行,或者可以在您的編輯器中/由您的編輯器處理。
遙測
Next.js 大約在 3 年前發布,並且在這個 3 年中,框架已大幅成長,從新功能到所有使用者更好的預設值。
我們一直以來進行此改進流程的方式在很大程度上是手動的。
Vercel 有一些大型的 Next.js 應用程式。例如,vercel.com、vercel.com/docs 和 https://nextjs.dev.org.tw。我們一直在 Vercel 內部「以身作則」Next.js,並根據我們的經驗改進 Next.js。
最重要的是,我們積極與社群互動以收集意見回饋。您很有可能之前曾與 Tim 談過,以提供關於您公司如何使用 Next.js 的意見回饋。
例如,如果您使用自訂伺服器、是否有自訂 webpack 設定等等。這些意見回饋對於引導 Next.js 的功能開發極為寶貴。
但是,這種方法存在一個問題,那就是我們只能從部分使用者收集意見回饋。這個子集可能與您/您的公司有不同的需求和使用案例。
其中一個範例是匯入 CSS 檔案,這是不標準的,但似乎有相當多的使用者正在使用它,無論是透過 next-css
(或 Sass/Less)還是自訂設定。如果我們知道有多少百分比的使用者正在使用這種特定方法,我們就可以優先改善它。
基於這個原因,我們推出了一種匿名、更自動化的方法來收集這些意見回饋點,以便我們在不久的將來可以更進一步地改進 Next.js。
這也將使我們能夠驗證對框架所做的改進是否正在改善所有應用程式的基準。
您可以在 nextjs.org/telemetry 上閱讀有關遙測的更多資訊。您也會在那裡找到如何選擇退出(如果您不想參與)的方法。
使用點指示活動的組建意見回饋
在與 Next.js 使用者交談時,一項小小的意見回饋是,有時看起來 next build
似乎沒有在做任何事情,主要是視覺上的。
為了解決這個問題,我們在執行 next build
時,在主控台輸出中新增了一個載入指示器。此輸出提供了一個視覺指示,表明命令仍在執行,並且處理序並未凍結。
我們計劃擴展此組建輸出,以便在可能的情況下顯示更多組建階段。
改善 next/head
元素追蹤
Next.js 提供了一種內建方式來管理 <head>
元素,因為它負責呈現應用程式的 HTML。此 API 透過 next/head
模組公開。
例如,將標題新增至頁面
import Head from 'next/head';
export default function MyPage() {
return (
<>
<Head>
<title>My Title</title>
</Head>
<h1>Hello World</h1>
</>
);
}
當呈現為 HTML 時,Next.js 將收集在 <Head>
中呈現的所有元件,並將標籤呈現到頁面的 <head>
中。
但是,Next.js 允許使用 <Link>
元件進行單頁應用程式 (SPA) 類型的路由轉換。
當您按一下 <Link>
時,Next.js 將擷取所需的 JavaScript 檔案,以在用戶端呈現頁面。然後,它將呈現與檔案關聯的 React 元件。
由於此轉換發生在用戶端,我們必須清除從上一頁注入的 <head>
元素,否則過時的元素可能會出現在另一個頁面上。
先前,Next.js 透過將類別名稱新增至每個 <Head>
提供的元素來追蹤這些元素。
以上述範例為例,<head>
看起來會像這樣
<head>
<title class="next-head">My Title</title>
</head>
此解決方案運作良好,因為透過 next/head
注入的每個元素都已清楚標記且易於清除。
但是,一小部分使用者回報了問題,即元素上額外的 class
屬性有時會使從外部服務新增的指令碼無法驗證。
來自 Google Chrome 團隊的 Gerald Monaco,提出了一種方法,可以在不需要元素上的類別名稱的情況下保留清除行為。
新的行為是 Next.js 將插入一個額外的 <meta>
標籤,其中包含它 (next/head
) 呈現的元素數量。有了這個,Next.js 可以使用計數來清除現有的元素。
因此,當將多個元素注入到頁面的 <head>
中時,此方法會縮減初始 HTML 酬載大小。
防止 Pages 目錄中出現非頁面檔案
剛開始使用 Next.js 時,您做的第一件事是建立一個 pages
目錄。
慣例是 pages
目錄中的每個檔案都會成為應用程式中的路由。一個簡單的範例是 pages/about.js
變成 /about
。
隨著時間的推移,我們偶爾收到使用者應用程式(無論大小)組建效能不佳的報告。
經過進一步調查,發現這些使用者已在 pages
目錄中建立了整個元件結構。
由於 pages
目錄中的每個檔案都被視為一個頁面,因此每個元件都被編譯為應用程式中的一個頁面。這會導致大量的組建時間額外負荷,為無效頁面產生 2 個以上的 JavaScript 檔案。
此外,這會部分影響 Next.js 決定產生程式碼分割區塊的方式。這是因為 Next.js 使用關於跨頁面程式庫使用情況的啟發法。
因此,我們必須確保使用者不會將此陷阱引入他們的 Next.js 應用程式中。
Next.js 9 現在驗證 pages
目錄中的檔案是否匯出 React 元件。
實際上,這表示 Next.js 將向您顯示一則訊息,提醒您在 pages
目錄中找到潛在的非頁面檔案。
這鼓勵使用者將不是頁面的檔案移至另一個目錄。反過來,開發、生產和程式碼分割變得更快且更準確。
執行階段改善
Next.js 框架由許多部分組成。其中之一是用戶端執行階段。此執行階段處理 hydration、用戶端路由等等。
hydration(此改進的重點)是使伺服器呈現或預先呈現的 HTML 互動所必需的。hydration 新增事件處理常式並呼叫生命週期方法,例如 useEffect()
或 componentDidMount
— 使您的應用程式為終端使用者做好準備。
此外,Next.js 處理的不僅僅是基本 hydration — 例如,設定用戶端路由器、設定 next/head
,以及透過 next/dynamic
載入額外的應用程式邏輯。
這些職責中的每一個也都有其特定的執行階段部分。
在 next/dynamic
的情況下,Next.js 必須確保在伺服器上呈現的延遲載入元件在用戶端上已就緒。每次使用 next/dynamic
都會產生一個額外的 JavaScript 套件,並且必須在 hydration 之前載入這些檔案,以避免 hydration 不符。
先前,此執行階段將始終包含在 Next.js 執行階段套件中。現在,它僅在您在應用程式中使用 next/dynamic
時才會包含。這表示對於未使用 next/dynamic
的應用程式,下載、剖析和執行的 JavaScript 更少。
AppTree 支援
React 生態系統中的某些程式庫以非常特定的方式實作伺服器端呈現。最值得注意的是,Apollo 的伺服器端呈現解決方案(稱為 getDataFromTree
)的工作方式是呈現 React 樹狀結構,對於找到的每個 Query
,它都會等待結果,然後再次重新呈現 React 樹狀結構。
預設情況下,Next.js 會將一些內容值新增到 React 樹狀結構中,例如,可以使用 useRouter
讀取的路由器。
with-apollo
範例過去呈現 React 樹狀結構的方式是透過呈現 <App>
並嘗試手動填寫遺失的屬性。隨著 React Context 的新增,這已不再可能,因為內容提供者是一個單獨的元素。
從 Next.js 9.0.4 開始,在 getInitialProps
中的內容物件中新增了一個名為 AppTree
的新屬性。它是專門為外部程式庫必須像 Apollo 的 getDataFromTree
一樣遍歷整個 React 樹狀結構的情況而新增的。
with-apollo
範例已 更新以反映變更。如果您已在應用程式中實作 Apollo,建議更新到 AppTree
方法,以便 useRouter
和未來新增的其他 API 可以在您的 Next.js 應用程式中正常運作。
如果您未使用 Apollo 或類似的程式庫,我們建議盡量避免使用 AppTree,因為 Next.js 團隊不建議一般遍歷 React 樹狀結構。它會增加相當多的效能額外負荷,因為 React 樹狀結構會多次呈現,而不僅僅是一次。
移除 next-server
套件
當我們一年多前開始最佳化 Next.js 以進行 serverless 部署時,我們建立了一個名為 next-server
的套件。這個套件是實驗性的,並且與 next
套件一起發布。它從未公開記錄,但它是一項實驗,旨在建立最小的 Next.js 伺服器執行階段。
最終,這個套件成功了,並且確實縮減了生產伺服器執行階段的大小。但是,我們想出了一種創新的新方法,可以使用 Next.js 編譯器和 靜態分析,使執行階段變得更小。
這樣一來,next-server
就變得過時了,並被 serverless 目標 取代。與使用 next-server
套件作為 next
的替代品相比,此目標具有更最佳化的輸出。
雖然這個套件已過時且無法直接使用,但我們仍然保留了它。這是因為它具有在套件之間共用的內部元件,並且移動程式碼將需要相當大的工作量。
我們最近做出了這項努力,並將程式碼從 next-server
移回 next
套件中。這表示 Next.js 框架的所有程式碼現在都位於 next
套件中。
這使得初學者和經驗豐富的貢獻者都能更輕鬆地為 Next.js 做出貢獻。現在有一個單一的編譯流程和統一的組建設定。先前,next
和 next-server
有單獨的設定,以及關於哪些程式碼屬於每個套件的任意限制。
升級 Next.js
如果您的專案在較舊版本的 Next.js 上執行,我們建議升級到 Next.js 9。
在大多數情況下,升級不需要進行任何變更。您可以按照升級指南,以確保順利升級體驗。
我們要感謝所有更新指南的社群貢獻者,感謝他們自發布以來所做的努力。
未來有哪些新功能?
本篇部落格文章中概述的全新優化,僅是我們正在開發的更廣泛優化和功能的開端。
我們很快就會分享關於進行中 RFC 的最新消息。在此之前,您可以透過 GitHub 上的 RFC 標籤 搶先一睹為快。
這展示了我們正在研究的一些功能,例如 內建 CSS 支援、public 目錄支援 和 src 目錄支援。
社群
我們很高興看到 Next.js 社群持續成長。
- 我們有超過 800 位貢獻者至少提交過 1 次 commit。
- 在 GitHub 上,這個專案已經獲得超過 41,100 次星號標記。
自上次主要版本發布以來,Next.js 社群規模已擴增一倍,成員超過 10,900 人。 加入我們!
我們對於社群持續的貢獻,以及來自公司和使用者的外部回饋感到興奮,這些都有助於塑造版本發布。