部署
恭喜,現在是發佈到生產環境的時候了。
你可以部署使用 Vercel 管理的 Next.js,或是在 Node.js 伺服器、Docker 映像檔,甚至靜態 HTML 檔案上自行託管。當使用 next start
部署時,所有 Next.js 功能都受到支援。
生產環境建置
執行 next build
會產生應用程式的最佳化版本以用於生產環境。HTML、CSS 和 JavaScript 檔案會根據你的頁面建立。JavaScript 會使用 Next.js 編譯器 編譯,而瀏覽器套件會被 最小化,以協助達到最佳效能並支援所有現代瀏覽器。
Next.js 產生一個標準的部署輸出,供託管和自行託管的 Next.js 使用。這確保了所有功能在這兩種部署方法中都受到支援。在下一個主要版本中,我們將把此輸出轉換為我們的 Build Output API 規範。
使用 Vercel 管理的 Next.js
Vercel,Next.js 的建立者和維護者,為你的 Next.js 應用程式提供託管基礎架構和開發人員體驗平台。
部署到 Vercel 是零設定的,並為全球的可擴展性、可用性和效能提供額外的增強功能。但是,自行託管時仍然支援所有 Next.js 功能。
深入了解Vercel 上的 Next.js 或免費部署範本來試用看看。
自行託管
你可以透過三種不同的方式自行託管 Next.js
🎥 觀看: 深入了解自行託管 Next.js → YouTube (45 分鐘)。
我們有社群維護的部署範例,適用於以下供應商
Node.js 伺服器
Next.js 可以部署到任何支援 Node.js 的託管供應商。請確保你的 package.json
具有 "build"
和 "start"
腳本
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
然後,執行 npm run build
以建置你的應用程式。最後,執行 npm run start
以啟動 Node.js 伺服器。此伺服器支援所有 Next.js 功能。
Docker 映像檔
Next.js 可以部署到任何支援 Docker 容器的託管供應商。當部署到容器協調器(例如 Kubernetes)或在任何雲端供應商的容器內執行時,你可以使用此方法。
- 在你的電腦上安裝 Docker
- 複製我們的範例 (或多環境範例)
- 建置你的容器:
docker build -t nextjs-docker .
- 執行你的容器:
docker run -p 3000:3000 nextjs-docker
透過 Docker 的 Next.js 支援所有 Next.js 功能。
靜態 HTML 匯出
Next.js 允許從靜態網站或單頁應用程式 (SPA) 開始,然後稍後選擇性地升級以使用需要伺服器的功能。
由於 Next.js 支援此靜態匯出,因此可以將其部署和託管在任何可以提供 HTML/CSS/JS 靜態資源的網頁伺服器上。這包括 AWS S3、Nginx 或 Apache 等工具。
以靜態匯出方式執行不支援需要伺服器的 Next.js 功能。深入了解。
要知道的好資訊
- 伺服器元件 透過靜態匯出支援。
功能
圖片最佳化
透過 next/image
進行圖片最佳化,在使用 next start
部署時,可以零設定自行託管。如果你希望有一個獨立的服務來最佳化圖片,你可以設定圖片載入器。
圖片最佳化可以與靜態匯出一起使用,方法是在 next.config.js
中定義自訂圖片載入器。請注意,圖片是在執行階段而非在建置期間進行最佳化。
要知道的好資訊
- 在基於 glibc 的 Linux 系統上,圖片最佳化可能需要額外的設定,以防止過度使用記憶體。
- 深入了解最佳化圖片的快取行為以及如何設定 TTL。
- 如果你願意,你也可以停用圖片最佳化,並且仍然保留使用
next/image
的其他好處。例如,如果你要另外自行最佳化圖片。
中介層
中介層 在使用 next start
部署時,可以零設定自行託管。由於它需要存取傳入的請求,因此在使用靜態匯出時不支援。
中介層使用所有可用 Node.js API 的子集執行階段,以協助確保低延遲,因為它可能會在應用程式中的每個路由或資源之前執行。此執行階段不需要「在邊緣」執行,並且可以在單區域伺服器中運作。在多個區域中執行中介層需要額外的設定和基礎架構。
如果你希望新增需要所有 Node.js API 的邏輯(或使用外部套件),你或許可以將此邏輯移至 版面配置 作為 伺服器元件。例如,檢查 標頭 和 重新導向。你也可以使用標頭、Cookie 或查詢參數,透過 next.config.js
重新導向 或 重寫。如果這不起作用,你也可以使用自訂伺服器。
環境變數
Next.js 可以同時支援建置時和執行階段環境變數。
預設情況下,環境變數僅在伺服器上可用。若要將環境變數公開給瀏覽器,必須以 NEXT_PUBLIC_
作為前綴。但是,這些公開的環境變數將在 next build
期間內嵌到 JavaScript 套件中。
你可以在動態渲染期間安全地在伺服器上讀取環境變數。
import { connection } from 'next/server'
export default async function Component() {
await connection()
// cookies, headers, and other Dynamic APIs
// will also opt into dynamic rendering, meaning
// this env variable is evaluated at runtime
const value = process.env.MY_VALUE
// ...
}
這允許你使用單一 Docker 映像檔,該映像檔可以使用不同的值在多個環境中升級。
要知道的好資訊
- 你可以使用
register
函式在伺服器啟動時執行程式碼。- 我們不建議使用 runtimeConfig 選項,因為這不適用於獨立輸出模式。相反地,我們建議逐步採用 App Router。
快取和 ISR
Next.js 可以快取回應、產生的靜態頁面、建置輸出,以及其他靜態資源,例如圖片、字體和腳本。
快取和重新驗證頁面(使用增量靜態重新產生)使用相同的共用快取。預設情況下,此快取會儲存在 Next.js 伺服器上的檔案系統(磁碟)中。當使用 Pages 和 App Router 自行託管時,這會自動運作。
如果你想要將快取的頁面和資料保存到持久儲存空間,或在 Next.js 應用程式的多個容器或執行個體之間共用快取,則可以設定 Next.js 快取位置。
自動快取
- Next.js 將
Cache-Control
標頭設定為public, max-age=31536000, immutable
,以用於真正不可變的資源。它無法被覆寫。這些不可變的檔案在檔名中包含 SHA-hash,因此可以安全地無限期快取。例如,靜態圖片匯入。你可以設定圖片的 TTL。 - 增量靜態重新產生 (ISR) 將
Cache-Control
標頭設定為s-maxage: <getStaticProps 中的 revalidate>, stale-while-revalidate
。此重新驗證時間在你的getStaticProps
函式中以秒為單位定義。如果你設定revalidate: false
,則預設為一年的快取持續時間。 - 動態渲染的頁面將
Cache-Control
標頭設定為private, no-cache, no-store, max-age=0, must-revalidate
,以防止快取使用者特定的資料。這適用於 App Router 和 Pages Router。這也包括草稿模式。
靜態資源
如果你想要在不同的網域或 CDN 上託管靜態資源,你可以在 next.config.js
中使用 assetPrefix
設定。當擷取 JavaScript 或 CSS 檔案時,Next.js 將使用此資源前綴。將你的資源分離到不同的網域確實會帶來額外花費在 DNS 和 TLS 解析上的時間的缺點。
設定快取
預設情況下,產生的快取資源將儲存在記憶體(預設為 50mb)和磁碟上。如果你使用容器協調平台(如 Kubernetes)託管 Next.js,則每個 Pod 都將擁有快取的副本。為了防止顯示過時的資料,因為預設情況下快取不在 Pod 之間共用,你可以設定 Next.js 快取以提供快取處理器並停用記憶體內快取。
若要設定自行託管時的 ISR/資料快取位置,你可以在 next.config.js
檔案中設定自訂處理器
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // disable default in-memory caching
}
然後,在專案的根目錄中建立 cache-handler.js
,例如
const cache = new Map()
module.exports = class CacheHandler {
constructor(options) {
this.options = options
}
async get(key) {
// This could be stored anywhere, like durable storage
return cache.get(key)
}
async set(key, data, ctx) {
// This could be stored anywhere, like durable storage
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}
async revalidateTag(tags) {
// tags is either a string or an array of strings
tags = [tags].flat()
// Iterate over all entries in the cache
for (let [key, value] of cache) {
// If the value's tags include the specified tag, delete this entry
if (value.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
}
// If you want to have temporary in memory cache for a single request that is reset
// before the next request you can leverage this method
resetRequestCache() {}
}
使用自訂快取處理器將允許你確保託管 Next.js 應用程式的所有 Pod 之間的一致性。例如,你可以將快取的值儲存在任何地方,例如 Redis 或 AWS S3。
要知道的好資訊
revalidatePath
是快取標籤之上的便利層。呼叫revalidatePath
將使用提供的頁面的特殊預設標籤呼叫revalidateTag
函式。
建立快取
Next.js 會在 next build
期間產生一個 ID,以識別您正在服務的應用程式版本。相同的建置版本應該被使用並啟動多個容器。
如果您為環境的每個階段重新建置,您將需要產生一個一致的建置 ID,以便在容器之間使用。請在 next.config.js
中使用 generateBuildId
命令。
module.exports = {
generateBuildId: async () => {
// This could be anything, using the latest git hash
return process.env.GIT_HASH
},
}
版本偏移
Next.js 將自動緩解大多數 版本偏移 的情況,並在偵測到時自動重新載入應用程式以擷取新的資源。例如,如果 deploymentId
中存在不符,頁面之間的轉換將執行硬導航,而不是使用預先擷取的值。
當應用程式重新載入時,如果應用程式狀態未設計為在頁面導航之間持續存在,則可能會遺失應用程式狀態。例如,使用 URL 狀態或本機儲存空間將在頁面重新整理後持續保存狀態。但是,像 useState
這樣的元件狀態將在這種導航中遺失。
Vercel 為 Next.js 應用程式提供額外的 偏移保護,以確保即使在新版本部署後,舊版本的用戶端仍然可以使用先前版本的資源和功能。
您可以手動在您的 next.config.js
檔案中設定 deploymentId
屬性,以確保每個請求都使用 ?dpl
查詢字串或 x-deployment-id
標頭。
串流和 Suspense
當您自行託管時,Next.js App Router 支援 串流回應。如果您使用 Nginx 或類似的代理伺服器,您需要將其設定為停用緩衝,以啟用串流。
例如,您可以透過將 X-Accel-Buffering
設定為 no
來停用 Nginx 中的緩衝。
module.exports = {
async headers() {
return [
{
source: '/:path*{/}?',
headers: [
{
key: 'X-Accel-Buffering',
value: 'no',
},
],
},
]
},
}
部分預先渲染
部分預先渲染 (實驗性功能) 預設與 Next.js 搭配運作,並非 CDN 功能。這包括部署為 Node.js 伺服器 (透過 next start
) 以及與 Docker 容器一起使用時。
搭配 CDN 使用
當在您的 Next.js 應用程式前端使用 CDN 時,當存取動態 API 時,頁面將包含 Cache-Control: private
回應標頭。這確保產生的 HTML 頁面被標記為不可快取。如果頁面完全預先渲染為靜態,它將包含 Cache-Control: public
,以允許頁面在 CDN 上快取。
如果您不需要靜態和動態元件的混合,您可以將整個路由設為靜態,並在 CDN 上快取輸出的 HTML。如果未使用動態 API,則此自動靜態最佳化是執行 next build
時的預設行為。
after
當使用 next start
自行託管時,完全支援 after
。
當停止伺服器時,請確保透過傳送 SIGINT
或 SIGTERM
訊號並等待來進行優雅關閉。這允許 Next.js 伺服器等待,直到在 after
內部使用的待處理回呼函式或 Promise 完成。
如果您想在自訂基礎架構上使用 after
,請查看您的供應商文件,以檢視對 after
的支援。
參考資料:serverless 平台對 after
的支援
在 serverless 環境中使用 after
需要在傳送回應後等待非同步任務完成。在 Next.js 和 Vercel 中,這是使用稱為 waitUntil(promise)
的基本機制實現的,它擴展了 serverless 調用的生命週期,直到傳遞給 waitUntil
的所有 Promise 都已 settled。如果您希望您的使用者能夠執行 after
,您將必須提供您自己的 waitUntil
實作,使其以類似的方式運作。
當呼叫 after
時,Next.js 將像這樣存取 waitUntil
const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil
這表示 globalThis[Symbol.for('@next/request-context')]
預期包含像這樣的物件
type NextRequestContext = {
get(): NextRequestContextValue | undefined
}
type NextRequestContextValue = {
waitUntil?: (promise: Promise<any>) => void
}
以下是實作範例。
import { AsyncLocalStorage } from 'node:async_hooks'
const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()
// Define and inject the accessor that next.js will use
const RequestContext: NextRequestContext = {
get() {
return RequestContextStorage.getStore()
},
}
globalThis[Symbol.for('@next/request-context')] = RequestContext
const handler = (req, res) => {
const contextValue = { waitUntil: YOUR_WAITUNTIL }
// Provide the value
return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}
生產環境檢查清單
靜態匯出
多區域
這有幫助嗎?