- การมาถึงของฟีเจอร์ CSS สมัยใหม่อย่าง View Transitions API ทำให้ตอนนี้ไม่จำเป็นต้องใช้โครงสร้างแบบ SPA เพื่อให้ได้การเปลี่ยนหน้าที่ลื่นไหลอีกต่อไป
- เว็บไซต์แบบ SPA ส่วนใหญ่ในความเป็นจริงกลับไม่ได้มอบทั้งประสิทธิภาพหรือประสบการณ์ที่ลื่นไหลได้ดีอย่างที่คาดหวังไว้ และมักมีแนวโน้มที่โค้ด JavaScript ขนาดใหญ่จะทำให้ประสบการณ์ผู้ใช้แย่ลง
- หากใช้ การเปลี่ยนหน้าแบบเนทีฟ และ Speculation Rules บนเบราว์เซอร์ที่พัฒนาบน Chromium ก็สามารถสร้างการนำทางที่รวดเร็วและเป็นธรรมชาติได้โดยไม่ต้องพึ่ง JavaScript
- โครงสร้างที่ซับซ้อนของ SPA ขัดขวางการปรับแต่งประสิทธิภาพของเบราว์เซอร์ ดังนั้นสำหรับเว็บไซต์จริง สถาปัตยกรรมแบบ MPA ที่เน้น HTML และ CSS จึงทั้งเร็วกว่าและดูแลง่ายกว่า
- ต่อจากนี้ควรหลีกเลี่ยงการนำ SPA มาใช้โดยไม่จำเป็น และใช้ CSS สมัยใหม่กับความสามารถแบบเนทีฟเพื่อพัฒนาเว็บไซต์ที่มีประสิทธิภาพและดูแลรักษาได้ง่าย
บทนำ: จุดจบของ SPA และการมาถึงของ CSS สมัยใหม่
- การเปิดตัวฟีเจอร์ CSS รุ่นใหม่อย่าง View Transitions API ทำให้ข้อได้เปรียบหลักที่ SPA (Single Page Application) เคยมอบให้นั้นไม่จำเป็นอีกต่อไปแล้ว
- แม้หลายทีมพัฒนายังคงเลือกใช้เฟรมเวิร์ก SPA อย่าง React หรือ Vue แต่แกนหลักของการตัดสินใจนั้นไม่ใช่เรื่องประสิทธิภาพ หากเป็นความเข้าใจคลาดเคลื่อนเกี่ยวกับอินเทอร์แอ็กชันและประสบการณ์การนำทางที่ลื่นไหล
- ในความเป็นจริง แนวคิดที่เชื่อว่าการนำทางที่ลื่นไหลต้องอาศัย SPA นั้นเป็นมุมมองที่ล้าสมัยไปแล้ว
ภาพลวงตาและความจริงของ SPA
- SPA เคยเป็นหนทางเดียวในการสร้างการเปลี่ยนหน้าที่ดูเป็นธรรมชาติที่สุด แต่ตอนนี้ไม่เป็นเช่นนั้นอีกแล้ว
- SPA จำนวนมากมีปัญหาดังต่อไปนี้:
- มีเพียงเอฟเฟกต์เฟดของสถานะการโหลด แต่ขาดความลื่นไหลที่แท้จริงในการเปลี่ยนเนื้อหา
- ปัญหาการคืนค่าตำแหน่งเลื่อน และการจัดการโฟกัสที่ไม่สม่ำเสมอ
- การนำทางล่าช้าจากความหน่วงในการเรนเดอร์/ไฮเดรต
- layout shift และเนื้อหาที่เด้งขึ้นมา, skeleton loading เป็นต้น
- ความซับซ้อนที่ไม่จำเป็นและการใช้ JavaScript มากเกินไป ทั้งที่ผลลัพธ์ด้านประสิทธิภาพคุ้มค่าน้อย
- เฟรมเวิร์ก SPA ที่เป็นตัวแทนอย่าง Next.js, Gatsby, Nuxt ฯลฯ กำลังเพิ่มโค้ด JS จำนวนมหาศาลเพื่อเลียนแบบพฤติกรรมพื้นฐานแบบเนทีฟของเบราว์เซอร์
- ผลลัพธ์คือเกิดปัญหาต้องแลกความเป็นธรรมชาติแบบเนทีฟกับความช้าลง และยังทำให้ SEO แย่ลงด้วย
พัฒนาการของเว็บแพลตฟอร์มและบทบาทที่เปลี่ยนไปของ CSS
- เบราว์เซอร์สมัยใหม่ที่ใช้ Chromium (เช่น Chrome, Edge) รองรับการเปลี่ยนหน้าแบบเนทีฟและเชิงประกาศแล้ว
- ผ่าน View Transitions API สามารถสร้างแอนิเมชันที่ลื่นไหลระหว่างเอกสารหรือทั้งหน้าได้โดยไม่ต้องใช้ JavaScript
- ความสามารถหลักมีดังนี้:
- เอฟเฟกต์เฟด ระหว่างหน้า (ทำได้ด้วย CSS เพียง 3–4 บรรทัด)
- shared element animation เช่น การเปลี่ยนจากภาพขนาดย่อไปยังภาพรายละเอียดอย่างเป็นธรรมชาติ
- การคงอยู่ขององค์ประกอบถาวร เช่น header, navbar
- เนื่องจากเป็น URL จริงและการย้ายหน้าแบบจริง จึงเข้ากันได้สูงสุดทั้งกับ SEO, การแชร์ลิงก์, back/forward cache เป็นต้น
วิธีใช้ประโยชน์จากพลังร่วมกันของ CSS และ JS ให้เต็มที่
- หากจำเป็น ก็สามารถใช้ JS เรียก View Transition ด้วยตนเองสำหรับการเปลี่ยนภายในหน้าได้
- ตัวอย่างเช่น การสลับธีม, การสลับแท็บ, การเปลี่ยนโหมดมืด โดยใช้ JavaScript เพียงเล็กน้อย
Speculation Rules และการนำทางแบบแทบจะทันที
- Speculation Rules ช่วยให้เบราว์เซอร์ preload/prerender หน้าไว้ล่วงหน้า พร้อมคาดการณ์พฤติกรรมผู้ใช้ (เช่น การเอาเมาส์ไปวาง) เพื่อมอบการนำทางที่แทบจะทันที
- สามารถตั้งค่าแบบเชิงประกาศได้ผ่าน
<script type="speculationrules">
- เงื่อนไขคือ ต้องเป็นหน้าที่เบาและปรับแต่งมาอย่างดีจึงจะได้ผลด้านประสิทธิภาพสูงสุด แต่หากเป็นหน้าที่หนักก็เสี่ยงสิ้นเปลืองทรัพยากรโดยเปล่าประโยชน์
การเคารพความสามารถดั้งเดิมของเบราว์เซอร์และ bfcache
- bfcache (Back/Forward Cache) ช่วยให้เมื่อผู้ใช้กดย้อนกลับ/ไปข้างหน้า ระบบสามารถกู้คืนทั้งหน้าได้ทันทีในรูปแบบสแนปช็อต
- เงื่อนไขคือ ต้องเป็นสถาปัตยกรรมที่สะอาดบนพื้นฐานของ HTML และ CSS ล้วน และไม่สามารถใช้ได้กับโครงสร้างแบบ SPA ที่ดักจับการทำงานของ routing
- กล่าวโดยสรุป เบราว์เซอร์สมัยใหม่กำลังพัฒนาไปในทิศทางที่ตอบแทนเว็บไซต์ที่เรียบง่ายและแข็งแรง
เปรียบเทียบประสิทธิภาพระหว่าง SPA และ MPA
- SPA ทั่วไป (อ้างอิงจาก Next.js):
- ขนาด JS bundle: 1–3MB
- TTI (เวลาที่เริ่มใช้งานได้): 3.5–5 วินาที
- การเปลี่ยน route: ปลอม/จำลอง
- SEO: ซับซ้อน ดูแลยาก
- พฤติกรรมการเลื่อน/anchor: ไม่เสถียร
- MPA สมัยใหม่ (ใช้ CSS transitions และ Speculation Rules):
- JS bundle: 0KB (มีเฉพาะส่วนเสริมตามต้องการ)
- TTI: ราว 1 วินาทีหรือน้อยกว่า
- การเปลี่ยน route: พฤติกรรมเนทีฟจริง
- SEO: ง่ายมาก
- smart scroll, focus, history: เป็นพฤติกรรมพื้นฐานของเบราว์เซอร์และรองรับได้สมบูรณ์
การแยกแยะระหว่างเว็บไซต์กับแอป และความจำเป็นในการทบทวนความเหมาะสม
- เว็บไซต์ส่วนใหญ่ไม่ได้เป็น "แอป" จริง ๆ และไม่ได้ต้องการสถานะที่แชร์ร่วมกัน, client-side routing, หรืออินเทอร์แอ็กชันที่ซับซ้อน
- สำหรับหน้า marketing, พอร์ทัลเอกสาร, อีคอมเมิร์ซ, บล็อก ฯลฯ โครงสร้างที่เน้น HTML, โหลดเร็ว, และเรียบง่าย เหมาะสมกว่า
- หากนำสแตก SPA มาใช้กับทุกโปรเจกต์ ก็อาจก่อให้เกิดความซับซ้อนเกินจำเป็นและประสิทธิภาพที่ลดลง
- ความต้องการให้ "ดูเหมือนแอป"
- นำเฟรมเวิร์กมาใช้
- เพิ่ม client-side routing และความซับซ้อน
- ประสิทธิภาพลดลงและต้องทำ optimization เพิ่ม
- สุดท้ายก็ยังช้ากว่าโครงสร้างลิงก์แบบเนทีฟ + CSS animation อยู่ดี
บทสรุปและข้อเสนอแนะ
- SPA เป็นเหมือนทางแก้ชั่วคราวต่อข้อจำกัดของแพลตฟอร์มในอดีต แต่ตอนนี้ข้อจำกัดเหล่านั้นไม่มีอยู่อีกแล้ว
- ตอนนี้เราสามารถใช้งานความสามารถแบบเนทีฟต่อไปนี้ได้อย่างจริงจัง:
- การเปลี่ยนจริงระหว่างหน้า
- การ prerender ล่วงหน้าแบบแทบจะทันทีผ่าน Speculation Rules
- โครงสร้างที่ทนทานต่อการลดทอนความสามารถแบบค่อยเป็นค่อยไป
- มาร์กอัปที่สะอาด โหลดเร็ว และใช้ URL จริง
- โครงสร้างที่ได้รับประโยชน์จากแพลตฟอร์มได้สูงสุด
- หากยังยึดติดกับ SPA เพียงเพราะเหตุผลเรื่อง "ความลื่นไหล" ก็จะต้องจ่ายต้นทุนทั้งในด้านความซับซ้อน ประสิทธิภาพ และการดูแลรักษา
- ด้วยการใช้server rendering, หน้าจริง, แอนิเมชันบนพื้นฐานของ CSS, การ preload อย่างตั้งใจ, และ JS ให้น้อยที่สุด ก็สามารถสร้างเว็บไซต์ที่เร็วและน่าใช้งานเหมาะกับยุคปัจจุบันได้
- ด้วยเทคโนโลยีในปี 2025 เราควรมุ่งสู่ประสบการณ์เว็บที่เร็วขึ้น เรียบง่ายขึ้น และเป็นมิตรกับทุกคน
10 ความคิดเห็น
ตั้งแต่แรกแล้ว หากจะพิจารณาใช้ SPA ด้วยเหตุผลแค่ว่า "ลื่นไหล" ผมก็คงยอมไม่เอาความลื่นไหลนั้นแล้วเขียนเป็น MPA ไปอยู่ดี เลยไม่ค่อยรู้สึกเห็นด้วยเท่าไรครับ...
จุดที่น่าเสียดายของบทความนี้
ตีความเป้าหมายที่แท้จริงของ SPA แคบเกินไป
View Transitions API นั้นยอดเยี่ยมมากจริง ๆ แต่เพียงแค่นั้นยังไม่ได้แปลว่า SPA จะไม่จำเป็นอีกต่อไป
มองทุกเว็บไซต์ด้วยเกณฑ์เดียวกัน
เว็บไซต์การตลาด ≠ แดชบอร์ด ≠ แอปคอมเมิร์ซ ≠ เครื่องมือทำงานร่วมกันแบบเรียลไทม์
ทั้งหมดมีความต้องการเชิงโครงสร้างที่แตกต่างกัน
ในการใช้งานจริง SPA + SSR + MPA กำลังอยู่ร่วมกัน
ไฮบริดเฟรมเวิร์กอย่าง Next.js แสดงให้เห็นเรื่องนี้ได้อย่างชัดเจน
สินทรัพย์แบบสแตติกใช้ SSG, แดชบอร์ดหลังล็อกอินใช้ CSR/SPA, ส่วนการรองรับเสิร์ชเอนจินใช้ SSR เป็นต้น จึงจำเป็นต้องมีการผสมผสานอย่างยืดหยุ่น
ผมคิดว่า SPA ไม่ได้เป็นเพียงเรื่องของประสบการณ์ผู้ใช้เท่านั้น แต่ใกล้เคียงกับการเป็นผลลัพธ์ของการปรับปรุงโครงสร้างมากกว่า
สำหรับหน้าที่ไม่จำเป็นต้องใช้ SPA, MPA + โมเดิร์น CSS อาจเป็นตัวเลือกที่ดีได้ แต่ในมุมของโครงสร้าง สถานะ ความสามารถในการขยาย และการบำรุงรักษา SPA ก็ยังคงจำเป็นอยู่ โมเดิร์น CSS อาจ "เสริม" SPA ได้ แต่ผมไม่คิดว่าจะ "แทนที่" ได้
ในบรรดากรณีที่คุณยกมา มีเพียงเครื่องมือทำงานร่วมกันแบบเรียลไทม์เท่านั้นที่ไม่สามารถแทนที่ SPA ด้วยสิ่งอย่าง View Transitions ได้ แต่เว็บไซต์ส่วนใหญ่ไม่ได้เป็นเครื่องมือทำงานร่วมกันแบบเรียลไทม์ เว็บไซต์การตลาด แดชบอร์ด และแอปคอมเมิร์ซ ล้วนสามารถสร้างได้โดยตัดเฟรมเวิร์ก SPA ออก และยึดเงื่อนไขอย่าง server rendering, หน้าแบบเต็ม, แอนิเมชันที่อิง CSS, การ preload อย่างตั้งใจ และการใช้ JS ให้น้อยที่สุด ฝั่ง Rails ก็มี Hotwire ที่มุ่งไปในทางนี้ และก็มีตัวอย่างใช้งานจริงในโปรดักชันอย่าง Basecamp และ HEY ด้วย เรื่องการจัดการ state? ถ้าไม่ใช่สิ่งอย่างเครื่องมือทำงานร่วมกันแบบเรียลไทม์ ก็ใช้วิธีฝั่งเซิร์ฟเวอร์อย่าง URL parameters หรือ server session หรือจะใช้ local storage ก็เพียงพอแล้ว แน่นอนว่าก็มีกรณีที่นำ SPA มาใช้เพราะการเปลี่ยนหน้าอยู่จริง (เช่นเว็บทางการของ AGF ที่แค่ Astro ก็น่าจะพอ แต่ก็นำ React มาใช้) และก็ปฏิเสธไม่ได้ว่าหนึ่งในข้อดีตัวแทนของ SPA ที่ถูกพูดถึงบ่อยมากก็คือการเปลี่ยนหน้านี่เอง
เป็นความจริงที่เฟรมเวิร์ก SPA ในปัจจุบันและเทรนด์ฟรอนต์เอนด์ที่อิงกับมัน จำเป็นต้องระวังการกลายเป็นสิ่งที่ไม่เป็นมาตรฐานอยู่เสมอ อีกทั้งยังเอื้อต่อการทำเกินความจำเป็นและการใช้ทรัพยากรโดยไม่จำเป็นได้ง่ายด้วย แต่…
ผมคิดว่ามีการมองแนวคิดของ SPA แคบเกินไป และยิ่งไปกว่านั้นก็อดสงสัยไม่ได้ว่าเข้าใจกันจริงหรือไม่ว่าเฟรมเวิร์ก SPA ส่งผลต่อภาพรวมของการพัฒนาอย่างไร
การบอกว่าแค่มี CSS กับ View Transition API อย่างเดียวก็ทำได้หมดนั้น ถ้าพูดอีกแบบก็คือฟังก์ชันทั้งหมดที่ไม่เกี่ยวกับสิ่งนั้น รวมถึงพาราไดม์ที่ใช้เพื่อทำให้มันเกิดขึ้น ล้วนไม่มีความหมายไปทั้งหมด ซึ่งผมคิดว่าเป็นมุมมองที่หยิ่งผยองเกินไปหน่อย
นี่เป็นอีกประเด็นหนึ่งที่แยกจากเรื่องการทำเกินความจำเป็นเวลาใช้ React สร้างเว็บไซต์ที่มีระดับแค่แทนโบรชัวร์ได้
ผมเห็นด้วยว่าหลายโปรเจ็กต์ขนาดเล็กส่วนใหญ่ไม่จำเป็นต้องใช้เฟรมเวิร์ก SPA แต่สำหรับบริการที่มีข้อกำหนดเป็นอินเทอร์แอ็กชันที่ซับซ้อน ประสบการณ์ผู้ใช้ที่ต่อเนื่อง ตลอดจนการบำรุงรักษาและการปรับปรุงอย่างต่อเนื่องตามนั้น ผมไม่คิดว่าจะเป็นเช่นนั้น แม้ CSS จะพัฒนาไปมากแล้วก็ตาม
พูดกันตามตรง มันดูเหมือนกับการพูดถึง Rust หรือ Haskell ทั้งที่ยังไม่เคยลองจับเลย แล้วบอกว่า ‘ไม่ต้องมีพวกนั้น ทุกวันนี้ C++ ก็ทำได้หมดแล้ว’
อืม ก็ไม่แน่ใจนะครับ วัตถุประสงค์ของการใช้เฟรมเวิร์กแบบ SPA น่าจะไม่ใช่เพื่อการเปลี่ยนผ่านที่ลื่นไหลมากกว่า แต่เพื่อรองรับปฏิสัมพันธ์ที่ซับซ้อนกับผู้ใช้ไม่ใช่หรือครับ?
มีกรณีที่นำเฟรมเวิร์ก SPA มาใช้เพียงเพื่อให้ได้ปฏิสัมพันธ์ที่ลื่นไหลอยู่จริง แต่เว็บไซต์จำนวนมากที่ใช้ SPA ไม่ได้ต้องการปฏิสัมพันธ์ที่ซับซ้อนขนาดนั้น
เห็นด้วยอย่างมาก
ยกตัวอย่างชัดๆ คือ React เองก็เป็นเหมือน Spring ของฝั่งฟรอนต์เอนด์
มันทั้งหนักและซับซ้อน ดูเหมือนจะทำให้งานสะดวกขึ้น แต่จริงๆ แล้วคือการตั้งกระบวนการที่ซับซ้อนกว่าเดิมขึ้นมาเพื่อทำงานเบาๆ แล้วค่อยไปทำให้กระบวนการที่จงใจทำให้ซับซ้อนนั้นใช้งานสะดวกขึ้น เป็นความสะดวกแบบประหลาดๆ
เห็นด้วยครับ ถ้าไม่ใช่เว็บแอปที่ซับซ้อนแบบ Google Docs ผมมองว่า Howired ที่ฝั่ง Rails ทำมาก็เพียงพอแล้ว และถ้าเป็นหน้าสแตติก Astro ก็เพียงพอเช่นกันครับ
ความเห็นจาก Hacker News
SPA มีความหมายเมื่อผู้ใช้ใช้เวลากับแอปเดียวเป็นเซสชันยาว ๆ กล่าวคือโหลด bundle ก้อนใหญ่ครั้งเดียว แล้วหลังจากนั้นก็ใช้งานแอปต่อได้ด้วยคำขอเครือข่ายเล็ก ๆ เท่านั้น ส่วนเอฟเฟกต์เปลี่ยนหน้าที่ลื่นไหลเป็นแค่ของแถม และไม่ใช่ปัญหาหลักที่ SPA แก้ ผมคิดว่าการอ้างว่า client-side routing มีไว้เพื่อการเปลี่ยนหน้าเป็นการเข้าใจจุดประสงค์ของ SPA ผิดไป ถ้าคุณเข้าใจ SPA แบบผิด ๆ แบบนั้นและใช้มันแก้ปัญหาที่ไม่ถูกต้อง บทความนี้ก็ถูก 100% แต่เดิมที SPA เกิดขึ้นมาเพื่อแอปที่ซับซ้อนในยุค jQuery เป็นก้อนโค้ด jQuery ขนาดใหญ่ที่แต่ละ div ทำงานเหมือนมินิแอป และซิงก์กันผ่านคำขอเครือข่ายเล็ก ๆ จำนวนมาก ในยุคเบราว์เซอร์เก่าและอินเทอร์เน็ตช้า วิธีนี้ทำให้ใช้งานได้อย่างมีประสิทธิภาพโดยไม่ต้องโหลดโค้ดทั้งหมดใหม่ทุกครั้ง หลังจากนั้นเฟรมเวิร์กอย่าง React ก็พัฒนาต่อมาและทำให้การสร้างแอปแบบมีโครงสร้างง่ายขึ้น และข้อดีหลักของ SPA ก็คือการแคช bundle ก้อนใหญ่ครั้งเดียวสำหรับผู้ใช้ที่มีเซสชันยาว แล้วลดทราฟฟิกเครือข่ายหลังจากนั้นให้เหลือน้อยที่สุด
(คำพูดที่อ้างจากความเห็นข้างบน: "...if you shared that misunderstanding of SPAs and used them to solve the wrong problem, this article is 100% correct.") เห็นด้วยสุด ๆ ผู้เขียนเป็นที่ปรึกษา SEO เลยดูเหมือนจะโฟกัสแต่ฝั่งเว็บการตลาด แอปจริง ๆ (ที่ไม่ใช่เว็บการตลาด) ได้ประโยชน์จาก SPA มาก ลองนึกภาพว่าจะทำ Google Maps โดยไม่มี SPA ดูสิ แค่เพิ่มแอนิเมชันเปลี่ยนหน้าก็ทำให้ UX แย่ลงอย่างหนักแล้ว
มีคำพูดว่า “ก็แค่กอง jQuery spaghetti” แต่จริง ๆ แล้วผมเคยใช้แพตเทิร์นการออกแบบ JS ยุคแรก ๆ อย่าง IIFE เพื่อจัดโครงสร้างโค้ด ทำ lazy loading ของโมดูล และทำ code obfuscation ด้วย และจากประสบการณ์ของผม AngularJS คือความพยายามจัดโครงสร้างฝั่งฟรอนต์เอนด์ที่ใหญ่ที่สุด และเหตุผลที่มันดึงดูดนักพัฒนา Java ก็คือเรื่อง modularity, DI, และความง่ายในการทดสอบ ตอนแรกตอนทำแอปด้วย Backbone ผมคิดว่าฟีเจอร์ส่วนใหญ่อยู่ฝั่งแบ็กเอนด์เลยไม่ได้ใส่ใจการทดสอบมากนัก แต่พอมา rebuild ด้วย AngularJS ก็มีการทดสอบฝั่งฟรอนต์เอนด์มากขึ้นมาก แน่นอนว่าทุกวันนี้ผมก็เริ่มต่อต้านความยืดยาว ความซับซ้อน และความอ้อมค้อมของโค้ด Angular ยุคใหม่หรือโค้ด Java
ผมคิดว่าเครือข่ายช้าและสภาพแวดล้อมที่มีการแคชอย่างจริงจังเป็นหนึ่งในเหตุผลที่หนักแน่นที่สุดที่ต้องใช้ SPA (โดยเฉพาะกับแอปมากกว่าเว็บไซต์) ถ้ามีการเชื่อมต่อที่พอใช้ได้ตอนแรกแล้วดาวน์โหลดฟรอนต์เอนด์ทั้งหมดมาทีเดียวพร้อมแคชไว้ หลังจากนั้นการใช้งานก็ทำได้ด้วยแบนด์วิดท์ขั้นต่ำ
ถ้าคุณทำงานในที่ที่ใช้ CI/CD pipeline สมัยใหม่ การ deploy วันละหลายครั้งมีโอกาสสูงมากที่ JS bundle ก้อนใหญ่นั้นจะถูก build ใหม่และ cache จะถูก invalidated ทุกครั้ง HTTP2 ก็เป็นค่าเริ่มต้นในเบราว์เซอร์มา 10 ปีแล้ว และด้วย multiplexing ก็ไม่มีเหตุผลต้องรวม JS เป็นก้อนใหญ่อีกต่อไป แนวทาง SPA ที่สร้าง bundle ใหญ่ ๆ เลยไม่ได้ใช้ประโยชน์จากความสามารถสมัยใหม่ของเบราว์เซอร์และเซิร์ฟเวอร์
ผมสงสัยว่ามีกรณีจริงมากแค่ไหนที่คำขอเครือข่ายหลังโหลดครั้งแรกเล็กลงอย่างมีนัยสำคัญ SPA ส่วนใหญ่ที่ผมเจอหลังโหลดเสร็จก็ยังมีการเรียกข้อมูลก้อนใหญ่อยู่ดี และช้ากว่าการส่ง HTML มาเลยมาก ข้ออ้างว่า JSON บีบอัดได้ดีกว่า HTML แบบอัศจรรย์ก็ไม่จริง HTML เองก็บีบอัดได้ดีพอ ๆ กัน ในทางปฏิบัติแล้วเหตุผลเรื่องเครือข่ายที่อ้างว่า SPA ดีกว่าจึงแทบจะเป็นแค่โฆษณาชวนเชื่อหรือความเชื่อผิด ๆ
ผมคิดว่าคุณค่าของ SPA ไม่ได้มีแค่การเปลี่ยนหน้าที่ลื่นไหล แต่ยังรวมถึงการจัดการเส้นทางผู้ใช้เกือบทั้งหมดฝั่งไคลเอนต์จนแทบไม่ต้องสนใจเซิร์ฟเวอร์เลยด้วย ตัวอย่างเช่นในปี 2025 ผมยังหงุดหงิดที่ร้านค้าออนไลน์ส่วนใหญ่ยังต้อง reload ทั้งหน้าทุกครั้งที่เปลี่ยนฟิลเตอร์หรือเข้าหมวดหมู่ แล้วก็ต้องดึงข้อมูลใหม่ ถ้าผู้ใช้สลับหมวดหมู่ไปมาและยิงคำขอหลายครั้ง UX จะดีขึ้นมากถ้าดาวน์โหลดแค็ตตาล็อกทั้งหมดมาที่ไคลเอนต์ครั้งเดียว แล้วกรองต่อได้โดยไม่ต้องสื่อสารกับเซิร์ฟเวอร์ แน่นอนว่ามีคนจะแย้งว่าข้อมูลเยอะ แต่หมวดหมู่ของร้านค้าส่วนใหญ่มีขนาดแค่ไม่กี่ KB เล็กกว่ารูปสินค้า 1 รูปเสียอีก ผมสร้างแอปแบบนี้มาตั้งแต่ปี 2005 และยังไม่เข้าใจว่าทำไม UX แบบนี้ถึงไม่แพร่หลายกว่านี้
สำหรับผม ปัญหาที่น่ารำคาญที่สุดของการต้อง reload เต็มหน้าไม่ใช่ขนาดข้อมูล แต่เป็นประสิทธิภาพของเว็บไซต์ ข้อมูลจริงมีแค่ไม่กี่ KB แต่ตัวหน้าเว็บกลับดาวน์โหลด 100MB และกิน RAM ของเบราว์เซอร์ 1GB ตัวอย่างเช่น Hacker News ใช้การ reload ในการนำทางเป็นส่วนใหญ่และยังทำงานได้ดีบนโน้ตบุ๊กเก่า ๆ ขณะที่ SPA อย่าง DoorDash ใช้เวลา 30 วินาทีบนเครื่องเดียวกัน และกว่าจะสั่งอาหารได้จริงก็เกิน 3 นาที ต้องรอประมาณ 2.5 นาทีกว่าอินเทอร์เฟซจะขึ้น และเกือบทั้งหมดนั้นก็ไม่ใช่ full reload ด้วยซ้ำ
เครื่องมืออย่าง HTMX ช่วยแก้ปัญหาพวกนี้ได้มาก ผมคิดว่าแนวทาง SPA ลงท้ายด้วยการสร้างแอป 2 ตัวแยกกันคือฟรอนต์เอนด์กับแบ็กเอนด์ ผมรู้สึกว่าทำส่วนใหญ่ไว้ฝั่งเซิร์ฟเวอร์ แล้วเพิ่มแค่เอฟเฟกต์โต้ตอบง่าย ๆ ฝั่งไคลเอนต์ เช่น show/hide, expand/collapse, เอฟเฟกต์ต่าง ๆ จะดีกว่า แน่นอนว่า SPA ก็ยังมีที่ที่มันมีประโยชน์
มีประสบการณ์คล้ายกันคือโปรเจกต์ส่วนตัวบางตัวของผมโฮสต์บน static web server แทนที่จะ render หน้าแยกกันหลายหมื่นหน้า ผมใช้ไฟล์ JSON ไฟล์เดียวแล้วให้ SPA render ฝั่งไคลเอนต์ และก็ใช้ Github Pages ด้วย ช่วงหลังผมกำลังทดลองโครงสร้างที่ใช้ sqlite database เวอร์ชัน wasm เพื่อดึงเฉพาะหน้าที่ต้องใช้ผ่าน HTTP Range Requests ได้ด้วย Full Text Search ของ sqlite ก็ใช้ได้ แต่กับการค้นหาสั้น ๆ ยังน่าเสียดายเพราะต้องดึงทั้งตารางมา อาจจะดีกว่าถ้าดาวน์โหลด DB ทั้งหมดมาแล้วสร้างตาราง FTS ในเครื่อง
ก็มีตัวอย่างโต้แย้งเหมือนกัน เช่น เวลา Shift-click หมวดหมู่ “sci-fi” เพื่อเปิดแท็บใหม่ MPA ทำได้แทบไม่ต้องออกแรง แต่ SPA ต้องจัดการเรื่องนี้เพิ่มเองจึงยุ่งยาก ถ้าไม่มีลิงก์หมวดหมู่และเข้าผ่าน Select Box อย่างเดียว UX ก็ไม่ดี
โดยทั่วไปแล้วบริษัทต่าง ๆ ไม่อยากให้ผู้ใช้ดาวน์โหลดทั้งแค็ตตาล็อก เพราะคู่แข่งจะวิเคราะห์ได้ง่าย อีกอย่างเช่นกรณีขายหนังสือมีเป็นแสนเล่ม การย้ายทั้งหมดมาทีเดียวก็ไม่มีประสิทธิภาพทั้งในมุม UX และในแง่แบนด์วิดท์/หน่วยความจำ
เป้าหมายของ SPA ไม่ใช่การเปลี่ยนหน้าเลย และแทบไม่มี SPA ไหนที่ทำ page transition ดีจริง ๆ เช่นใน Next.js ด้วยวิธีโหลดแบบ route-level ทำให้การทำ page transition แทบเป็นไปไม่ได้เลย ผมเคยเพิ่มฟีเจอร์ page transition ที่เหมาะสมให้ Next.js จริง ๆ และมันเป็นฝันร้ายชัด ๆ ข้อดีที่ชัดเจนของ SPA สำหรับผมมีสองอย่าง หนึ่ง แอปส่วนใหญ่ต้องการความ interactive ระดับหนึ่งอยู่แล้ว (HTML/CSS อย่างเดียวไม่พอ) และการผสม React กับ HTML ล้วนเป็นเรื่องทรมานมาก โดยเฉพาะเมื่อจำเป็นต้องจัดการ global state สอง ถ้าโหลดโครงสร้างทั้งหน้าล่วงหน้าไว้แล้ว การโหลดข้อมูลภายหลังจะเร็วขึ้น และการมีปฏิกิริยาทันทีหลังคลิกพร้อมแสดง loading screen ก็ให้ UX ที่ดีกว่ารอ 500ms กว่าจะตอบสนอง (แม้ถ้าน้อยกว่า 100ms จะเป็นอีกเรื่อง) เพราะไม่ต้องวาดทั้งหน้าใหม่ ประสิทธิภาพฟรอนต์เอนด์จึงเป็นสิ่งที่ HTML ล้วนตามไม่ทัน แม้จะมีตัวอย่างอย่าง Basecamp ที่สร้างเว็บแอปซับซ้อนโดยไม่ใช้ SPA ได้ดี แต่แค่คลิกเล่น 30 วินาทีก็เห็นแล้วว่าประสิทธิภาพยังตาม SPA ไม่ทัน ผมเองก็อยากให้เว็บทำงานแบบที่เว็บควรเป็น แต่ความซับซ้อนที่ Next.js และ SPA เพิ่มเข้ามา แม้จะทำให้แอปเร็วและตอบสนองดีขึ้น ก็ทำให้พัฒนายากขึ้นและสร้าง bundle ใหญ่ด้วย ถึงอย่างนั้นผมก็ยังคิดว่า HTML อย่างเดียวยังตามประสิทธิภาพของ SPA ไม่ทัน
ไม่รู้ว่าที่ปรึกษา SEO คนเขียนบทความนี้อยู่จักรวาลไหน การยก Next กับ Nuxt มาเป็นตัวอย่างเฟรมเวิร์กที่ตรงข้ามกับ SPA นั้นผิดเต็ม ๆ 1. Next ครองตลาดในสหรัฐ/ตะวันตกแทบหมดแล้ว เวลาใครพูดถึงแอป React ใหม่ ๆ ส่วนใหญ่ก็หมายถึง Next ฝั่ง Vue เอง Nuxt ก็แทบเป็นมาตรฐาน และ Nuxt = Next ของโลก Vue นั่นหมายความว่าคนจำนวนมากกำลังเลือก Next และกลยุทธ์แบบ MPA โดยไม่รู้ตัว ผมกลับคิดว่าลูกตุ้มเหวี่ยงไปทาง MPA มากเกินไปแล้ว จึงควรแนะนำให้คนลอง SPA มากกว่า 8 ปีที่ผ่านมาเป็นยุคคลั่ง MPA และตอนนี้แม้แต่ Facebook ก็แนะนำ Next ในเอกสารแทน Create React App อย่างเป็นทางการแล้ว 2. คำบ่นเรื่องความซับซ้อนของ Next จริง ๆ คือคำบ่นต่อความยากของกลยุทธ์ MPA สมัยใหม่ ส่วนฝั่ง SPA แทบไม่มีอะไรเปลี่ยนมาเกือบ 10 ปี 3. การพัฒนา MPA ยากกว่า SPA มาก เพราะต้องรักษาเส้นแบ่งระหว่างเซิร์ฟเวอร์กับไคลเอนต์ให้เข้มงวดกว่า 4. ถ้าอยากโหลดข้อมูลแบบ MPA ใน SPA ก็เป็นทางเลือกของนักพัฒนาเอง และต้องยอมรับข้อดีข้อเสียเอง จะ preload ข้อมูลไว้ล่วงหน้าเพื่อให้การนำทางใน SPA เกิดขึ้นทันทีเลยก็ได้ 5. นอกจาก main frontend ที่ SEO สำคัญจริง ๆ ยังมี dashboard ภายในหรือแอปอีกจำนวนมาก React developer ก็มักอยู่ในงานพวกนี้ จึงสำคัญที่จะไม่แบกภาระเกินจำเป็นจากการพยายามทำเฟรมแรกให้สมบูรณ์แบบเสมอไป
ผมคิดว่าน้ำเสียงที่ดูแคลน SPA นั้นไม่ยุติธรรม แม้ SPA จะต้องใช้แรงมากกว่า แต่ข้อดีก็มากกว่าชัดเจน เป็นเวลานานมากที่ SPA คือวิธีเดียวในการสร้าง UX ที่ให้ความรู้สึกเหมือนแอป ผู้เขียนพูดถึง app fatigue แต่ถ้าจะมอบประสบการณ์แบบ ‘application’ จริง ๆ SPA ก็แทบเป็นทางเลือกเดียว การเอา SPA หนัก ๆ ไปเทียบกับเว็บไซต์เบา ๆ (static site) ก็ไม่เหมาะสม ถ้าใครสร้างเว็บไซต์เบา ๆ ได้ ก็สร้าง SPA เบา ๆ ได้เหมือนกัน ไม่ว่าจะเป็น SPA หรือเว็บไซต์ ถ้าสร้างอย่างไม่มีประสิทธิภาพก็ช้าและหนักได้เท่ากัน ในฐานะคนที่ลงทุนกับ SPA มาเยอะ ผมก็สนใจมากกับวิธีที่ใช้ความพยายามน้อยลงแต่ให้ประสบการณ์แบบเดียวกันได้ ทว่าบทความนี้ดูคล้ายแค่การตกแต่งภาพเล็กน้อย policy นั้นมีคุณค่า แต่ไม่ได้ทรงอิทธิพลพอจะตัดสินว่าจะเลือก SPA หรือไม่
การบอกว่า “ลองสร้าง linear.app โดยไม่ใช้ SPA framework ดูสิ” นั้นผมว่าไม่สมเหตุสมผล และประโยคที่ว่า “Native CSS transitions ทำลายข้อดีใหญ่ที่สุดของ SPA (client routing) ไปแล้ว” ก็ไม่สมเหตุสมผลเช่นกัน
ผมคิดว่า Linear เป็นกรณีพิเศษมากแม้ในบรรดา SPA และนี่ไม่ใช่การบอกให้แบน SPA หรือเอา JS ออกจากเบราว์เซอร์ไปเลย เหตุผลที่ Linear เร็วคือการออกแบบแบบ “offline-first” แต่แทบไม่มีบริการไหนทำแบบนั้น ผมคิดว่าระบบจองตั๋ว ฟอรัม ข่าว บล็อก หรือเว็บไซต์เชิงข้อมูล เหมาะกับการพัฒนาแบบ SSR มากกว่า ใช้ SPA เฉพาะจุดที่จำเป็นจริง ๆ ส่วนที่เหลือพัฒนาแบบ SSR ให้เร็ว แล้วใช้ CSS ทำให้มันดูเหมือน SPA จะมีประสิทธิภาพกว่ามาก
ไม่ใช่ว่า SPA ไม่มีที่ยืน แต่เว็บไซต์อีก 99% ที่เหลือไม่จำเป็นต้องเป็น SPA
SPA ไม่ได้มีไว้เพื่อ view transition (การเปลี่ยนหน้า) บทความต้นฉบับ (TFA) สื่อเหมือนว่าการเปลี่ยนหน้าหรู ๆ สำคัญมาก ซึ่งเป็นความคิดที่ผิด แทนที่จะไปโทษ “CMO” หรือ “brand manager” ควรพูดถึงคุณค่าที่แท้จริงของ SPA มากกว่า SPA เป็นเฟรมเวิร์กที่ยอดเยี่ยมสำหรับ client logic มีข้อดีมากมาย เช่น การแยก concerns (แยก frontend logic ออกจาก backend), ปรับปรุง developer experience → ทำให้พัฒนาได้เร็วขึ้น ฯลฯ ที่บทความแนวนี้ถูกพูดถึงเยอะก็เพราะมันสร้างข้อถกเถียงได้แบบที่คอมเมนต์ของผมกำลังทำอยู่ แต่จริง ๆ ผมไม่คิดว่าเป็นบทความที่ควรได้รับความสนใจขนาดนี้
จากมุมผม คำสัญญาหลักของ SPA ไม่ใช่การเปลี่ยนหน้าที่ลื่นไหล แต่คือการสร้าง data API กับ frontend ที่แยกจาก backend อย่างสมบูรณ์ เพราะแบบนี้ผมจึงไม่ชอบการผสม SSR กับ client rendering ผมมองว่ามันควรเป็นเว็บไซต์ไปเลยหรือไม่ก็เป็นแอปไปเลย
ผมมีคำถามว่า “เกณฑ์แบ่ง SPA กับ MPA คืออะไร” เว็บไซต์ส่วนตัวของผมที่ทำด้วย Next.js จริง ๆ แล้ว render เกือบทุกอย่างแบบ server-side technically มันเป็น SPA แต่ถ้าเปิด JS ก็จะมี RSC กับ client-side navigation ทำงาน และถ้าปิด JS แม้ client-only component (เช่นตัวสร้าง QR code) จะโชว์เป็น fallback content แต่ส่วนที่เหลือก็ยัง render แบบ SSR ทั้งหมด ทำงานได้ดีแม้จะช้าลงนิดหน่อย การไม่ render component จากฝั่งเซิร์ฟเวอร์กลับต้องใช้แรงมากกว่า Progressive enhancement ดีที่สุด
Window loadevent ของแอปเกิดขึ้นอีกอย่างหนึ่งคือผมหงุดหงิดมากที่ทั้งวงการ SEO และนักพัฒนาเว็บรุ่นใหม่ที่เพิ่งเข้าทำงานหลังโควิดชอบเข้าใจ SPA ผิดและดูแคลนมัน จากมุมคนที่พัฒนามาตั้งแต่ยุค 2000 จุดกำเนิดที่แท้จริงของ SPA ไม่ใช่เพราะ “คำสัญญาปลอม ๆ” ตามบทความต้นฉบับ แต่เป็นเพราะช่วงปลายยุค 2000 ถึงต้นยุค 2010 ที่กลยุทธ์ mobile-first แพร่หลายจนต้องแยก frontend กับ backend ออกจากกันโดยสิ้นเชิง ก่อนหน้านั้นฟรอนต์เอนด์โดยทั่วไปก็แค่ render HTML จาก template ฝั่งเซิร์ฟเวอร์แล้วโรย jQuery เล็กน้อย แต่ตอนนี้ทั้งแอปมือถือและเดสก์ท็อปต้องใช้ business logic/DB ชุดเดียวกัน จึงเกิดกระแสโครงสร้างแบบ REST, การกลับไปอ่านงานของ Roy Fielding, สถาปัตยกรรมเชิงบริการ และการเปิด API ออกสู่ภายนอก รวมถึงแรงผลักเรื่องการ optimize ต้นทุนด้วย ช่วงนั้นเฟรมเวิร์กเว็บแบบ full-stack อย่าง Ruby on Rails หรือ Django ก็ซบเซาไปพักหนึ่ง ขณะเดียวกัน Node.js ก็เริ่มมาแรง และทั้งเบราว์เซอร์กับมือถือก็ทรงพลังขึ้นเรื่อย ๆ จนสามารถย้าย business logic จำนวนมากไปไว้ที่ “edge device” หรือก็คือฝั่งไคลเอนต์ได้ และนี่แหละคือหัวใจของ SPA ซึ่ง CSS ไม่สามารถมาแทนความจำเป็นนี้ได้