多區域 (Multi-Zones)

範例

多區域 (Multi-Zones) 是一種微前端架構方法,將大型應用程式在單一網域下拆分為多個較小的 Next.js 應用程式,每個應用程式負責處理一組特定的路徑。當應用程式中存在與其他頁面無關的頁面集合時,這特別有用。透過將這些頁面移至獨立的區域(即獨立的應用程式),您可以減少每個應用程式的大小,從而改善建置時間並移除僅適用於特定區域的程式碼。

舉例來說,假設您有以下頁面集合需要拆分:

  • /blog/* 用於所有部落格文章
  • /dashboard/* 用於使用者登入儀表板後的所有頁面
  • /* 用於網站其他未被其他區域涵蓋的部分

透過多區域支援,您可以建立三個應用程式,它們都在同一個網域下運行,對使用者來說看起來相同,但您可以獨立開發和部署每個應用程式。

三個區域:A、B、C。展示不同區域間路由的硬導航 (hard navigation) 與同區域內路由的軟導航 (soft navigation)

在同一個區域內導航頁面時,會執行軟導航 (soft navigation),這種導航不需要重新載入頁面。例如,在此圖表中,從 / 導航至 /products 將會是軟導航。

從一個區域的頁面導航至另一個區域的頁面時(例如從 / 導航至 /dashboard),則會執行硬導航 (hard navigation),卸載當前頁面的資源並載入新頁面的資源。經常一起造訪的頁面應放在同一個區域中,以避免硬導航。

如何定義區域

定義新區域不需要特殊 API。一個區域就是一個普通的 Next.js 應用程式,您只需配置 basePath 以避免與其他區域的頁面和靜態檔案發生衝突。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  basePath: '/blog',
}

預設應用程式(負責處理所有未指定到更特定區域的路徑)不需要設定 basePath

Next.js 的資源(如 JavaScript 和 CSS)也會加上 basePath 前綴,確保它們不會與其他區域的資源衝突。這些資源將在每個區域的 /basePath/_next/... 路徑下提供。

如果區域提供的頁面沒有共同的路徑前綴(例如 /home/blog),您也可以設定 assetPrefix,確保該區域的所有 Next.js 資源都在唯一的路徑前綴下提供,而不需要為應用程式中的其他路由新增路徑前綴。

如何將請求路由到正確的區域

設定多區域後,您需要將路徑路由到正確的區域,因為它們由不同的應用程式提供服務。您可以使用任何 HTTP 代理來實現這一點,但也可以使用其中一個 Next.js 應用程式來路由整個網域的請求。

要使用 Next.js 應用程式路由到正確的區域,您可以使用 rewrites。對於由不同區域提供的每個路徑,您可以新增重寫規則,將該路徑發送到其他區域的網域。例如:

next.config.js
async rewrites() {
    return [
        {
            source: '/blog',
            destination: `${process.env.BLOG_DOMAIN}/blog`,
        },
        {
            source: '/blog/:path+',
            destination: `${process.env.BLOG_DOMAIN}/blog/:path+`,
        }
    ];
}

destination 應指向由該區域提供服務的 URL,包括協定和網域。這應指向該區域的生產網域,但也可用於在本地開發時將請求路由到 localhost

須知:URL 路徑應為區域獨有。例如,兩個區域都嘗試提供 /blog 會導致路由衝突。

區域間的連結

連結到不同區域的路徑時,應使用 a 標籤而非 Next.js 的 <Link> 元件。這是因為 Next.js 會嘗試預取並對 <Link> 元件中的任何相對路徑執行軟導航,這在跨區域時將無法運作。

共享程式碼

構成不同區域的 Next.js 應用程式可以存放在任何程式碼庫中。然而,將這些區域放在 monorepo 中通常更方便,以便更輕鬆地共享程式碼。對於存放在不同程式碼庫的區域,也可以使用公開或私有的 NPM 套件來共享程式碼。

由於不同區域的頁面可能在不同時間發布,功能標誌 (feature flags) 可用於在不同區域間統一啟用或停用功能。

對於 Vercel 上的 Next.js 應用程式,您可以使用 monorepo 來透過單次 git push 部署所有受影響的區域。

On this page