Server Components ของ Next.js 14 ช่วยลดขนาด bundle ลงได้ประมาณ 60% และผลักดันเวลา first-paint ให้ต่ำกว่า 200 ms ในหน้าบล็อกทั่วไป ซึ่งหมายความว่าผู้ใช้จะเห็นเนื้อหาได้เร็วขึ้น และ search engine จะได้รับ HTML ที่ถูก render มาอย่างสมบูรณ์

การเปิดตัวเวอร์ชันใหม่นี้ได้พลิกโมเดลการทำงานเริ่มต้น (execution model) สำหรับแอป React ที่สร้างด้วย Next.js จากเดิมที่ทุก component จะถูกส่งไปยัง browser แต่ตอนนี้เหล่านักพัฒนาสามารถระบุส่วนต่างๆ ของ UI ให้เป็น “Server Components” เพื่อให้ทำงานบน backend เท่านั้น โค้ดสำหรับ component เหล่านั้นจะไม่ถูกส่งไปยัง client เลย ทำให้ browser ได้รับเพียงแค่ส่วนที่จำเป็นต้องมีการโต้ตอบ (interactivity) เท่านั้น

ทำไมการเปลี่ยนแปลงนี้ถึงสำคัญ

นักพัฒนา React ต้องต่อสู้กับปัญหาที่เกี่ยวพันกันสามประการมาอย่างยาวนาน ได้แก่ การส่ง network requests จำนวนมหาศาล, JavaScript bundles ที่บวมเกินไป และการโหลดหน้าเว็บที่ล่าช้า ปัญหาเหล่านี้ยังส่งผลเสียต่อ SEO เนื่องจาก HTML เริ่มต้นที่ส่งไปยัง crawler มักจะว่างเปล่า ทำให้ search bots ต้องรอการทำ client-side hydration ของ Next.js 14 จึงเข้ามาจัดการที่ต้นเหตุด้วยการย้ายงานที่ต้องใช้ข้อมูลหนักๆ ออกจาก client ไปอย่างสิ้นเชิง

Server Components แตกต่างจากโมเดลเดิมอย่างไร

  • Server Components – ทำงานบน server, ดึงข้อมูล (fetch data), ติดต่อกับ database และแสดงผลเป็น HTML ธรรมดา โดยที่ JavaScript ของพวกมันจะไม่ถูกส่งผ่านเครือข่ายเลย
  • Client Components – อยู่ใน browser และจัดการการโต้ตอบของ UI เช่น การคลิกปุ่ม, การส่งฟอร์ม หรือ component ใดๆ ที่มีการใช้ React state หรือ effects

framework นี้บังคับใช้การแบ่งส่วนนี้ด้วยคำสั่ง (directive) ง่ายๆ เพียงแค่เพิ่ม use client ไว้ที่ด้านบนสุดของไฟล์ จะเป็นการบอก Next.js ให้จัดการ component นั้นเป็น client-side เท่านั้น ส่วนอะไรก็ตามที่ไม่มีเครื่องหมายนี้จะถูกกำหนดให้เป็น Server Component โดยค่าเริ่มต้น

ตัวเลขจากโลกแห่งความเป็นจริง

การทดลองสั้นๆ กับหน้าบล็อกส่วนตัวแสดงให้เห็นถึงผลลัพธ์ที่ชัดเจน หลังจากย้ายการ fetch ข้อมูลเข้าไปอยู่ใน Server Component และปล่อยให้ server ทำการ render รายการเป็น static HTML ขนาดของ JavaScript bundle ก็ลดลงถึง 60% และหน้าเว็บก็ render เสร็จสิ้นภายในเวลาไม่ถึง 200 ms

รูปแบบการวางเลเยอร์ที่นำไปใช้ได้จริง

  1. Bottom layer (Server) – ดึงข้อมูลจาก APIs หรือ databases เก็บ logic ส่วนตัวไว้ที่นี่ เพราะมันจะไม่หลุดออกจาก server เลย
  2. Middle layer (Server) – แปลงข้อมูลดิบให้เป็น HTML markup บริสุทธิ์ เลเยอร์นี้ยังคงสามารถใช้ syntax JSX ของ React ได้ แต่จะทำงานบน server เท่านั้น
  3. Top layer (Client) – ใส่ widget ขนาดเล็กที่แยกส่วนกันเพื่อการโต้ตอบ ตัวอย่างที่เห็นได้ชัดคือ ปุ่ม “like”, ฟอร์มแสดงความคิดเห็น หรือเมนู dropdown ที่ต้องมีการใช้ state

การทำตามลำดับขั้นนี้จะช่วยให้แอปส่วนใหญ่มีน้ำหนักเบา ในขณะที่ยังคงรักษาความรู้สึกที่ลื่นไหล (dynamic feel) ตามที่ผู้ใช้คาดหวังไว้

ขั้นตอนที่คุณสามารถเริ่มทำได้วันนี้

  1. ตรวจสอบ codebase ของคุณเพื่อหา component ที่ใช้ useEffect เพียงเพื่อการ fetch ข้อมูลเท่านั้น
  2. แยกการเรียก fetch ออกมาเป็น Server Component ใหม่ และปล่อยให้มันส่งคืน markup ที่ถูก render แล้ว
  3. สร้าง client component ขนาดเล็กที่สุด (โดยเพิ่ม use client ไว้ด้านบน) สำหรับองค์ประกอบที่มีการโต้ตอบที่เหลืออยู่
  4. รัน bundle analyzer อีกครั้ง คุณควรจะเห็นขนาดที่ลดลงอย่างเห็นได้ชัด

หลีกเลี่ยงการใส่ use client ไว้ทุกที่ หาก component ใดไม่ได้พึ่งพา React state, context หรือ lifecycle hooks ก็ควรปล่อยให้เป็น Server Component ยิ่งคุณเก็บโค้ดไว้ห่างจาก client มากเท่าไหร่ ขนาดการดาวน์โหลดก็จะยิ่งเล็กลงและหน้าเว็บก็จะยิ่งเร็วขึ้นเท่านั้น

สรุป: ด้วยการย้ายการ fetch ข้อมูลและการ render หนักๆ ไปไว้ที่ server ทำให้ Next.js 14 ช่วยให้คุณส่ง JavaScript ไปน้อยลงมาก, ส่งมอบ HTML ที่ถูก render มาอย่างสมบูรณ์ได้ทันที และยังคงรักษาการโต้ตอบไว้ในจุดที่จำเป็นจริงๆ ผลลัพธ์ที่ได้คือประสบการณ์เว็บที่เร็วขึ้นและเบาขึ้น ซึ่งเป็นประโยชน์ต่อทั้งผู้ใช้และ search engine