04 Next.js Pages Router 靜態輸出部署注意事項
Pages Router 靜態輸出專案的部署路徑、資產路徑與驗收提醒。
這份文件給接手 Chlitina-Refining、KindShare-Exocare 的人看。兩個站都是 Next.js Pages Router 靜態輸出,但路徑處理方式不一樣;排查時如果把 basePath、assetPrefix、build 後補寫混成同一件事,很容易越修越亂。
先說結論:這類專案最常壞的不是頁面 component,而是輸出後的公開路徑。首頁能開,不代表 _next chunk、圖片、SVG、字型也會在實際部署位置正常載入。驗收時一定要直接打 deployed URL,重新整理一次,再看 Network。
單一 repo 的 build 指令、env 名稱與檔案位置,仍以 repo README 為準。這份文件只整理跨專案共通的部署風險。
敏感資料交付提醒:本文件中的 05 或 05-environment-variables 指 05-environment-variables_環境變數與金鑰;該文件含 env value / secret 線索,僅做本地交付,不做雲端交付。
什麼時候看這份
如果你現在處理的是 build command、套件安裝或單一 repo 的 script,先看 repo README。如果問題和部署後的 URL、子目錄、資產 404、字型失效有關,才回到這份。
| 情境 | 先看哪裡 |
|---|---|
| 剛接手,不確定專案是不是 Pages Router 靜態輸出 | 先看下方 適用專案 |
| 某一站 build 失敗 | 該 repo README |
| deploy path、hosting、rollback 權限不清楚 | 04 Deployment Guide |
| env 值、env 開關或缺值症狀不清楚 | 05-environment-variables |
| reload 後停在舊 scroll 位置,首屏動畫、ScrollTrigger 或鎖滾動流程錯亂 | 09 的 scroll restoration 初始化防護文件 |
| 字型有載入,但 macOS / Retina 上看起來比 Figma 粗 | 09 的 Figma 字重與瀏覽器顯示差異文件 |
適用專案
| Project | 路徑策略 | 接手時先讀 |
|---|---|---|
Chlitina-Refining | output: "export",並依 env 切換 distDir / basePath | repo README -> 這份 -> 05 |
KindShare-Exocare | assetPrefix="./",再用 build 後腳本補寫 CSS 裡的字型路徑 | repo README -> 這份 -> 05 |
這兩個站都不是一般 SSR 專案。不要用「server 起來就好」的方式驗收,也不要只檢查 out/ 或輸出資料夾有沒有生成。靜態輸出真正要驗的是:這包檔案被放到正式位置後,瀏覽器能不能用正確路徑找到所有資產。
先判斷是哪一型問題
| 你看到的症狀 | 先懷疑 |
|---|---|
首頁能開,但 /_next/ chunk、CSS、圖片 404 | basePath、assetPrefix 或部署子目錄對不上 |
| 站內點擊正常,重新整理 deployed URL 後壞掉 | export 後路徑假設錯誤,或 hosting 子目錄沒有對齊 |
| 畫面大致正常,但字型退回 fallback font | CSS 裡的字型路徑沒有被補寫,或相對層級錯了 |
| 只改 env 開關,整包靜態檔的公開路徑跟著變 | 該 env 不只控制 UI,也影響輸出目錄或公開 URL 前綴 |
| 字型已載入,但和 Figma 粗細不同 | 這多半是瀏覽器與作業系統渲染差異,回 09 的字重文件 |
這裡有一個很實用的分界:404 是部署輸出問題;字看起來比較粗,不一定是部署壞掉。先用 Network 把字型檔是否真的載入確認清楚,會省很多時間。
共通規則
- 不要假設正式站一定掛在網域根目錄
/。 - 不要把 Pages Router 靜態輸出專案當成 SSR 專案排查。
- 新增站內連結時,優先交給 Next 路由或站內絕對路徑,不要手刻
./about、../about這類相對路徑。 - 新增圖片、SVG、字型等資產時,先確認它是由 Next 接管,還是 build 後仍要額外補寫。
- 驗收時要直接打 deployed URL 並重新整理,不要只靠站內點擊。
- 頁面如果有 GSAP ScrollTrigger、首屏動畫或鎖滾動流程,reload 驗收時也要確認瀏覽器沒有沿用舊 scroll 位置。
Chlitina-Refining
這個站最需要記的是:表單開關、輸出資料夾、公開 URL 前綴是綁在一起的。NEXT_PUBLIC_SHOW_FORM_SECTION 不只控制畫面上某個 section 顯示與否,也會影響 distDir 名稱;ENV_VAR=production 時,basePath 會跟著輸出資料夾名稱走。
所以排查時不要只問「這次表單要不要開」。也要一起確認這次 build 會輸出到哪個資料夾,以及部署後使用者實際打開的 URL 前綴是不是同一個。
新增路徑或資產時,避免在 JSX 裡手寫 ./foo.png、../foo.png、./about。圖片優先 import 後交給 next/image 或專案既有的包裝元件處理。這樣做不是為了風格一致而已,而是讓 basePath 有機會正確接管公開路徑。
常見誤判:
- 以為只是開關某個 section,實際上部署目錄也一起變了。
- 以為
basePath是補救相對路徑的工具,實際上它是公開 URL 前綴設定。 - 只在 local dev 驗證,沒有用正式子目錄 URL 打開 deployed 版本。
KindShare-Exocare
這個站的重點不同。正式 build 會靠 ENV_VAR=production 讓 assetPrefix="./" 生效;它可以處理 Next 自己產出的靜態資源,但不會自動修正 CSS 裡硬寫的字型路徑。
因此 replace-in-file --configFile=config.js 不是可有可無的整理腳本,而是正式 build 鏈的一部分。少了它,頁面可能看起來有出來,_next 也不一定壞,但字型會在非 root path 部署時退回 fallback font。這種問題很容易被誤判成設計稿、瀏覽器或字重設定差異。
驗收時除了看 out/ 是否生成,也要打開實際部署位置,確認 Network 裡的字型檔不是 404,畫面也沒有掉到 fallback font。
常見誤判:
- 以為有
output: "export"或assetPrefix,所有資源就都會自動相對化。 - 以為
replace-in-file可以刪,結果只在非 root path 部署時才發現字型壞掉。 - 只檢查輸出資料夾,沒有在實際部署 URL 驗字型與
_next資產。
最少驗收清單
- 直接輸入 deployed URL,重新整理後頁面仍然正常。
- Network 沒有
404的/_next/chunk、圖片、SVG、字型。 - 如果這次有改 env,確認 build 用的是哪組輸出目錄與公開 URL 前綴。
- 如果專案有 build 後補寫腳本,確認腳本真的跑完,輸出檔內容也已被改寫。
- 如果頁面有首屏動畫、ScrollTrigger 或鎖滾動流程,reload 後再看一次首屏狀態。
和其他文件怎麼搭配
- 要找 repo、README、閱讀順序:回 02 Project Inventory。
- 要查 deploy owner、hosting、rollback:回 04 Deployment Guide。
- 要查 env 值與缺值症狀:回
05-environment-variables。 - 要查 reload 後舊 scroll 位置、ScrollTrigger 初始化與鎖滾動防護:回 09 的 scroll restoration 初始化防護文件。
- 要查 Figma 字重與瀏覽器渲染差異:回 09 的 Figma 字重與瀏覽器顯示差異文件。
- 要做事故分流:回 15 Runbooks and Troubleshooting。