我們很榮幸今天推出正式版的 Next.js 8,主要功能包括:
- 無伺服器 Next.js
- 大幅降低建置時記憶體使用量
- 建置時環境配置
- 預取效能改進
- 更小的初始 HTML 體積
- 改進的按需載入條目
- 開發模式下更快的埠監聽
- 更快的靜態匯出
- Head 元素去重
- 新增 crossOrigin 配置選項
- 移除內聯 JavaScript
- API 認證範例
一如既往,我們努力確保所有這些改進都完全向下相容。對於大多數 Next.js 應用程式,您只需要執行:
我們感謝我們的社群以及所有相信我們會成功的人。自從我們上一篇部落格文章以來,我們已經看到像 AT&T、Starbucks 和 Twitch 這樣的公司使用 Next.js 重新推出了他們的公開網站和應用程式。
無伺服器 Next.js
Next.js 的無伺服器目標會從頁面輸出無伺服器函數
無伺服器部署通過將您的應用程式拆分為更小的部分(也稱為 lambdas)來顯著提高可靠性和可擴展性。在 Next.js 的情況下,pages
目錄中的每個頁面都會成為一個無伺服器 lambda。
無伺服器有許多好處。參考連結在 Express 的背景下討論了其中一些,但這些原則普遍適用:無伺服器允許分散的故障點、無限的可擴展性,並且採用「按使用付費」模式非常經濟實惠。
要在 Next.js 中啟用無伺服器模式,請在 next.config.js
中添加 serverless
建置 target
:
serverless
目標會為每個頁面輸出一個獨立的 lambda。這個檔案完全獨立,不需要任何依賴即可執行:
pages/index.js
=>.next/serverless/pages/index.js
pages/about.js
=>.next/serverless/pages/about.js
Next.js 無伺服器函數的簽名類似於 Node.js HTTP 伺服器回調:
- http.IncomingMessage
- http.ServerResponse
void
表示該函數沒有返回值,等同於 JavaScript 的undefined
。呼叫該函數將完成請求。
Next.js 為無伺服器部署提供了低階 API,因為託管平台有不同的函數簽名。通常情況下,您會希望用相容層包裝 Next.js 無伺服器建置的輸出。
例如,如果平台支援 Node.js http.Server 類:
總結
- 實現無伺服器部署的低階 API
pages
目錄中的每個頁面都成為一個無伺服器函數 (lambda)- 建立最小的無伺服器函數(50 KB 基礎 zip 大小)
- 針對函數的快速冷啟動進行了優化
- 無伺服器函數具有 0 依賴(它們包含在函數包中)
- 使用 Node.js 的 http.IncomingMessage 和 http.ServerResponse
- 通過在
next.config.js
中設置target: 'serverless'
來選擇啟用 server
目標仍然完全支援並維護publicRuntimeConfig
和serverRuntimeConfig
在serverless
模式下不支援。請改用建置時配置。
大幅降低建置時記憶體使用量
我們為 webpack 做出了貢獻,以改進 Next.js(以及整個 webpack 生態系統!)的建置效能和資源利用率。
這項努力使得記憶體使用量最多提高了 16 倍,且效能沒有任何下降。
記憶體釋放得更快,且在大量壓力下(許多頁面)程序不再崩潰。
我們將很快深入探討我們是如何實現這一優化的。請關注 Next.js 部落格。
建置時環境配置
在審查 Next.js 應用程式時,我們經常觀察到一個重複出現的模式,即添加 babel-plugin-transform-define
或 webpack.DefinePlugin
來為應用程式提供配置值。
在 Next.js 8 中,我們在 next.config.js
中引入了一個名為 env
的新鍵,以向後相容的方式提供相同的功能:
這將允許您在程式碼中使用 process.env.customKey
。例如:
process.env.customKey
將在建置時被替換為 'MyValue'
。
預取效能改進
Next.js 路由器允許您預取頁面以實現更快的導航:
它的工作原理是預取具有 prefetch
屬性的每個連結的 JavaScript 包。
在 Next.js 8 之前的版本中,這意味著將 <script>
標籤注入到文件 <body>
中。
然而,這在打開頁面時引入了一些開銷,最明顯的是瀏覽器的「加載」指示會顯示得比您預期的時間更長,即使頁面已經可以互動。
在 Next.js 8 中,prefetch
使用 <link rel="preload">
而不是 <script>
標籤。它還只在 onload
之後開始預取,以允許瀏覽器管理資源。
此外,Next.js 現在檢測 2G 網路和 navigator.connection.saveData
模式,以在較慢的網路連接上禁用預取。
更小的初始 HTML 體積
由於 Next.js 預渲染 HTML,它將頁面包裝到一個帶有 <html>
、<head>
、<body>
和渲染頁面所需的 JavaScript 文件的預設結構中。
在 Next.js 7 中,我們將初始負載優化到 1.50KB,這比前一版本減少了 7.4%。
我們能夠進一步將初始負載大小減少到 1.16KB,再減少 23%:
7.0 | 8.0 | 差異 | |
---|---|---|---|
文件大小(伺服器渲染) | 1.50KB | 1.16KB | 23% 更小 |
我們減少大小的主要方式是:
- 移除了頁面初始化的內聯腳本
/_error
頁面不再包含在每次頁面加載中
按需加載 /_error
當生產環境中發生錯誤時,會渲染 /_error
頁面以顯示發生了錯誤。
自從 Next.js 的第一個版本發布以來,/_error
頁面的腳本標籤就是初始 HTML 的一部分,這意味著即使沒有運行時錯誤,它也會被加載。
從 Next.js 8 開始,/_error
頁面在發生錯誤時按需加載。
這意味著預設情況下需要加載、解析和執行的程式碼更少。
開發體驗改進
Next.js 的主要目標之一是提供最佳的生產效能和最佳的開發者體驗。此版本包括許多基於用戶反饋的細微改進。
改進的按需載入條目
開箱即用,Next.js 會自動編譯僅正在_積極_開發的頁面。Next.js 不會在每次運行 next dev
時編譯 pages 目錄中的所有頁面。相反,它會在您訪問它們時編譯頁面。
例如,當訪問 http://localhost:3000/my-page
時,pages/my-page.js
文件會按需編譯,然後渲染頁面。
這確保開發者在啟動開發伺服器時不必等待所有頁面編譯完成,這在較大的應用程式上可能需要相當長的時間。它保持記憶體使用量低,並且編譯器快速,因為編譯器不需要在打包時考慮所有頁面。
按需載入條目的流程
當一個頁面在 25 秒內未被訪問時,它將從編譯器的建置快取中釋放,以保持編譯器快速並減少記憶體使用量。
Next.js 跟踪頁面被訪問的方式是使用輪詢機制。每 5 秒,會發送一個「on-demand-entries-ping」以使 Next.js 開發伺服器知道某個頁面正在被訪問。
自從此功能首次發布以來,ping 是使用 window.fetch
呼叫完成的,這意味著每次觸發 ping 時,它都會在瀏覽器開發工具的 console
和 network
選項卡中顯示。
最常被請求的功能之一是能夠從瀏覽器開發工具中隱藏這些請求,因為這些請求可能會增加不必要的噪音。
我們很高興地宣布,在 Next.js 8 中,基於 fetch
的 ping 已被基於 WebSockets 的方法取代,這意味著 ping 仍然會發生,但只有在檢查 WebSocket 連接時才會可見。
特別感謝 JJ Kasper 在轉換到 WebSockets 方面的合作。
開發模式下更快的埠監聽
當啟動 Next.js 開發伺服器時,它必須執行一些初始編譯才能提供請求,預設情況下,Next.js 會等待此編譯步驟完成後再啟動 HTTP 伺服器,這意味著如果您運行 next dev
然後轉到瀏覽器,有時可能會收到「此站點無法訪問」消息,因為 HTTP 伺服器尚未開始監聽連接。
在 Next.js 8 中,HTTP 將在編譯開始之前監聽連接,這意味著如果您在編譯完成之前轉到 http://localhost:3000/
,請求將等待初始編譯完成後再提供請求,而不必刷新頁面直到它可用。
特別感謝 Brian Beck 實現了此功能。
更快的靜態匯出
Next.js 專注於預渲染作為實現高效能的手段。預渲染有兩種形式:
- 伺服器渲染,其中每個請求觸發一次渲染。因此,最終用戶不必等待任何 JS 下載即可開始消費數據
- 靜態渲染,我們輸出可以直接提供的靜態文件,無需在伺服器上執行任何代碼
從 Next.js 8 開始,通過 next export
進行的靜態渲染如果您的機器有多個 CPU,將會有速度改進。
基於 4 CPU 核心 MacBook 的測試,通過利用所有核心預渲染頁面,匯出速度從大約每秒 25 頁提高到每秒 75 頁。
Next.js 會自動檢測 CPU 核心數量並相應地分配頁面,無需任何代碼更改。
特別感謝 Benjamin Kniffler 實現了此功能。
Head 元素去重
構建應用程式時的一個常見需求是更新頁面的 <head>
元素。例如設置 <title>
或 <meta name="viewport">
以實現響應式設計。
Next.js 提供了一個內建組件來引入對 <head>
的更改:
<Head>
組件甚至可以在不同的組件中多次使用,例如您的佈局組件可以設置一些預設的 head 標籤。
但是,您可能希望用不同的值覆蓋預設的 head 標籤,在舊版本的 Next.js 中,這會導致標籤在輸出中重複,因為沒有辦法去重標籤。
因此,現在可以為 <Head>
組件中的每個元素提供一個 key
屬性,這將自動去重具有相同 key
值的標籤。
當在兩個標籤上設置 key="viewport"
時,只有最後一個會被渲染。
安全性改進
新增 crossOrigin
配置選項
在 Next.js 6 中,我們引入了在 pages/_document.js
中為 <Head>
和 <NextScript>
添加 crossOrigin
屬性的選項,但這並未涵蓋設置 cross-origin
的所有用例。
Next.js 有一個客戶端路由器,它會動態注入 <script>
標籤,這些標籤在注入時缺少 cross-origin
屬性。
為了確保所有 <script>
標籤都設置了 cross-origin
,我們在 next.config.js
中引入了一個新的配置選項
引入此選項的另一個好處是,不再需要自定義 pages/_document.js
來設置應用程式中的 cross-origin
。
之前的行為仍然支援,但會在開發中發出警告,以幫助開發者遷移到新引入的選項。
移除內嵌式 Javascript
當使用 Next.js 7 及以下版本時,若要啟用 內容安全政策 (CSP),使用者必須在政策中包含 script-src 'unsafe-inline'
,因為 Next.js 會建立一個內嵌的 <script>
標籤來傳遞資料,例如將 getInitialProps
的結果傳遞到客戶端。
在 Next.js 8 中,我們已將此內嵌的 script 標籤改為 JSON 標籤,以安全地傳輸到客戶端。這意味著 Next.js 不再包含任何內嵌的 script。
經過謹慎考量後,現在可以使用 script-src 'self'
。
API 驗證範例
歷來最常被要求的範例之一 是如何在 Next.js 中針對外部 API 進行驗證,無論是任何 API 或任何程式語言。
隨著 Next.js 8 的推出,我們也引入了一個新建立的範例:with-cookie-auth
此範例展示了如何針對外部 Node.js API 進行驗證,但所應用的概念適用於任何無狀態 API。
該範例使用 cookie 在伺服器端和客戶端渲染之間共享 token。
這樣一來,如果應用程式在伺服器端渲染,它仍然可以代表使用者獲取經過驗證的資料。
特別感謝貢獻此範例的 Juan Olvera。
社群
自首次發布以來,Next.js 已被從財富 500 強公司到個人部落格的各種場景使用。我們非常高興看到 Next.js 的採用持續增長。
- 我們已有超過 600 位貢獻者 提交了至少 1 次 commit。
- 在 GitHub 上,該專案已獲得超過 34,400 次星標。
- 自首次發布以來,已提交超過 2600 個 pull request。
Next.js 社群擁有超過 4,570 名成員。加入我們!