第 12 週 · 單元 5-1 · 換一套技術
同一份 PROJECT.md,換成 Next.js 重做吃貨站
第 4–5 週用 Flask 做的吃貨站,這兩週用 JavaScript 的 Next.js 再做一次。需求、資料表、驗收標準一字不改,你會發現:真正在工作的是六步建站法,技術只是工具。
W12Next.js同一份規格
本週結束時你會
今天的時間安排
| 0:00–0:25 | 觀念:Flask 與 Next.js 的對照;Server Component 是什麼 |
| 0:25–1:00 | 【跟著做】安裝 Node.js、建立專案、連上 Neon 開發分支 |
| 1:00–1:10 | 休息 |
| 1:10–1:50 | 功能 1【自己做】首頁排行榜,對答案 |
| 1:50–2:30 | 功能 2【自己做】店家頁,對答案;週誌 |
Flask 與 Next.js 對照
| 要做的事 | Flask(第 4–5 週) | Next.js(這兩週) |
|---|---|---|
| 語言 | Python | JavaScript |
| 一個網址對應一段程式 | @app.route("/shop/<int:id>") | 資料夾 app/shop/[id]/page.js |
| 頁面 | Jinja 範本 templates/shop.html | React 元件(同一個 page.js 裡) |
| 讀資料庫 | 路由函式裡查詢,再交給範本 | Server Component 直接 await query(...) |
| 表單送出 | @app.post 路由 | Server Action("use server") |
| SQL 參數 | ?(SQLite)/%s(Postgres) | $1、$2(Postgres) |
| 本機資料庫 | SQLite 檔案 | Neon 的開發分支(連線字串放 .env.local) |
| 部署 | Vercel(Python Function) | Vercel(Next.js 是 Vercel 自家的框架,零設定) |
Server Component:在伺服器上執行的 React 元件,可以直接查資料庫,查完再把 HTML 送給瀏覽器。資料庫連線字串永遠不會被送到使用者的瀏覽器。
準備環境【跟著做】
- 到 nodejs.org 下載 LTS 版安裝,裝好後重新開啟 Antigravity。
- Neon 開發分支:Vercel 的 Storage 頁面點進 Neon 管理後台 → Branches → 建立一個
dev分支。開發用 dev,正式網站用 main,測試資料不會弄髒正式資料。 - 在 dev 分支的連線資訊中複製連線字串,只貼到專案的
.env.local(下一步建立),不要貼到對話框。
提示詞 1 Antigravity
請在「程式設計三」資料夾建立 Next.js 專案 foodie-next:使用 create-next-app 15 版、JavaScript(不要 TypeScript)、App Router、不要 Tailwind。 接著: 1. 複製我的吃貨站 PROJECT.md 進來,把「技術」改成 Next.js 15、Postgres(pg 套件)、Pico.css 2. 安裝 pg;建立 lib/db.js,從環境變數 DATABASE_URL 建立連線池,提供 query(sql, params) 函式,SQL 參數用 $1、$2 3. 建立 db/schema.sql(Postgres 語法)與 db/seed.sql(從 Flask 版的 seed.sql 轉換),以及 npm run init-db 指令 4. 建立 .env.example 說明需要哪些環境變數;我會自己建立 .env.local 並貼上連線字串 完成後告訴我下一步要做什麼。不要讀取或顯示 .env.local 的內容。
應該看到你自己建立 .env.local 後,執行
npm run init-db 顯示「shops 12 筆、reviews 49 筆」。Flask 版 seed.sql 指定了店家 id,轉成 Postgres 後要把自動編號接到最大值之後,否則新增店家時會和既有的 id 衝突。參考解答在 seed.sql 最後用 setval 處理。若學生新增店家時出現 duplicate key 錯誤,就是漏了這一步,是很好的討論題材。
功能 1:首頁排行榜【自己做】
照吃貨站第 4 週的提示詞改寫:把「只修改 app.py 與 templates/」換成「只修改 app/page.js」,並說明要用 Server Component 直接查資料庫。
| 檢查 | 正確結果(與第 4 週相同) |
|---|---|
| 前五名 | 派森牛肉湯、函式炒鱔魚、布林豆花、字典虱目魚粥、迴圈碗粿 |
| 最後一名 | 模組肉燥飯,「尚無評分」 |
/?category=麵 | 函式炒鱔魚、縮排鍋燒意麵、變數擔仔麵 |
巡堂重點:Postgres 的平均數
Postgres 的 AVG() 回傳的是 numeric,ROUND(AVG(rating), 1) 在某些寫法下會出錯,要寫成 ROUND(AVG(rating)::numeric, 1)。另外 pg 套件會把 numeric 以文字形式交給 JavaScript(例如 "4.7"),顯示沒問題,但拿來計算前要先轉成數字。
功能 2:店家頁【自己做】
| 網址 | 正確結果 |
|---|---|
/shop/1 | ★ 4.7(6 則評論),第一則是小林 |
/shop/12 | 尚無評分 |
/shop/999、/shop/abc | 都是 404 頁面(不是錯誤畫面) |
Next.js 15 的寫法提醒:頁面收到的 params 與 searchParams 要先 await 才能使用。AI 有時會用舊版寫法,出現相關警告時,把警告訊息貼給它。