Next.js改了環境變數還是舊值:NEXT_PUBLIC在建置時固定

Next.js網站換了API網址,容器裡也能讀到新環境變數,瀏覽器卻繼續送往舊網址。先確認程式讀的是不是 NEXT_PUBLIC_ 開頭的值。這類變數在直接引用時,會於建置期間放進送給瀏覽器的JavaScript;只修改啟動環境,通常不會改掉已產生的客戶端程式。

本文聚焦一個部署問題:同一份建置產物移到另一個環境,為何公開設定還停在建置時的值。用BUILD_A建置、RUNTIME_B啟動的小頁面看結果,再分清何時要重新建置,何時應由伺服器提供可變設定。它不是清快取的通用指南,也不處理所有伺服器環境變數讀取方式。

先把變數讀取位置找出來

在Client Component或會進入瀏覽器bundle的程式裡,找到具體的 process.env.NEXT_PUBLIC_API_BASE。注意是直接寫明變數名稱。不要只看.env檔有沒有值;檔案存在、建置程序讀得到、客戶端程式採用的是哪個值,是三件需要對應的事。

'use client'

export default function ApiLabel() {
  const base =
    process.env.NEXT_PUBLIC_API_BASE
  return <p>{base}</p>
}

這段在建置時若讀到測試API網址,部署該bundle後,直接引用通常就已固定成那個字串。伺服器重啟時設另一個同名值,不會重新加工舊JavaScript。既然檔案內容沒改,換容器的啟動參數也不等於重新產生客戶端設定。

查程式時也看有沒有同名常數、fallback或其他設定來源。如果讀取失敗後自動退回測試網址,畫面就可能一直看似正常,實際請求卻去了錯環境。先把讀取位置與建置參數對上,再判斷是否另有快取或部署版本問題。

一個公開標籤就能看出固定時點

示例使用一個Client Component顯示公開標籤,不需要真API、金鑰或會員資料。建置前把 NEXT_PUBLIC_CASE_LABEL 設為BUILD_A,完成建置後,再把啟動環境的同一變數改為RUNTIME_B。

'use client'

export default function PublicValue() {
  return (
    <p>
      {process.env.NEXT_PUBLIC_CASE_LABEL}
    </p>
  )
}

在PowerShell裡可分兩階段操作。使用你的專案正常build與start腳本;下面例子顯示的是時點,不要求你更改整個部署方式。

$env:NEXT_PUBLIC_CASE_LABEL = 'BUILD_A'
npm run build

$env:NEXT_PUBLIC_CASE_LABEL = 'RUNTIME_B'
npm run start

本文示例建置成功後,啟動服務回傳的頁面仍包含BUILD_A,客戶端chunk也包含BUILD_A;啟動時改成的RUNTIME_B沒有出現在該頁回應。這是公開值已固定於建置產物的證據,不能因此推論所有環境變數在所有路由裡都固定。

需要新公開值時,重新建置再部署

若網站的設計本來就是每個環境各產生一份bundle,修法通常是把正確公開值放到建置階段,重新build,部署這份新產物。CI裡只在「啟動容器」步驟設定值,但「建置映像」步驟沒給它,仍可能得到錯的客戶端設定。

保存每次建置使用的公開參數與產物識別,再核對正式站實際提供的chunk。不要在記錄中保存私密變數值。建置成功後確認部署服務採用了新映像或新目錄,並且HTML引用的是本次產物;只看到CI綠燈,還不能證明訪客拿到新bundle。

如果使用Docker多階段建置,公開變數需在執行build的階段可用。放到最後執行階段的ENV只影響那個階段的程序環境,不會回頭改先前編譯出的檔案。用同一映像從測試環境推到正式環境時,尤其要先決定公開設定是否應跟映像一起固定。

想讓同一份產物跨環境,先換設定路徑

若同一份bundle必須在啟動後讀到不同API位置,就不要把可變值只放在NEXT_PUBLIC直接引用裡。可以由伺服器在執行時讀環境,透過受控端點回傳允許公開的設定;客戶端啟動後取得這份設定,再初始化需要它的程式。這是另一種架構,要處理取得失敗、載入順序與快取,不是改一個前綴就能完成。

回傳的設定只能包含可公開資料,不能把整個 process.env 序列化送出去。伺服器私密API金鑰應留在伺服器,由受控的後端請求使用。若某第三方服務提供的是可公開識別碼,仍需按該服務的權限及來源限制設計,不能只因為它叫「key」或加了NEXT_PUBLIC就自行判定安全。

伺服器讀取還要核對路由的渲染與快取行為。App Router動態渲染時可以讀取執行期環境變數;靜態預產生的內容則可能在建置時取得值。本文示例是公開直接引用,與伺服器動態讀值不同。修改為Runtime設定端點後,應另測它在目前Next.js版本下是否確實每次按預期讀值。

動態屬性名稱不是繞過建置的可靠方法

const key = 'NEXT_PUBLIC_API_BASE'
const value = process.env[key]

const env = process.env
const another = env.NEXT_PUBLIC_API_BASE

官方文件說明,這類間接讀取不會按直接引用的方式內嵌值。不要把它理解成瀏覽器會因此取得伺服器啟動環境;瀏覽器本來就沒有伺服器的完整process.env。把直接引用改成動態名稱,可能只是得到未定義或不符合預期的值,不能用來代替Runtime設定介面。

.env檔案與建置程序要對在一起

先確認檔案位於專案根目錄;如果原始碼放在src,環境檔仍放根目錄。也核對部署程序的工作目錄、NODE_ENV,以及是否已有外部環境變數覆蓋.env檔。不同.local檔有載入順序,不能看見某檔寫了新值就假設build最後採用的是它。

用無敏感的公開標籤先做診斷,通常比直接印出所有環境變數更容易看出問題。把本次建置的標籤與頁面或可辨識產物對上;排查結束後保留必要的版本資訊,移除臨時除錯輸出。不要把伺服器金鑰列在瀏覽器console或部署日誌裡。

建置已更新,才往瀏覽器與CDN查

若新產物確認包含正確公開值,訪客卻仍拿到舊結果,再看部署目錄、HTML引用的chunk、CDN回應及瀏覽器快取。先核實新檔案真的被服務提供,避免反覆清快取卻一直重新取得同一份舊bundle。如果有Service Worker,也要檢查它是否保存了舊頁或靜態檔。

確認網址之外,實際在瀏覽器Network裡核對請求目標、回應及必要的CORS設定。API位置正確不代表登入cookie、伺服器授權或業務功能已可用。若只是顯示的公開標籤改了,交付記錄也應只說設定已更新,不把它稱為整個網站部署成功。

若你遇到的是重新整理與站內切換不同,可接著讀 Next.js狀態讀取位置。外部圖片被元件拒絕則另看 remotePatterns與圖片網址;環境變數換對,不會自動放行未符合圖片來源規則的URL。

示例環境Next.js16.3.8,以webpack建置Client Component;BUILD_A建置、RUNTIME_B啟動比較HTTP正文與客戶端chunk,沒有連接真實API。你的渲染模式、部署與快取層需另外核對。

參考資料

原文鏈接:https://wntheme.com/next-public-env-build-time/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?