經過 70 個 canary 版本後,我們很高興推出 Next.js 9,主要功能包括:
- 內建零配置 TypeScript 支援:透過自動 TypeScript 支援與整合型別檢查,讓您更有信心地建構應用程式。
- 基於檔案系統的動態路由:透過檔案系統表達複雜的應用程式路由需求,無需自訂伺服器。
- 自動靜態優化:預設建立超快速網站,同時利用伺服器渲染 (Server-Side Rendering) 與靜態預渲染 (Static Prerendering) 功能。
- API 路由:利用熱重載與統一建置流程,快速建立後端應用端點。
- 更多生產環境優化:透過視窗內預取 (in-viewport prefetching) 等優化,讓應用程式反應更靈敏。
- 改進的開發者體驗:不顯眼且易用的改進,幫助您發揮最佳開發效率。
一如往常,我們努力確保所有這些改進都向後相容。對於大多數 Next.js 應用程式,您只需要執行:
極少情況下您的程式碼庫可能需要調整。詳情請參閱升級指南。
自上次發布以來,我們很高興看到 IGN、Bang & Olufsen、Intercom、Buffer 和 Ferrari 等公司採用 Next.js 上線。查看展示區了解更多!
內建零配置 TypeScript 支援
一年前 Next.js 6 透過 @zeit/next-typescript
插件引入了基礎 TypeScript 支援。使用者還需要自訂 .babelrc
並在 next.config.js
中啟用該功能。
配置完成後,該插件允許 Next.js 建置 .ts
和 .tsx
檔案。然而,它並未整合型別檢查,Next.js 核心也未提供型別定義。這意味著社群套件必須單獨維護於 DefinitelyTyped 中,可能與版本不同步。
在與眾多新舊使用者交流後,我們發現大多數人對使用 TypeScript 非常感興趣。他們希望有更可靠且標準化的解決方案,能輕鬆將 TypeScript 整合到現有或新程式碼庫中。
因此,我們決定將 TypeScript 支援整合到 Next.js 核心中,改善開發者體驗並提升效率。
自動化設定
在 Next.js 中使用 TypeScript 非常簡單:將任何檔案、頁面或元件從 .js
重新命名為 .tsx
。然後執行 next dev
!
這會讓 Next.js 偵測到您的專案正在使用 TypeScript。Next.js CLI 將引導您安裝 React 和 Node.js 所需的型別定義。
如果尚未存在,Next.js 還會建立一個預設的 tsconfig.json
並提供合理的預設值。此檔案允許在 Visual Studio Code 等編輯器中進行整合型別檢查。
Next.js 9 自動化 TypeScript 設定
整合型別檢查
Next.js 為您在開發和生產建置時處理型別檢查。
在開發過程中,Next.js 會在儲存檔案後顯示型別錯誤。型別檢查在背景執行,讓您可以立即在瀏覽器中與更新後的應用程式互動。型別錯誤將在可用時傳播到瀏覽器。
Next.js 9 開發型別檢查
如果存在型別錯誤,Next.js 也會自動使生產建置(即 next build
)失敗。這有助於防止將損壞的程式碼部署到生產環境。
Next.js 9 生產型別檢查
Next.js 核心使用 TypeScript 編寫
過去幾個月我們已將大部分程式碼庫遷移到 TypeScript,這不僅強化了程式碼品質,還讓我們能為所有核心模組提供型別定義。
例如,當您導入 next/link
時,支援 TypeScript 的編輯器將顯示允許的屬性及其接受的值。
Next.js 核心型別
動態路由區段
動態路由(也稱為 URL 段或簡潔 URL)是 Next.js 發布 2.5 年後 GitHub 上最早的功能請求之一!
這個問題在 Next.js 2.0 中通過引入自訂伺服器 API 以程式化方式使用 Next.js 而「解決」。這允許將 Next.js 作為渲染引擎使用,實現抽象化並將傳入 URL 映射到特定頁面進行渲染。
我們與使用者交流並檢查了許多應用程式,發現許多人使用自訂伺服器。一個模式浮現:使用自訂伺服器最主要的原因就是動態路由。
然而,自訂伺服器有其缺點:路由在伺服器層級而非代理層處理,它作為單體部署和擴展,且容易出現效能問題。
由於自訂伺服器要求整個應用程式必須在一個實例中可用,因此通常難以部署到解決這些問題的無伺服器 (Serverless) 環境。無伺服器請求在代理層路由,並獨立擴展/執行以避免效能瓶頸。
此外,我們相信可以提供更好的開發者體驗!Next.js 的許多魔法始於當您建立一個名為 pages/blog.js
的檔案時,突然就有一個可透過 /blog
存取的頁面。
為什麼使用者需要建立自己的伺服器並學習 Next.js 的程式化 API 來支援像 /blog/my-first-post
(/blog/:id
)這樣的路由?
基於這些回饋和願景,我們開始研究由使用者已知的 pages/
目錄驅動的路由映射解決方案。
建立動態路由頁面
Next.js 支援建立帶有基本命名參數的路由,這種模式由 path-to-regexp
(驅動 Express 的函式庫)推廣。
現在可以透過在 pages
目錄中建立一個名為 pages/post/[pid].js
的檔案來建立匹配 /post/:pid
路由的頁面!
Next.js 會自動匹配像 /post/1
、/post/hello-nextjs
等請求,並渲染 pages/post/[pid].js
中定義的頁面。匹配的 URL 段將作為查詢參數傳遞給您的頁面,參數名稱由 [方括號]
指定。
例如:給定以下頁面和請求 /post/hello-nextjs
,query
物件將是 { pid: 'hello-nextjs' }
:
也支援多個動態 URL 段!
[param]
語法支援目錄名稱和檔案名稱,意味著以下範例都有效:
您可以在 Next.js 文件 或 Next.js 學習區 閱讀更多關於此功能的資訊。
自動靜態優化
Next.js 在大約兩年前發布的 v3 版本中增加了靜態網站生成支援。當時,這是 Next.js 最受期待的功能。
這有充分的理由:靜態網站無疑是快速的!它們不需要伺服器端計算,可以從 CDN 位置即時串流給終端使用者。
然而,在伺服器端渲染或靜態生成應用程式之間的選擇是二元的,您要麼選擇伺服器端渲染,要麼選擇靜態生成。沒有中間地帶。
實際上,應用程式可能有不同的需求。這些需求需要不同的渲染策略和權衡。
例如,首頁和行銷頁面通常包含靜態內容,非常適合靜態優化。
另一方面,產品儀表板可能受益於伺服器端渲染,因為資料頻繁更新。
我們開始探索如何讓使用者兩全其美,並預設實現快速。我們如何為使用者提供靜態行銷頁面和動態伺服器渲染頁面?
從 Next.js 9 開始,使用者不再需要選擇完全伺服器渲染或靜態導出應用程式。讓您可以按頁面獲得兩者的優勢。
自動部分靜態導出
引入了一種啟發式方法來自動判斷頁面是否可以預渲染為靜態 HTML。
此判斷基於頁面是否通過使用 getInitialProps
具有阻塞資料需求。
這種啟發式方法允許 Next.js 產生包含伺服器渲染和靜態生成頁面的混合應用程式。
內建的 Next.js 伺服器(next start
)和程式化 API(app.getRequestHandler()
)都透明地支援此建置輸出。無需配置或特殊處理。
靜態生成的頁面仍然是反應式的:Next.js 將在客戶端水合 (hydrate) 您的應用程式,以提供完整的互動性。
此外,如果頁面依賴於 URL 中的查詢參數,Next.js 將在水合後更新您的應用程式。
Next.js 在開發過程中會視覺化地告知您頁面是否將被靜態生成。可以通過點擊隱藏此視覺提示。
Next.js 靜態優化指示器
靜態生成的頁面也會顯示在 Next.js 的建置輸出中:
Next.js 建置輸出類型指示器
API 路由
在許多建構 React 應用程式的情況下,您最終需要某種後端。無論是從資料庫檢索資料還是處理使用者提供的資料(例如聯絡表單)。
我們發現許多需要後端的使用者使用自訂伺服器建構他們的 API。這樣做時,他們遇到了不少問題。例如,Next.js 不編譯自訂伺服器程式碼,意味著您不能使用 import
/ export
或 TypeScript。
因此,許多使用者最終在自訂伺服器之上實作自己的自訂編譯流程。雖然這解決了他們的目標,但容易出現許多陷阱:例如,當配置錯誤時,整個應用程式的樹搖 (tree shaking) 將被禁用。
這引發了一個問題:如果我們將 Next.js 提供的開發者體驗帶到建構 API 後端會怎樣?
今天我們很高興推出 API 路由,這是 Next.js 為建構後端提供的最佳開發者體驗。
要開始使用 API 路由,您需要在 pages/
目錄內建立一個名為 api/
的目錄。
此目錄中的任何檔案將自動映射到 /api/<您的路由>
,與其他頁面檔案映射到路由的方式相同。
例如,pages/api/contact.js
將映射到 /api/contact
。
注意:API 路由也支援動態路由!
pages/api/
目錄中的所有檔案都導出一個請求處理函式,而不是 React 元件:
req
指 NextApiRequest,它擴展了 http.IncomingMessageres
指 NextApiResponse,它擴展了 http.ServerResponse
通常 API 端點接收一些傳入資料,例如查詢字串、請求主體或 cookies,並回應其他資料。
在調查將 API 路由支援添加到 Next.js 時,我們注意到在許多情況下使用者並不直接使用 Node.js 的請求和回應物件。相反,他們使用像 Express 這樣的伺服器函式庫提供的抽象。
這樣做的原因是,在許多情況下,傳入資料是某種需要先解析才能使用的文字。因此這些特定的伺服器函式庫幫助減輕手動解析資料的負擔,通常通過中介軟體 (middleware)。最常用的中介軟體提供查詢字串、主體和 cookies 解析,但仍需要一些設定才能開始使用。
Next.js 中的 API 路由將預設提供這些中介軟體,讓您可以立即高效建立 API 端點:
除了使用傳入資料外,您的 API 端點通常也會回傳資料。常見的回應是 JSON。Next.js 預設提供 res.json()
以簡化發送資料:
在開發過程中對 API 端點進行更改時,程式碼會自動重新載入,因此無需重啟伺服器。
生產環境優化
視窗內 <Link>
預取
Next.js 9 將自動預取出現在視窗內的 <Link>
元件。
此功能通過使導航到新頁面更快,提高了應用程式的反應速度。
Next.js 使用 Intersection Observer 在背景預取必要資源。
這些請求優先級較低,並讓位給 fetch()
或 XHR 請求。如果使用者啟用了資料節省模式,Next.js 將避免自動預取。
您可以通過將 prefetch
屬性設為 false
來為很少訪問的頁面選擇退出此功能:
預設優化的 AMP
Next.js 9 現在會自動為 AMP-first 和混合 AMP 頁面渲染優化的 AMP。
雖然 AMP 頁面需要手動啟用,但 Next.js 會自動優化其輸出。這些優化可以帶來高達 50% 的渲染速度提升!
這項變更得益於 Sebastian Benz 在 AMP 優化工具 上的卓越貢獻。
針對 typeof window
分支的無效程式碼消除
Next.js 9 在伺服器和客戶端建置時會將 typeof window
替換為適當的值(undefined
或 object
)。這項變更讓 Next.js 能自動從生產環境建置的應用程式中移除無效程式碼。
如果使用者在 getInitialProps
或其他應用程式部分有僅限伺服器的程式碼,他們應該會看到客戶端套件大小減少。
開發者體驗改進
編譯指示器
在 9 之前的版本中,唯一能知道熱程式碼替換即將發生(以及 Next.js 編譯工具鏈正在運作)的方式是查看開發者控制台。
然而很多時候使用者關注的是渲染結果,因此難以判斷 Next.js 是否仍在進行編譯工作。例如,你可能正在修改頁面上不明顯的樣式,無法立即知道它們是否已更新。
為此,我們創建了一個 RFC / "good first issue" 來討論如何指示工作正在進行的潛在解決方案。
我們在 RFC 中收到了許多設計師和工程師的回饋,例如他們的偏好和指示器設計的潛在方向。
Rafael Almeida 抓住這個機會與我們的團隊合作,實作了一個全新的指示器,現在 Next.js 9 預設提供。
每當 Next.js 正在進行編譯工作時,你會在頁面右下角看到一個小三角形顯示!
Next.js 編譯指示器
控制台輸出
傳統上,在開發過程中進行變更時,Next.js 會顯示一個編譯指示狀態,並持續清除畫面。
這種行為會導致一些問題。最明顯的是它會清除來自應用程式程式碼的控制台輸出,例如當你在元件中添加 console.log
。同時也會影響使用外部工具(如 Vercel CLI 或 docker-compose
)拼接日誌輸出的情況。
從 Next.js 9 開始,日誌輸出的跳動減少且不再清除畫面。這提供了更好的整體體驗,因為你的終端視窗將顯示更多相關資訊且閃爍減少,同時 Next.js 能更好地與你已使用的工具整合。
Next.js 開發控制台輸出
特別感謝 Justin Chase 在輸出清除方面的合作。
建置輸出統計資料
現在使用 next build
為生產環境建置應用程式時,會提供所有已建置頁面的詳細視圖。
每個頁面都會自動顯示一些統計資料。
最突出的是套件大小。隨著應用程式的增長,JavaScript 套件也會變大,這個建置時指示將幫助你監控生產套件的增長情況。未來你還可以為頁面設定 效能預算,超過預算將導致生產建置失敗。
Next.js 建置頁面大小
除了套件大小,我們還顯示每個頁面使用了多少專案元件和 node_modules
元件。這可以反映頁面的複雜度。
Next.js 頁面套件計數
每個頁面還會標示是靜態優化還是伺服器端渲染,因為每個頁面的行為可能不同。
Next.js 建置頁面類型
每頁配置物件
現在每個頁面都可以匯出一個配置物件。最初這個配置允許你選擇啟用 AMP,未來你將能配置更多頁面特定選項。
要啟用混合 AMP 渲染,可以使用值 'hybrid'
:
withAmp
高階元件已被移除,改用這個新的配置方式。
我們提供了一個 codemod 來自動將 withAmp
的使用轉換為新的配置物件。你可以在 升級指南 中閱讀更多相關資訊。
程式碼庫改進
我們最近對工具進行了一些變更,以提供更好的貢獻體驗,並確保隨著程式碼庫增長時的穩定性。
如你在 TypeScript 部分所讀到的,Next.js 核心現在使用 TypeScript 編寫,並自動為 Next.js 應用程式生成類型。這不僅對使用 Next.js 建置的應用程式有用,對核心程式碼庫的工作也很有幫助,因為你會自動獲得類型錯誤和自動完成。
Next.js 已經有一個包含 50 多個 Next.js 應用程式的大型整合測試套件,並針對它們運行測試。這些測試確保新版本發布時升級過程順利,因為之前可用的功能都通過了相同的測試套件。
我們大多數測試都是整合測試,因為在許多情況下它們模擬了開發者在開發過程中使用 Next.js 的「真實」情況。例如,我們有測試模擬對 Next.js 應用程式進行變更,以檢查熱模組替換是否正常工作。
我們的整合測試主要基於 Selenium webdriver,我們將其與 chromedriver 結合使用以在無頭 Chrome 中進行測試。然而隨著時間推移,其他瀏覽器(尤其是像 Internet Explorer 11 這樣的舊瀏覽器)會出現某些問題。
由於我們使用了 Selenium,我們能夠自動在多個瀏覽器上運行測試。
目前,我們在 Chrome、Firefox、Safari 和 Internet Explorer 11 上運行測試套件。
與 Google Chrome 團隊的合作
Google Chrome 團隊一直通過貢獻 RFC 和拉取請求來改進 Next.js。
這次合作的目標是大規模效能改進,重點關注套件大小、啟動和水合時間。
例如,這些變更將改善小型網站的體驗,也會改善像 Hulu、Twitch 和 Deliveroo 這樣的大型應用程式。
Module / Nomodule
第一個重點領域是向支援現代 JavaScript 的瀏覽器發送現代 JavaScript。
例如,目前 Next.js 需要為 async
/await
語法提供 polyfill,因為程式碼可能在不相容 async
/await
的瀏覽器中執行,這會導致錯誤。
Next.js Module/Nomodule 合作 RFC
為了避免破壞舊瀏覽器同時仍向支援的瀏覽器發送現代 JavaScript,Next.js 將採用 module/nomodule 模式。這種模式提供了一種可靠的機制,可以向現代瀏覽器提供現代 JavaScript,同時允許舊瀏覽器回退到帶有 polyfill 的 ES5。
Next.js 中 module/nomodule 的 RFC 可以在這裡找到。
改進的套件拆分
Next.js 目前的套件拆分策略基於一種比例啟發式方法,將模組包含在單一的「commons」區塊中。由於只有一個套件,粒度非常小,程式碼要麼被不必要地下載(因為 commons 區塊可能包含特定路由實際上不需要的程式碼),要麼在多個頁面套件中重複。
Next.js 分塊合作 RFC
改進套件拆分的 RFC 可以在這裡找到。
其他改進
Chrome 團隊還在進行許多其他優化和變更來改進 Next.js。這些的 RFC 將很快分享。
這些 RFC 和拉取請求都標記為「Collaboration」,以便在 Next.js 問題追蹤器中輕鬆找到。
社群
我們很高興看到 Next.js 社群的持續成長。
這個版本有超過 65 位拉取請求作者貢獻了核心改進或範例。
說到範例,我們現在提供了超過 200 個關於如何將 Next.js 與不同函式庫和技術整合的範例!包括大多數 css-in-js 和資料獲取函式庫。
- 我們有超過 720 位貢獻者提交了至少 1 次提交。
- 在 GitHub 上,該專案已被加星標超過 38,600 次。
- 自首次發布以來提交了超過 3,400 個拉取請求,即自上一個主要版本以來增加了 超過 800 個!
Next.js 社群自上一個主要版本以來已翻倍,擁有超過 8,600 名成員。加入我們!
我們感謝我們的社群以及所有幫助塑造這個版本的外部回饋和貢獻。