2019 年 2 月 11 日,星期一
Next.js 8
發佈者我們很榮幸今天推出正式版 Next.js 8,它具備以下特性:
- 無伺服器 Next.js
- 大幅降低建置時記憶體用量
- 建置時環境設定
- 預先擷取效能提升
- 更小的初始 HTML 大小
- 改進的隨需載入項目
- 在開發環境中更快的連接埠監聽速度
- 更快的靜態匯出
- Head 元素重複資料刪除
- 新的 crossOrigin 設定選項
- 移除內嵌 JavaScript
- API 驗證範例
一如既往,我們致力於確保所有這些優點都**完全向下相容**。對於大多數 Next.js 應用程式,您只需要執行
npm i next@latest react@latest react-dom@latest
我們非常感謝我們的社群以及所有看好我們成功的人。自從我們上次的部落格文章以來,我們看到像 AT&T、Starbucks 星巴克 和 Twitch 等公司使用 Next.js 重新發布他們的公開網站和應用程式。
無伺服器 Next.js
無伺服器部署藉由將您的應用程式分割成更小的部分(也稱為 **lambda 函式**)來顯著提高可靠性和可擴展性。在 Next.js 的情況下,`pages` 目錄中的每個頁面都會變成一個無伺服器 lambda 函式。
無伺服器架構有許多優點。參考連結在 Express 的上下文中討論了其中一些優點,但這些原則普遍適用:無伺服器允許分散式故障點、無限擴展性,並且以「用多少付多少」的模式提供令人難以置信的價格優勢。
要在 Next.js 中啟用**無伺服器模式**,請在 `next.config.js` 中新增 `serverless` 建構 `target`
module.exports = {
target: 'serverless',
};
`serverless` target 會為每個頁面輸出一個 lambda 函式。這個檔案是完全獨立的,不需要任何依賴項即可運行
- `pages/index.js` => `.next/serverless/pages/index.js`
- `pages/about.js` => `.next/serverless/pages/about.js`
Next.js 無伺服器函式的簽名與 Node.js HTTP 伺服器回呼類似
type Function = (req: http.IncomingMessage, res: http.ServerResponse) => void;
- http.IncomingMessage
- http.ServerResponse
void
表示函式沒有返回值,相當於 JavaScript 的undefined
。呼叫該函式將會結束請求。
由於不同的託管平台有著不同的函式簽章,Next.js 為無伺服器部署提供了低階 API。一般來說,您會需要用一個相容性層來包裝 Next.js 無伺服器建置的輸出。
例如,如果平台支援 Node.js 的 http.Server 類別
const http = require('http');
const page = require('./.next/serverless/about.js');
const server = new http.Server((req, res) => page.render(req, res));
server.listen(3000, () => console.log('Listening on https://127.0.0.1:3000'));
摘要
- 用於實現無伺服器部署的低階 API
pages
目錄中的每個頁面都會變成一個無伺服器函式 (lambda)- 建立盡可能最小的無伺服器函式 (基本 zip 大小為 50 KB)
- 針對函式的快速 冷啟動 進行最佳化
- 無伺服器函式沒有任何依賴項(它們已包含在函式套件中)
- 使用 Node.js 的 http.IncomingMessage 和 http.ServerResponse
- 在
next.config.js
中使用target: 'serverless'
選擇加入 server
目標仍然完全支援並維護- 在
serverless
模式下不支援publicRuntimeConfig
和serverRuntimeConfig
。請改用建置時設定。
大幅降低建置時的記憶體使用量
我們已為 webpack 貢獻程式碼,以提升 Next.js(以及 webpack 生態系統其他部分!)的建置效能和資源利用率。
這項努力成果是,在效能不降低的情況下,**記憶體用量最高提升 16 倍**。
記憶體釋放速度更快,而且在高負載(多個頁面)的情況下,程序也不再崩潰。
我們很快就會深入探討如何達成這項優化。敬請密切關注 Next.js 部落格。
建置時環境設定
在檢閱 Next.js 應用程式時,我們觀察到一個經常重複出現的模式,就是新增 babel-plugin-transform-define
或 webpack.DefinePlugin
來提供應用程式的設定值。
在 Next.js 8 中,我們在 next.config.js
中引入了一個名為 env
的新鍵值,以向後相容的方式提供相同的功能。
module.exports = {
env: {
customKey: 'MyValue',
},
};
這將允許您在程式碼中使用 process.env.customKey
。例如:
export default function IndexPage() {
return <h1>The value of customKey is: {process.env.customKey}</h1>;
}
process.env.customKey
將在建置時被替換為 'MyValue'
。
預取效能提升
Next.js 路由器允許您預取頁面以加快導覽速度。
import Link from 'next/link';
export default function IndexPage() {
return (
<>
<Link href="/about" prefetch>
<a>To About Page</a>
</Link>
</>
);
}
其運作方式是預取每個具有 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 dev
時,Next.js 並不會編譯 pages 目錄中的所有頁面。相反,它會在您訪問頁面時進行編譯。
例如,當訪問 https://127.0.0.1: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 已經被基於 WebSocket 的方法取代,這意味著 ping 仍然會發生,但只有在檢查 WebSocket 連線時才能看到。
特別感謝 JJ Kasper 協助完成 WebSocket 的轉換工作。
更快的開發環境埠口監聽速度
啟動 Next.js 開發伺服器時,它必須執行一些初始編譯才能提供服務請求。預設情況下,Next.js 會等待此編譯步驟完成後才會啟動 HTTP 伺服器,這意味著如果您執行 next dev
然後開啟瀏覽器,有時可能會收到「無法連線到此網站」的訊息,因為 HTTP 伺服器尚未開始監聽連線。
使用 Next.js 8,HTTP 伺服器將在編譯開始前就開始監聽連線。這表示,如果您在編譯完成前前往 https://127.0.0.1:3000/
,請求將會等待初始編譯完成後再提供服務,而無需重新整理頁面直到它可用為止。
特別感謝 Brian Beck 實作此功能。
更快的靜態匯出速度
Next.js 專注於預渲染的概念,以實現高性能。預渲染有兩種形式:
- 伺服器渲染:每個請求都會觸發渲染。因此,終端使用者無需等待任何 JS 下載即可開始使用數據。
- 靜態渲染:我們輸出靜態檔案,可以直接提供服務,而無需在伺服器上執行任何程式碼。
從 Next.js 8 開始,如果您的機器有多個 CPU 核心,則透過 next export
進行靜態渲染的速度將會提升。
根據使用 4 核心 CPU 的 MacBook 進行的測試,透過利用所有核心來預渲染頁面,匯出速度從大約每秒 25 頁提升到每秒 75 頁。
Next.js 會自動偵測 CPU 核心的數量並相應地分配頁面,無需任何程式碼更改。
特別感謝 Benjamin Kniffler 實作了這個功能。
Head 元素去重複化
建構應用程式時,一個常見的需求是更新頁面的 <head>
元素。例如,設定 <title>
或 <meta name="viewport">
以實現響應式設計。
Next.js 提供了一個內建元件來修改 <head>
。
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>My page title</title>
</Head>
</>
);
}
<Head>
元件甚至可以在不同的元件中多次使用,例如,您的佈局元件可以設定一些預設的 head 標籤。
然而,您可能想要用不同的值覆蓋預設的 head 標籤,在舊版本的 Next.js 中,這會導致標籤在輸出中重複,因為沒有辦法去除重複的標籤。
因此,現在可以為 <Head>
元件內的每個元素提供一個 key
屬性,它會自動去除具有相同 key
值的標籤。
當在兩個標籤上設定 key="viewport"
時,只會渲染最後一個標籤。
import Head from 'next/head';
export default function IndexPage() {
return (
<>
<Head>
<title>My page title</title>
<meta
name="viewport"
content="initial-scale=1.0, width=device-width"
key="viewport"
/>
</Head>
<Head>
<meta
name="viewport"
content="initial-scale=1.2, width=device-width"
key="viewport"
/>
</Head>
</>
);
}
安全性提升
新增 crossOrigin
設定選項
引入此選項的另一個好處是,不再需要自訂 pages/_document.js
即可在應用程式中設定 cross-origin
。
先前的行為仍然受到支援,但會在開發過程中發出警告,以協助開發人員遷移到新引入的選項。
移除內嵌 JavaScript
在使用 Next.js 7 以及更早的版本時,若要啟用內容安全策略 (CSP)script-src 'unsafe-inline'
,因為 Next.js 會建立一個內嵌的 <script>
標籤來傳遞資料,例如,將 getInitialProps
的結果傳遞到客戶端。
在 Next.js 8 中,我們已將這個內嵌腳本標籤改為 JSON 標籤,以便安全地傳輸到客戶端。這表示 Next.js 不再包含任何內嵌腳本。
經過仔細考量,現在可以使用 script-src 'self'
。
API 驗證範例
一直以來,最多人要求的範例之一
隨著 Next.js 8 的推出,我們也推出了一個新建立的範例:with-cookie-auth
這個範例展示了如何針對外部 Node.js API 進行驗證,但所應用的概念適用於任何無狀態 API。
此範例使用 cookie 在伺服器端和客戶端渲染之間共享權杖。
這樣一來,如果應用程式在伺服器上渲染,它仍然可以代表使用者獲取已驗證的資料。
特別感謝貢獻此範例的 Juan Olvera
社群
自首次發布以來,Next.js 已被廣泛應用於各種領域,從財星 500 強公司到個人部落格。我們很高興看到 Next.js 的採用率持續增長。
- 我們有超過 600 位貢獻者,至少提交了 1 次 commit。
- 在 GitHub 上,該專案已獲得超過 34,400 個星標。
- 自首次發布以來,已提交超過 2600 個 Pull Request。
Next.js 社群擁有超過 4,570 位成員。加入我們!