如何自行託管 Next.js 應用程式

部署您的 Next.js 應用程式時,您可能需要根據基礎架構配置不同功能的處理方式。

🎥 觀看影片: 深入了解自行託管 Next.js → YouTube (45 分鐘)

圖片最佳化

透過 next/image 進行的圖片最佳化在使用 next start 部署時,無需配置即可自行託管。如果您希望使用單獨的服務來最佳化圖片,可以配置圖片載入器

圖片最佳化可與靜態匯出一起使用,方法是在 next.config.js 中定義自訂圖片載入器。請注意,圖片是在執行時最佳化,而非建置期間。

須知事項:

  • 在基於 glibc 的 Linux 系統上,圖片最佳化可能需要額外配置以防止過度記憶體使用。
  • 深入了解最佳化圖片的快取行為以及如何配置 TTL。
  • 如果您願意,也可以停用圖片最佳化,同時保留使用 next/image 的其他好處。例如,如果您自行單獨最佳化圖片。

中介軟體

中介軟體在使用 next start 部署時,無需配置即可自行託管。由於它需要存取傳入請求,因此在使用靜態匯出時不受支援。

中介軟體使用邊緣運行時,這是所有可用 Node.js API 的子集,以幫助確保低延遲,因為它可能在應用程式的每個路由或資產前運行。如果您不希望這樣,可以使用完整的 Node.js 運行時來運行中介軟體。

如果您希望新增需要所有 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、標頭和其他動態 API
  // 也會選擇動態渲染,意味著
  // 此環境變數在執行時評估
  const value = process.env.MY_VALUE
  // ...
}

這允許您使用單一的 Docker 映像,可以在多個環境中推廣,並使用不同的值。

須知事項:

  • 您可以使用 register 函式在伺服器啟動時執行程式碼。
  • 我們不建議使用 runtimeConfig 選項,因為這不適用於獨立輸出模式。相反,我們建議逐步採用應用程式路由器。

快取與 ISR

Next.js 可以快取回應、生成的靜態頁面、建置輸出以及其他靜態資產,如圖片、字型和腳本。

快取和重新驗證頁面(使用增量靜態再生)使用相同的共享快取。預設情況下,此快取儲存在 Next.js 伺服器的檔案系統(磁碟)上。這在使用頁面和應用程式路由器自行託管時自動運作

如果您希望將快取的頁面和資料持久化到持久儲存,或在 Next.js 應用程式的多個容器或實例之間共享快取,可以配置 Next.js 快取位置。

自動快取

  • Next.js 將 Cache-Control 標頭設定為 public, max-age=31536000, immutable 給真正不可變的資產。這無法覆蓋。這些不可變檔案在檔案名稱中包含 SHA 雜湊,因此可以安全地永久快取。例如,靜態圖片匯入。您可以配置 TTL 給圖片。
  • 增量靜態再生 (ISR) 將 Cache-Control 標頭設定為 s-maxage: <revalidate in getStaticProps>, stale-while-revalidate。此重新驗證時間在您的 getStaticProps 函式中以秒為單位定義。如果您設定 revalidate: false,它將預設為一年的快取持續時間。
  • 動態渲染的頁面將 Cache-Control 標頭設定為 private, no-cache, no-store, max-age=0, must-revalidate 以防止使用者特定資料被快取。這適用於應用程式路由器和頁面路由器。這也包括草稿模式

靜態資產

如果您希望在不同的網域或 CDN 上託管靜態資產,可以在 next.config.js 中使用 assetPrefix 配置。Next.js 將在檢索 JavaScript 或 CSS 檔案時使用此資產前綴。將資產分離到不同的網域會帶來 DNS 和 TLS 解析的額外時間。

深入了解 assetPrefix

配置快取

預設情況下,生成的快取資產將儲存在記憶體中(預設為 50mb)和磁碟上。如果您使用 Kubernetes 等容器編排平台託管 Next.js,每個 pod 將擁有快取的副本。為了防止顯示過時資料,因為預設情況下快取不在 pod 之間共享,您可以配置 Next.js 快取以提供快取處理程式並停用記憶體快取。

在自行託管時配置 ISR/資料快取位置,您可以在 next.config.js 檔案中配置自訂處理程式:

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // 停用預設的記憶體快取
}

然後,在專案的根目錄中建立 cache-handler.js,例如:

cache-handler.js
const cache = new Map()

module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }

  async get(key) {
    // 這可以儲存在任何地方,例如持久儲存
    return cache.get(key)
  }

  async set(key, data, ctx) {
    // 這可以儲存在任何地方,例如持久儲存
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }

  async revalidateTag(tags) {
    // tags 是字串或字串陣列
    tags = [tags].flat()
    // 遍歷快取中的所有條目
    for (let [key, value] of cache) {
      // 如果值的標籤包含指定的標籤,刪除此條目
      if (value.tags.some((tag) => tags.includes(tag))) {
        cache.delete(key)
      }
    }
  }

  // 如果您希望為單一請求擁有臨時記憶體快取,並在下一個請求前重置
  // 您可以利用此方法
  resetRequestCache() {}
}

使用自訂快取處理程式將允許您確保所有託管 Next.js 應用程式的 pod 之間的一致性。例如,您可以將快取值儲存在任何地方,如 Redis 或 AWS S3。

須知事項:

  • revalidatePath 是快取標籤上的便利層。呼叫 revalidatePath 將使用提供的頁面的特殊預設標籤呼叫 revalidateTag 函式。

建置快取

Next.js 在 next build 期間生成一個 ID,以識別正在提供的應用程式版本。相同的建置應在多個容器中使用和啟動。

如果您為環境的每個階段重新建置,則需要生成一致的建置 ID 以在容器之間使用。在 next.config.js 中使用 generateBuildId 命令:

next.config.js
module.exports = {
  generateBuildId: async () => {
    // 這可以是任何內容,使用最新的 git 雜湊
    return process.env.GIT_HASH
  },
}

版本偏差

Next.js 將自動緩解大多數版本偏差的實例,並在檢測到時自動重新載入應用程式以檢索新資產。例如,如果 deploymentId 不匹配,頁面之間的轉換將執行硬導航而非使用預取值。

當應用程式重新載入時,如果未設計為在頁面導航之間持久化,則可能會丟失應用程式狀態。例如,使用 URL 狀態或本地儲存將在頁面重新整理後持久化狀態。然而,元件狀態如 useState 將在此類導航中丟失。

串流與 Suspense

Next.js 應用程式路由器在自行託管時支援串流回應。如果您使用 Nginx 或類似代理,則需要配置它以停用緩衝來啟用串流。

例如,您可以透過將 X-Accel-Buffering 設定為 no 來在 Nginx 中停用緩衝:

next.config.js
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。如果在執行 next build 時未使用動態 API,則此自動靜態最佳化是預設行為。

隨著部分預渲染趨於穩定,我們將透過部署適配器 API 提供支援。

after

after 在使用 next start 自行託管時完全支援。

停止伺服器時,請透過發送 SIGINTSIGTERM 信號並等待來確保優雅關機。這允許 Next.js 伺服器等待直到 after 內使用的待處理回呼函式或承諾完成。

On this page