~/VibeHandbook
PDF ฟรี

บท 17 · 04

กรณีศึกษาที่ 4: เว็บไซต์คอนเทนต์ที่ไม่ต้องคอยดูแล

ไอเดีย

นักเขียนงานอดิเรกคนหนึ่งอยากเปลี่ยนโฟลเดอร์ Markdown บันทึกของเขา ซึ่งเป็นรีวิวร้านอาหารจากหลายปีที่เดินทางไปมา ให้กลายเป็นเว็บไซต์สาธารณะที่ค้นหาได้ โดยไม่ต้องมี CMS ให้ล็อกอิน และไม่มีค่าใช้จ่ายรายเดือน แค่เพิ่มบันทึกใหม่ push ขึ้นไป จบ

สเปก

A static site generated from a folder of Markdown files, one file
per review (title, city, rating, body in frontmatter). Build a
homepage that lists reviews newest-first, a page per review, and
client-side search by city or name. No database, no login, no
build step I have to run by hand. Pushing a new .md file should
publish it.

ข้อกำหนดที่ซ่อนอยู่คือประโยคสุดท้าย "No build step I have to run by hand" หมายความว่าสเปกนี้จริง ๆ แล้วพูดถึง เวิร์กโฟลว์ ไม่ใช่แค่ผลลัพธ์เท่านั้น และข้อกำหนดด้านเวิร์กโฟลว์เป็นสิ่งที่ AI มักข้ามไปเว้นแต่คุณจะระบุมันไว้ชัดเจน เพราะมันไม่ปรากฏให้เห็นในตัวแอปที่รันอยู่

สแต็กที่เลือกใช้

ตัวสร้างเว็บไซต์สแตติกที่อ่าน Markdown ตอน build time ดีพลอยไปยังโฮสต์ CDN ที่ build อัตโนมัติเมื่อมีการ push เข้า push เข้า repo โฮสต์ก็ build ใหม่ CDN ก็เสิร์ฟให้ ส่วนการค้นหาทำงานฝั่ง client บน index เล็ก ๆ ที่สร้างขึ้นตอน build จึงไม่มีเซิร์ฟเวอร์และไม่มีค่าใช้จ่ายจากการคิวรี ซึ่งเป็นข้อแลกเปลี่ยนที่ดีสำหรับรีวิวสักไม่กี่ร้อยรายการ และเป็นสิ่งที่เราตั้งใจระบุไว้ตั้งแต่แรก ไม่ใช่ค้นพบทีหลัง

เวิร์กโฟลว์ทั้งหมดเป็นลูกศรเดียว การ push จะทริกเกอร์การ build ที่เผยแพร่เว็บไซต์ ไม่มีอะไรทำงานตอน request time เลย นอกจากเบราว์เซอร์ของผู้เข้าชมเองที่กรอง index:

  add review.md          ┌──────────────────┐
  git push  ───────────▶ │  CDN HOST        │
                         │  build step:     │
                         │  read all *.md   │──▶ static HTML pages
                         │  emit search.json│──▶ tiny search index
                         └────────┬─────────┘
                                  │ serves
                                  ▼
                         ┌──────────────────┐
                         │  VISITOR BROWSER │  filters search.json
                         │  (client-side)   │  locally — no server
                         └──────────────────┘
        no database · no login · no build step run by hand

พรอมต์สำคัญ

เรากำหนดให้ AI ยึดตามรูปแบบข้อมูลก่อนเป็นอันดับแรก ก่อนที่จะแตะต้อง UI เลย:

Set up a static site that reads every .md file in /reviews. Each
file's frontmatter has title, city, rating (1-5), date. Parse all
of them at build time into a sorted list (newest first) and
generate: a homepage listing them, and one page per review at
/reviews/<slug>. Show me the data-loading code first, before any
styling.

"Before any styling" (ก่อนใส่สไตล์ใด ๆ) เป็นคันโยกที่จงใจดึงใช้ ถ้าคุณขอทุกอย่างพร้อมกันทีเดียว คุณจะได้หน้าเว็บที่สวยงามแต่เชื่อมกับข้อมูลที่ไว้ใจไม่ได้ แต่ถ้าขอชั้นข้อมูลก่อน คุณจะตรวจสอบรากฐานได้ก่อนที่พิกเซลแม้แต่ตัวเดียวจะมาดึงความสนใจไป จากนั้นจึงเป็นเรื่องการค้นหา ที่ตีกรอบให้ยังคงประหยัดต้นทุน:

Generate a search.json at build time with {title, city, slug} for
every review. On the homepage, add a search box that filters the
visible list client-side by matching city or title — no network
calls, just filter the already-loaded index. Keep it under 50
lines of JS.

อุปสรรค

การ build ผ่านฉลุยตอนรันในเครื่อง แต่เว็บไซต์ที่ดีพลอยไปแล้วขึ้น 404 ในทุกหน้ารีวิวแต่ละรายการ หน้าแรกทำงานปกติ แต่หน้ารีวิวรายตัวไม่ทำงาน เราวางอาการที่เกิดขึ้นและการตั้งค่าไปให้ดู แทนที่จะทฤษฎีเดาไปเอง:

Homepage works live, but /reviews/<slug> pages all 404 in
production while working in local dev. Here's my build output
directory listing and my host's deploy config: [pasted]. Why does
local dev serve these pages but production doesn't?

The AI traced it to the difference between dev-server routing (which
resolves paths dynamically) and static hosting (which serves only
files that physically exist). The build was generating the review
pages into the wrong output folder, so they never got uploaded —
dev had hidden the bug because its router faked the routes that
production couldn't.

เราชี้โฟลเดอร์ output ให้ตรงกับสิ่งที่โฮสต์ดีพลอยจริง หน้าเว็บก็ปรากฏขึ้นมา และเราได้เพิ่มอีกหนึ่งบรรทัดในเช็กลิสต์การเปิดตัว นั่นคือ คลิกลิงก์ลึกบนเว็บไซต์จริง ไม่ใช่แค่หน้าแรก บทเรียนที่กว้างกว่านั้นคือ "ใช้งานได้ตอนพัฒนา" กับ "ใช้งานได้ตอนดีพลอยจริง" เป็นข้อสรุปคนละเรื่องกัน และ static export คือจุดที่มันแยกทางกันชัดเจนที่สุด เซิร์ฟเวอร์สำหรับพัฒนามักจะยอมความกับเรื่อง routing ในแบบที่การโฮสต์ไฟล์จริงไม่มีวันยอม

การเปิดตัว

เรา push รีวิวจริงเข้าไปหนึ่งรายการ ดูโฮสต์ build ใหม่ แล้วโหลดลิงก์ลึกไปยังรีวิวนั้นบนโดเมนจริง ซึ่งเป็นกรณีเดียวกับที่ dev เคยโกหกเราไว้พอดี จากนั้นเราค้นหาชื่อเมืองของมันเพื่อยืนยันว่า index จับมันไว้แล้ว การเพิ่มรีวิว ถัดไป เป็นแค่คอมมิตหนึ่งบรรทัด ซึ่งคือประเด็นทั้งหมดของเรื่องนี้ การเปิดตัวไม่ใช่โมเมนต์เดียว แต่เป็นเวิร์กโฟลว์ที่ทำงานต่อไปได้เองโดยไม่ต้องมีเราคอยดูแล

อยากได้แบบออฟไลน์?

ดาวน์โหลดหนังสือทั้งเล่มเป็น PDF หรือ EPUB — ฟรี