此篇以 Next.js 11.0.1 版為主,內容僅供參考。
若要使用 Next.js SSG 額外輸出 static HTML,不打算把 SSG 的內容置於 Next.js 的 Node.js Server 上的話,光靠目前 package.json
的 scripts 指令是不夠的,我們需要使用 next export
。
修改 package.json
scripts
使用 create-next-app 建立好預設 Next 專案後,到 package.json
修改 scripts,在 "build":
的 next build
指令後方加上 && next export
"scripts": {
"dev": "next dev",
"build": "next build && next export",
"start": "next start",
"lint": "next lint"
},
原本指令會執行 next build
建構 prod 模式的 next application,現在另外加上&& next export
告訴 Next.js 專案把原本會產進 .next
的檔案也另外執行 next export
輸出來。
趕緊到 terminal 試試看,cd 進入 Next.js 專案後輸入
npm run build
來跑跑看結果。
Error: Image Optimization using Next.js’ default loader is not compatible with next export.
若 Next.js 開發環境和筆者一樣是 11.0.1
版,沒意外建好專案後 next build && next export
會看到此錯誤。
注: 此錯誤未來 Next.js 會(已)修正,在筆者撰寫的當下已有討論 Static Loader for next/image 與 PR Merged Rename next/image dangerously-unoptimized to custom and warn when applicable #26998,目前在 canary 版已修正但這裡還是先以當前正式版本為主。
Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
Possible solutions:
- Use `next start` to run a server, which includes the Image Optimization API.
- Use any provider which supports Image Optimization (like Vercel).
- Configure a third-party loader in `next.config.js`.
- Use the `loader` prop for `next/image`.
自從 Next.js 推出自己優化的 Image 元件後,使用 create-next-app 建立預設專案內會包含使用 Image 元件的程式碼,例如我們可以在預設的 /pages/index.js
找到:
import Image from "next/image";
//..略
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
預設 my-app
專案後下 next build && next export
會跳這錯誤,是因為 next Image 元件仰賴 Next Server 或第三方圖片處理的服務,此時我們在 local SSG 輸出自然會出問題。
好 OK,靜態頁面 SSG 不用 Image 元件沒關係吧,我們可以試著把 Image 元件改回原本的 HTML <img>
試試看吧,殊不知 Next 的 ESLint 馬上逼逼叫:
Do not use
<img>
. Use Image from 'next/image' instead.
...恩好喔
暫時解法有幾種,其中一種一樣使用 Next 的 Image 元件,然後在 next.config.js
多加上 images 的設定:
module.exports = {
images: {
loader: "imgix",
path: "/",
},
// 略...
};
重新執行另加上 && next export
的 npm run build
,這時應該就會成功了,此時可以看見多了一個 out
資料夾。
out
資料夾
out
資料夾存放著我們 SSG 輸出檔案,預設 HTML 有 index.html
和 404.html
以及其他存放在 _next
資料夾內的 .css
、.js
檔案。
既然是輸出完的 static file,試著把 out
內的 index.html
直接拖曳進瀏覽器看看。
恩?是有看到 Welcome to Next.js! 等文字,和原本預設 npm run dev
跑的網頁比起來差異是..樣式?
看起來就像是沒載入 css 樣式檔案?
檢查檔案路徑是否有跑掉
輸出的out
資料夾_next
內本來就有.css
、.js
檔案,既然瀏覽器呈現index.html
樣式沒呈現,我們打開 Chrome 開發者工具來找看看問題在哪:
選擇 Network 後再 reload 一次,發現 .css
、.js
檔案都 failed,沒有成功載入。
接著回到編輯器如 vscode 打開 out
資料夾內的 index.html
,會發現 code 是行數壓縮過單行的樣子,我們可以利用 vscode 文件格式化功能把這份 html 重新排版。
瀏覽排版後 index.html
,發現似乎哪裡怪怪的。
href
與 src
那邊引入 .css
、.js
的路徑怪怪的,要在 index.html
讀到對應 .css
、.js
,相對路徑應該是 ./_next/..
路徑開頭而不是 /_next/..
開頭
手動作法(不推薦)
這裡先試試手動把每個引入 .css
、.js
的路徑多加 .
看看。
原本的/_next/
開頭路徑改成 ./_next/
,存檔後再把index.html
直接拖曳進瀏覽器看看。
yes,看起來正常多了。
另外提醒這邊只是為了 debug 測試,實務上不可能每次都自己親手補上這個多出來的 .
。前幾篇的文章有提到,我們不太可能也不建議手動修改如 .next
之類的資料夾,理由是由指令產生出來的檔案或資料夾,下次重下指令又會重新產生和覆蓋。
同樣的道理,out
資料夾也是由指令產生出來的,現在修改 out
資料夾內檔案,下次重新 next export
又會把舊的檔案蓋掉,這樣就沒意義了。
修改 next.config.js
這個問題其實社群也有人討論過,按照 Next.js Issues 這篇討論:Generated static files html files have wrong assets paths,我們可以修改 next.config.js
,多加上一行 assetPrefix: ".",
module.exports = {
assetPrefix: ".",
images: {
loader: "imgix",
path: "/",
},
// 略...
};
存檔後重下指令 npm run build
跑 export
看看,試著把 out
內的 index.html
直接拖曳進瀏覽器看看。
這麼一來就正常了。
總結
這篇筆記算是隨手紀錄,不過還是抱怨一下 Next 9 版就推出 SSG,結果現在 11 版用 create-next-app 建立預設專案 next export
還是會報錯。所幸官方社群有討論也有 PR,未來開發者不一定會遇到相同問題。
之後若有 Next.js 筆記,就不會只著墨在 SSG 的功能上,應該會回歸 SSR 那邊相關功能的紀錄。
參考
Nextjs 官方文件: Static HTML Export
Custom loaders are not recognized by next export #21079
add Absolute Imports and Module path aliases #26797
Generated static files html files have wrong assets paths