# Next.js 中 NEXT_PUBLIC_ 環境變數的 Build-time 陷阱 在使用 Next.js 進行開發時,許多人會直覺地認為,只要修改 `.env` 檔案或系統環境變數,前端程式碼就能在部署後即時反映最新設定。然而,當應用程式完成正式建置並部署至 Production 環境後,往往會發現一件令人困惑的事情──**以 `NEXT_PUBLIC_` 開頭的環境變數並不會隨環境變化而更新**。 這個行為在開發階段不易察覺,但一旦進入正式環境,便很容易成為實際踩到的坑。 --- ## 原因:NEXT_PUBLIC_ 會在建置階段被「寫死」 根據官方文件 [Bundling Environment Variables for the Browser](https://nextjs.org/docs/pages/guides/environment-variables#bundling-environment-variables-for-the-browser),Next.js 在建置(build)階段,會將所有以 `NEXT_PUBLIC_` 開頭的環境變數**直接內嵌(inline)到前端 bundle 中** 這代表: - 以 `NEXT_PUBLIC_` 開頭的變數,一旦完成建置,無論部署到哪個環境,這些值都不會再改變 ## 解決方法 如果確實有需求在前端取得**執行時(runtime)**的環境變數,一個可行且穩定的做法是: 1. 在 **Server Component**(例如 Root Layout)中讀取 `process.env` 2. 將變數透過 `<Script>` 注入到瀏覽器的 `window` 物件 3. 由前端程式碼在 runtime 讀取這些值 這樣即可避開 Next.js 在建置階段對 `NEXT_PUBLIC_` 的靜態替換行為。 ### Layout 範例 ```tsx import Script from "next/script"; export default async function RootLayout({ children, params, }: { children: React.ReactNode; params: Promise<{ lng: string }>; }) { const { lng } = await params; // 使用動態索引方式,避免在 build-time 被靜態替換 const runtimeUrl = process.env["NEXT_PUBLIC_APP_URL"]; return ( <html lang={lng}> <body> <Script id="env-script" strategy="beforeInteractive"> {`window.ENV = { NEXT_PUBLIC_APP_URL: ${JSON.stringify(runtimeUrl)} };`} </Script> {children} </body> </html> ); } ``` 這樣在前端任何的地方都可以透過 `window.ENV.NEXT_PUBLIC_APP_URL` 來取得動態變數 ### Hono Client 範例 ```TypeScript import { hc } from "hono/client"; import type { HonoAppRoute } from "@/app/api/[...route]/route"; const getBaseUrl = () => { if (typeof window !== "undefined" && (window as any).ENV?.NEXT_PUBLIC_APP_URL) { return (window as any).ENV.NEXT_PUBLIC_APP_URL; } return process.env.NEXT_PUBLIC_APP_URL || ""; }; const client = hc<HonoAppRoute>(`${getBaseUrl()}/`, { init: { credentials: "include", }, }); export { client as apiClient }; ```
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.