- Next.js มีข้อจำกัดด้านการตั้งค่ามิดเดิลแวร์สำหรับการล็อก และ การล็อกพื้นฐาน ถูกเปิดใช้งานเฉพาะในสภาพแวดล้อมพัฒนาเท่านั้น ทำให้ติดตามปัญหาใน production ได้ยาก
- ในมิดเดิลแวร์สามารถส่งต่อได้แค่ header และไม่สามารถ chain มิดเดิลแวร์หลายตัวได้ จึงจำกัดการทำระบบล็อกที่ซับซ้อน
- การล็อกด้วย AsyncLocalStorage มีพฤติกรรมไม่คาดคิดใน Edge runtime และ การแชร์คอนเท็กซ์ ระหว่างหน้าเพจกับมิดเดิลแวร์ก็ทำงานได้ไม่ถูกต้อง
- ต่อให้ใช้ custom server ก็แก้ปัญหาการล็อกได้ยาก และข้อจำกัดเชิงการออกแบบของ Next.js ก็บีบบังคับนักพัฒนาให้ทำตามแนวทางที่กำหนด
- SvelteKit ของ Vercel มีมิดเดิลแวร์ที่ยืดหยุ่นกว่าและมีกลไกส่งผ่านข้อมูลที่ดีกว่า แสดงให้เห็นการออกแบบที่เป็นมิตรกับนักพัฒนามากกว่า Next.js
เบื้องหลังปัญหาการล็อกของ Next.js
- ระหว่างดูแลบริการที่ใช้ Next.js และพยายามทำ การบันทึกล็อกใน production จึงพบว่าฟังก์ชันล็อกพื้นฐานถูกเปิดใช้เฉพาะในสภาพแวดล้อมพัฒนา
- เมื่อต้องการ สร้างระบบล็อก ที่เหมาะกับสภาพแวดล้อมจริง จึงต้องเจอกับข้อจำกัดของ Next.js
ข้อจำกัดของมิดเดิลแวร์
- ตามเอกสารทางการ มิดเดิลแวร์จะ ทำงานก่อนการ routing และเหมาะกับการทำฟีเจอร์อย่าง authentication, logging และ redirection
- แต่ในความเป็นจริง พารามิเตอร์ที่ส่งต่อได้ในมิดเดิลแวร์ถูกจำกัดไว้ที่ 4 ตัว และมีเพียง header เท่านั้นที่ส่งต่อใช้งานได้จริง
- โครงสร้างแบบ chain หรือผสาน มิดเดิลแวร์หลายตัว เข้าด้วยกันนั้นไม่ถูกรองรับ
- แม้ใน Node.js จะมีแนวปฏิบัติด้านมิดเดิลแวร์ที่ชัดเจนจาก Express และอื่น ๆ แต่ ใน Next.js ไม่สามารถนำแนวทางเหล่านั้นมาใช้ได้อย่างเหมาะสม
ความพยายามอ้อมปัญหาด้วย AsyncLocalStorage
- มีการลองใช้ pino และ AsyncLocalStorage เพื่อจัดการอินสแตนซ์การล็อกในระดับมิดเดิลแวร์
- แม้จะสามารถเก็บล็อกแยกตามคอนเท็กซ์ของแต่ละ request ได้ในมิดเดิลแวร์ แต่กลับพบว่า ทำงานได้ปกติเฉพาะในสภาพแวดล้อมเบราว์เซอร์เท่านั้น
- สาเหตุคือมิดเดิลแวร์ของ Next.js ใช้ Edge runtime เป็นค่าเริ่มต้น และแม้จะตั้งเป็น Node.js runtime ก็ยังไม่เสถียรขึ้นอยู่กับสถานการณ์ของโปรเจ็กต์
อุปสรรคในคอมโพเนนต์ของหน้าเพจ
- เมื่อเรียกใช้ฟังก์ชันล็อกในหน้าเพจหรือเลย์เอาต์คอมโพเนนต์จริง logger() จะคืนค่าเป็น null
- มีปัญหาเชิงโครงสร้างที่ทำให้คอนเท็กซ์ logger ที่สร้างในมิดเดิลแวร์ ไม่ถูกส่งต่อไปยังบริบทการเรนเดอร์แบบอะซิงโครนัส
- วิธีแก้มีเพียง แนบข้อมูลการล็อกอย่าง requestId ไปกับ header เพื่อส่งต่อ ซึ่งทำให้โค้ดซับซ้อนขึ้นและโครงสร้าง import ก็ชวนสับสน
- ใน client component ก็ต้องเพิ่มการแยกโครงสร้างในลักษณะคล้ายกันอีก
ความพยายามใช้ custom server
- มีการทดลองตามตัวอย่าง custom server ในเอกสารทางการ โดยใช้ http.createServer และ app.getRequestHandler ของ next.js
- ในสภาพแวดล้อมนี้ก็พยายามนำ AsyncLocalStorage กลับมาใช้อีกครั้ง แต่ก็ยังพบปัญหาว่า ไม่สามารถเชื่อมคอนเท็กซ์ระหว่างมิดเดิลแวร์–เพจ–custom server ได้ ซ้ำเดิม
- โดยพื้นฐานแล้ว Next.js ใช้ AsyncLocalStorage ได้อย่างเหมาะสมเฉพาะภายในระบบของตัวเอง และไม่ได้เปิดสิทธิ์ในระดับเดียวกันให้นักพัฒนา
- วิธีส่งต่อจากมิดเดิลแวร์ไปยังหน้าเพจที่เป็นไปได้จริง แทบมีแค่ response header (change) และการย้ายเส้นทางด้วย redirect/rewrite
- จากมุมมองของผู้ใช้ การขยายระบบอย่างยืดหยุ่นหรือการส่งต่อ custom context ทำได้ยากมาก
เปรียบเทียบกับ SvelteKit
- SvelteKit ของ Vercel มี ระบบมิดเดิลแวร์ ที่ยืดหยุ่นกว่า Next.js
- สามารถส่งต่อข้อมูลของ request ได้อย่างอิสระผ่านอ็อบเจ็กต์ event.locals
- สามารถกำหนด handle function หลายตัวแล้ว chain ต่อกันได้ ทำให้ทำลอจิกที่ซับซ้อนได้ง่าย
- SvelteKit แสดงให้เห็นการออกแบบที่ เป็นมิตรกับนักพัฒนา ซึ่งตัดกันชัดเจนกับข้อจำกัดของ Next.js
- แม้ SvelteKit จะเป็นผลิตภัณฑ์ของ Vercel เช่นกัน และถูกมองว่าเป็น โปรเจ็กต์รอง เมื่อเทียบกับ Next.js แต่กลับมอบประสบการณ์ที่ดีกว่า
วิจารณ์ issue tracker และวัฒนธรรมของ ecosystem
- GitHub issue tracker อย่างเป็นทางการของ Next.js แทบไม่ตอบสนองต่อ feedback จากผู้ใช้
- แม้แต่ issue หรือ bug ยอดนิยมก็ยังถูกปล่อยทิ้งไว้นานโดยไม่มีคำตอบหรือการแก้ไขอยู่บ่อยครั้ง
- ต่อให้เตรียมโค้ดสำหรับ reproducing แบบ minimal แล้วเปิด issue ก็ยัง ไม่ได้รับการตอบสนองหรือการดำเนินการต่ออย่างเป็นรูปธรรม
บทสรุปและการทบทวน
- บั๊กและข้อจำกัดเชิงโครงสร้าง ที่พบใน Next.js ส่งผลเสียต่อ productivity ของนักพัฒนาอยู่ซ้ำ ๆ และดูเป็นปัญหาที่ควรถูกแก้ไขในระดับรากฐาน
- เมื่อเทียบกับเฟรมเวิร์กอื่นอย่าง SvelteKit Next.js กลับเสียเปรียบด้านการใช้งาน ทั้งที่เป็นผลิตภัณฑ์หลัก
- แม้ตอนนี้จะยังเปลี่ยนจาก Next.js ได้ยาก แต่ก็เริ่มรู้สึกว่าโปรเจ็กต์ในอนาคตควรพิจารณาทางเลือกอื่นด้วย
7 ความคิดเห็น
ดูเหมือนว่ายังไม่ได้นึกเลยว่า React ก็ทำลายประสิทธิภาพการทำงานเหมือนกัน
ครั้งนี้ผมลองทำเว็บพัฒนาดูด้วยความสนใจส่วนตัวล้วน ๆ ในสายที่ไม่เกี่ยวกับงานพัฒนาที่เคยทำเลย เดิมทีผมทำบอร์ดประกาศด้วย next.js v15 app router แต่พอเห็นโพสต์แบบนี้ทีไร ก็รู้สึกเหมือนหมดไฟที่จะลองอะไรใหม่ ๆ ทางฝั่งเว็บทุกทีเลยนะครับ ทำไม ecosystem ถึงไม่เสถียรขนาดนี้กันนะ แบบนี้เดี๋ยวพอมีของใหม่ออกมา คนก็จะแห่กันไปใช้พักหนึ่ง แล้วก็บ่นก่อนจะไปหาตัวอื่นอีกหรือเปล่า วงการเว็บพัฒนานี่คงยากจริง ๆ นะครับ
ข้อดีของวงการนี้คือการเปลี่ยนแปลงเกิดขึ้นเร็ว แต่ในขณะเดียวกันก็เป็นข้อเสียด้วยเหมือนกัน 555 แต่ปัญหาในเนื้อหาหลักจริง ๆ แล้วมีต้นตอมาจากการก่อกวนของ Vercel โดยพื้นฐาน ถ้าคุณจะทำฝั่งฟรอนต์เอนด์ ก็ควรจับตา Vercel ไว้สักหน่อยครับ ฮือ ๆ
ฉันเริ่มต้นเส้นทางอาชีพจากสายเว็บ เลยไม่แน่ใจว่าเพราะแบบนั้นหรือเปล่า แต่การพัฒนาเว็บ (โดยเฉพาะฝั่งฟรอนต์) เดิมทีก็พัฒนากันด้วยอารมณ์ประมาณนี้แหละ
มีรสชาติแบบเปลี่ยนแปลงรวดเร็วตลอดเวลา...
ฝั่ง JS ก็ให้ความรู้สึกประมาณนั้นน่ะครับ มีอะไรหลายอย่างที่เขาว่ากันว่าดี แต่พอแยกดูแล้วแต่ละอย่างก็มีปัญหานิด ๆ หน่อย ๆ กันหมด และกระแสก็เปลี่ยนเร็วตามเทรนด์ไปเรื่อย ๆ...
อาจเป็นเพราะผมเคยใช้ Java, EJB, Struts เป็นหลักด้วยก็ได้เลยรู้สึกแบบนั้น
ความคิดเห็นจาก Hacker News
เห็นด้วย 100% ฉันก็เจอปัญหาเดียวกัน และจะไม่ใช้ Next.js อีกเด็ดขาด รวมถึงตั้งใจจะแนะนำทุกทีมในบริษัทให้ใช้ทางเลือกอื่น
Next.js มีชั้น abstraction มหาศาลที่ไม่จำเป็นสำหรับ 99.9999% ของโปรเจกต์ และในกรณีส่วนน้อยที่จำเป็นจริง ๆ ฉันคิดว่าทำโซลูชันเฉพาะด้วยชิ้นส่วนระดับล่างจะดีกว่า
ในบรรดาเทคโนโลยีที่เคยใช้ Next.js แย่ที่สุดแบบทิ้งห่าง
โล่งใจมากที่ไม่ได้มีแค่ฉันคนเดียวที่คิดแบบนี้
ฉันเคยทำแอป production ที่มีรายได้และมีความซับซ้อนระดับกลางด้วย Next.js ตอนแรกใช้ Vercel กับ Google Firebase แล้วหลังจากนั้นย้ายไปโฮสต์เองและเปลี่ยนเป็น Pocketbase
มีแค่ Pocketbase อย่างเดียวที่ประสบการณ์โอเค ที่เหลือเลวร้ายหมด
มีแต่ความซับซ้อนไม่รู้จบ การเปลี่ยนแปลงที่พังของเดิมตลอดเวลา และเอกสารที่เข้าถึงยาก ไม่มีอะไรที่ง่ายเลย
ฉันมั่นใจว่าถ้า 5 ปีที่ผ่านมาเราเอาวงการ FE ย้อนกลับไป แล้วโฟกัสกับการสอนเทคโนโลยีที่มีอยู่ในตอนนั้นให้ดี สถานการณ์ตอนนี้คงดีกว่านี้
ฉันก็เคยทำ React frontend ที่ซับซ้อนพอสมควร แม้จะไม่ได้ชอบ React มากนัก แต่ Next.js แย่ยิ่งกว่าอีก
ฉันยังเคยทำ CMS ด้วย Go และ vanilla JS ด้วย ถึง DX อาจจะด้อยกว่านิดหน่อย แต่ก็ให้ความรู้สึกว่าฉันรู้จริง ๆ ว่าเกิดอะไรขึ้น
ไม่เข้าใจว่าทำไมใน React และ Next.js ผ่านมา 6 ปีแล้วก็ยังต้องเดาอยู่ตลอดว่าจะเกิดอะไรขึ้น
ฉันสะสมประสบการณ์พอจะคลี่ความพันกันของ framework ได้แล้ว แต่โดยรวมมันยังให้ความรู้สึกว่าสกปรกและออกแบบมาไม่ดี
ใน Go หลังผ่าน 6 เดือนแรกไปแล้วก็แทบไม่มีอะไรให้แปลกใจ และ codebase เก่า ๆ ก็ยังแข็งแรงอยู่
น่าเสียดายที่ฝั่ง frontend ยังสร้างประสบการณ์แบบนี้ไม่ได้
จากประสบการณ์ของฉัน ส่วนที่หยาบ ๆ ของ Next.js ไม่ใช่บั๊ก แต่เป็นฟีเจอร์
ทุกอย่างเหมือนถูกออกแบบมาให้ผู้ใช้ถอดใจแล้วถูกผูกติดกับโฮสติ้งของ Vercel
คิดว่าสถานการณ์จะยิ่งแย่ลงอีกในอนาคต
ตอนนี้แม้แต่คอร์สออนไลน์อย่าง PluralSight ก็ยังดัน Next.js อย่างเดียวในคอร์สสาย React
ไม่รู้ว่าทำไมมันถึงกลายมาเป็นแบบนี้ แต่สุดท้ายก็มาอยู่ตรงนี้แล้ว
สำหรับฉัน Sharepoint เป็นความทรงจำที่สกปรกกว่า ดังนั้น Next.js เลยเป็นอันดับสองของที่แย่ที่สุด
สิ่งที่น่าหงุดหงิดที่สุดใน Next.js คือมันทำเหมือนเป็น full-stack framework แบบ Rails, Wordpress, Meteor ที่มีทุกอย่างให้ แต่ในความจริงกลับมีความเห็นเฉพาะส่วนที่น่าเบื่อและจำกัดที่สุดเท่านั้น เช่น middleware, image resizing, SSR ฯลฯ แล้วกลับโยนการตัดสินใจที่มีคุณค่าจริง ๆ เช่น database, ORM, communication protocol ให้ผู้ใช้จัดการเอง
ในทางปฏิบัติมันแตกต่างจาก Rails/Wordpress/Meteor มาก และแทนที่ framework จะเป็นตัวกำหนดโครงสร้างพื้นฐาน กลับกลายเป็นว่าโครงสร้างพื้นฐานมาคุม framework แทน
ในแดชบอร์ดของฉัน "Fluid Active CPU" กับ "ISR Writes" คือรายการใช้งานสูงสุด และสิ่งที่ทำได้ก็มีแค่จ่าย $20 แล้วภาวนาอย่าให้เกิน 100%
ชื่อรายการต่าง ๆ เต็มไปด้วยคำเทคนิคแบบ Star Trek จนไม่อยากเสียเวลาเรียนรู้ เพราะเดี๋ยวเวอร์ชันใหญ่ครั้งหน้าก็คงเปลี่ยนอีก
คนรู้จักที่เคยคลั่งไคล้ Zeit เมื่อก่อนจำนวนไม่น้อยสุดท้ายก็ย้ายโปรเจกต์กับลูกค้าออกไปที่อื่น
ถ้า Vercel มาถามฉันว่าควรเปลี่ยนอะไรใน major release ถัดไป ฉันคงตอบได้แค่ว่า "ทุกการตัดสินใจตั้งแต่ App Router เป็นต้นมาผิดหมด"
ฉันไม่รู้เลยว่าจะกู้สถานการณ์นี้กลับมายังไง
ฉันคิดว่าปัญหาหลายอย่างของ Next.js มาจากการที่เราไม่ค่อยรู้ว่าโค้ดรันอยู่ที่ไหนกันแน่
ทั้ง browser, middleware, edge กับ node, SSR ทุกอย่างปนกันจนเกิดความซับซ้อนมหาศาล
กรณีที่ยุ่งยากแบบนี้จะเหมาะเมื่อ
คุณทำบริการ B2C สำหรับผู้ใช้ทั่วโลกและอยากลด latency ด้วย edge semantics
คุณพร้อมจะใช้โฮสติ้งราคาแพงของ Vercel
คุณต้องการสถาปัตยกรรมที่ไม่ซับซ้อนมากและไม่ต้องมี background jobs
กรณีอื่นนอกจากนั้น react-vite SPA หรือ SSR แบบดั้งเดิมอย่าง Rails มักจะเป็นทางเลือกที่ปลอดภัยกว่ามาก
ฉันไม่เห็นด้วยแม้แต่กับเงื่อนไขข้างบน
ถึงจะเป็นเคสที่เข้ากับ Next.js จริง ๆ ฉันก็ยังไม่คิดว่าการลดลงของ productivity และ maintainability จะคุ้มค่าเลย
ตอนนี้ฉันใช้ Lustre ของ Gleam และไม่คิดจะหันกลับไปแล้ว
keynote ของผู้ก่อตั้ง Elm ก็เป็นตัวอย่างในทิศทางตรงข้ามกับ Next.js เช่นกัน
https://www.youtube.com/watch?v=sl1UQXgtepE
ฉันมองว่า Vercel เป็นมะเร็งของเว็บยุคใหม่
มันแทรกซึมเข้าไปในทุก ecosystem ของ framework แล้วใช้มันในทางที่ผิดเพื่อขายแพ็กเกจเสียเงิน พร้อมทำทีเหมือนสนับสนุนโอเพนซอร์ส การแข่งขัน และความก้าวหน้าของเว็บ
ต่อให้เข้าเงื่อนไขข้อแรก ก็ยังยากจะเชื่อว่าการใช้ Vercel กับ SSR จะช่วยแก้คอขวดด้านประสิทธิภาพได้
สาเหตุของประสิทธิภาพตกส่วนใหญ่ก็มักเป็นเรื่องพื้นฐาน เช่น bundle ใหญ่เกินไป หรือมี API call ช้า ๆ จำนวนมาก
การทำ profiling, optimization และ simplification พื้นฐานก่อน มีผลดีกว่าการเพิ่มความซับซ้อนทางสถาปัตยกรรมมาก
ฉันเห็นด้วยกับประเด็นเรื่อง "ไม่รู้ว่าโค้ดรันอยู่ที่ไหน"
เมื่อก่อนฉันเคยมองว่าความเป็น everything-in-JavaScript เป็นข้อดี แต่ตอนนี้กลับรู้สึกว่ามันเป็นปัญหา
บริษัทของเราใช้ Inertia.js + Vue ซึ่งโดยรวมโครงสร้างเรียบง่ายมาก ยังได้พลังของการ render ฝั่ง frontend ครบ แต่ routing จัดการฝั่ง server 100% และไม่ต้องมี API แยกเลย
Inertia ใช้กับ React และ Svelte ก็ได้
ตอนแรกเราใช้ Nuxt แต่ซับซ้อนถึงขั้นต้องรันทั้ง backend server กับ frontend server พร้อมกัน และยากจะรู้ว่าโค้ดตัวไหนรันที่ไหน
ตอนนี้แยกชัดเจนว่า PHP คือ server, JS คือ browser เลยไม่ต้องปวดหัวอะไรเลย
สำหรับเรา นี่เป็นข้อได้เปรียบมหาศาล
สรุปประเด็นได้ดีมาก
Vercel กำลังไล่ล่าการเพิ่มประสิทธิภาพด้วย React Server Components, Partial Pre-rendering, Edge server, streaming ฯลฯ
การออกแบบและการตัดสินใจด้าน API ที่แปลก ๆ ทั้งหมดก็มาจากตรงนี้
ถ้าจำเป็นจริง สิ่งเหล่านี้อาจช่วยได้ แต่หลายกรณีแค่ใช้ ssr อย่างเหมาะสมใน edge function บางส่วนก็ทำให้ดีขึ้นได้มากแล้ว
ขอบคุณสำหรับ feedback
เราทราบถึงปัญหา DX ใน Middleware และในเวอร์ชัน 15.5 ได้เพิ่มการรองรับ Node runtime เป็นความก้าวหน้าครั้งใหญ่[1]
ถ้าย้อนกลับไปได้ เราน่าจะเปลี่ยนชื่อเป็น Routing Middleware หรือ Routing Handler เพื่อสื่อว่ามันเป็น advanced escape hatch สำหรับใช้ในขั้น routing และส่งต่อไปยัง CDN edge ได้
ถ้าต้องการ log สามารถใช้ OpenTelemetry และจัดการตามแนวทาง
instrumentation.ts[2] ได้[1] https://nextjs.org/blog/next-15-5#nodejs-middleware-stable
[2] https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation
ขอบคุณสำหรับคำตอบ
แต่พอพูดถึง instrumentation กับ observability แล้ว มันฟังดูเหมือนกำลังแก้ปัญหา logging ง่าย ๆ ด้วยอีกชั้นความซับซ้อน
ไม่ใช่ทุกแอปที่ต้องการ OpenTelemetry
ฉันไม่เข้าใจว่าทำไมวิธีธรรมดาอย่าง
logger().info()ถึงทำไม่ได้ภาษาและ framework อื่นก็มีหมด แล้วทำไมอันนี้ถึงยากขนาดนี้ก็ไม่เข้าใจ
บรรยากาศที่นี่ค่อนข้างลบ เลยอยากพูดให้ชัดก่อน: Next.js เป็นซอฟต์แวร์ที่ดีมากและเหมาะกับเป้าหมายที่มันตั้งไว้จริง ๆ
ฉันคิดว่ามันถูกสร้างมาอย่างดีเพื่อรองรับเว็บไซต์นับล้าน
ปัญหาอยู่ที่การขาดเอกสารและ reference เชิงลึก ซึ่งเอกสารบอกว่ามีอะไรอยู่บ้าง แต่ไม่ได้อธิบายดีพอว่าควรใช้อย่างไร รันเมื่อไร มีหลุมพรางอะไรบ้างที่พบบ่อย
มันเป็นมิตรกับผู้เริ่มต้น แต่ยังขาดคำอธิบายเกี่ยวกับ runtime context ที่ซับซ้อนหรือความซับซ้อนที่เกิดตามมา
นี่เป็นแนวโน้มที่เห็นได้ในหลายโปรเจกต์ช่วงนี้
การหาสมดุลระหว่างความเป็นมิตรกับผู้ใช้และคำอธิบายเชิงลึกเป็นเรื่องยากมาก
หวังว่ามันจะพัฒนาต่อไป
ขอพูดสั้น ๆ อีกที
ผู้เขียนบทความนี้แค่แยกความต่างของโดเมนไม่ออก และพยายามเรียกใช้ฟังก์ชันแบบเดียวกันทุกที่
ข้อผิดพลาดของ Next.js เกิดจากความพยายามฝืนรวมโดเมนที่มีธรรมชาติแตกต่างกันเข้าด้วยกันตั้งแต่แรก
ถ้าพยายามปน edge, SSR, Node และ client เข้าด้วยกันแบบนี้ มันก็มีแต่เพิ่มความซับซ้อน
ต่อให้มีเอกสารก็แก้ไม่ได้ มีแต่จะทำให้สับสนมากขึ้น
ฉันเคยมีคนแนะนำวิธีทำ instrumentation ในคอมเมนต์ Reddit
ถ้าฉันไปนั่งตั้งค่า opentelemetry ให้ Next ในช่วงเวลาใกล้ ๆ กัน ถึงเอกสารจะต่างออกไป ก็คงได้เขียนบล็อกโพสต์หลังเจอประสบการณ์แบบนี้เหมือนกัน
ไม่ใช่ความผิดของพวกคุณโดยตรง แต่แทบทุกแพ็กเกจ opentelemetry มีป้าย experimental เลยทำให้ไม่มั่นใจเวลาจะใช้ใน production
การตั้งค่า pino instrumentation ก็ยากมาก
ต้องเพิ่ม pino เข้าไปใน
serverExternalPackagesถึงจะทำงานถูกต้องauto instrumentation ก็ไวกับลำดับ
importแบบสุด ๆ และวัดได้เฉพาะ default export ของ pinoตัวแปร local ของโมดูลก็ไม่ทำงานอย่างที่หวัง จนต้องใช้
globalThisแล้วสุดท้ายก็ยังไปติดปัญหานี้อีก https://github.com/vercel/next.js/issues/80445
สรุปคือสุดท้ายมันก็ทำงานได้ แต่การตั้งค่าน่าหงุดหงิดมาก
ประสบการณ์แบบนี้เกิดขึ้นเพราะใช้ manual router (= ไม่ใช้
vercel/otel)ถ้าตัดสินใจรองรับ server-side middleware แล้ว ทำไมถึงยังไม่มี middleware chain (การต่อหลายฟังก์ชัน) และยังรองรับแค่ตัวเดียวอยู่ ก็ไม่เข้าใจ
มันเป็นฟีเจอร์ที่ server framework อื่นมีหมด
ฉันชักสงสัยแล้วว่าที่บอกว่า "ต่อ middleware หลายตัวไม่ได้" เป็นเรื่องจริงหรือเปล่า
https://nextjs.org/docs/messages/nested-middleware
ถ้ามีหลายตัวก็ต้องรวมเป็นไฟล์เดียวแล้วค่อยรัน ฟังแล้วยังไม่น่าเชื่อจริง ๆ
ถ้าฉันอ่านไม่ผิด นี่แปลว่า Next.js กำลังบอกว่าอย่าแยกโครงสร้างเป็นหลายไฟล์ แต่ให้รวมเป็นไฟล์เดียวเหรอ?
เป็นเพราะปัญหาเรื่อง scoping เลยใช้หลายไฟล์ลำบากงั้นหรือ? สำหรับ framework แล้วนี่เป็นข้อเรียกร้องที่เหลือเชื่อเกินไป
ฉันอดสงสัยไม่ได้ว่าการตัดสินใจประหลาด ๆ พวกนี้หลายอย่างไม่ได้ทำเพื่อประโยชน์ของ framework แต่ทำเพื่อให้ Vercel ได้เปรียบมากกว่า
ตอนเห็น Next.js ครั้งแรก ฉันนึกถึง Meteor.js ขึ้นมาทันที
ฉันลงทุนเรียนรู้มันพอสมควรในโปรเจกต์ส่วนตัว แต่เพราะ abstraction ที่มากเกินไปและความแข็งทื่อของมัน เลยไปได้ไม่เกินขั้น prototype
โซลูชันแบบ “batteries included” พวกนี้ยังคงโผล่มาเรื่อย ๆ เพราะมันตั้งค่าเริ่มต้นได้สะดวก
ไม่นานมานี้ใน Hacker News ก็ยังมีการคุยเปรียบเทียบ Laravel vs Symphony โดยมีคนบอกว่าพอระบบซับซ้อนขึ้นมันก็พัง
ถ้าเทียบแนวทางแบบนี้กับการประกอบเองเป็นชิ้น ๆ แบบ NodeJS/React SPA สมัยก่อน แต่ละชิ้นจะเป็น abstraction ระดับล่างที่แยกอิสระ ทำให้ยืดหยุ่นกว่าและเปลี่ยนบางส่วนได้ง่ายกว่า
ถึงจะมีข้อเสีย แต่ก็มักลื่นไหลกว่าการ over-engineer หรือพูดอีกอย่างคือความซับซ้อนที่ก่อทับซ้อนขึ้นมา
ฉันเข้าใจดีว่าทำไมแบบ batteries included ถึงได้รับความนิยม
การประกอบเครื่องมือกับไลบรารีสารพัดให้เข้ากันมันน่ารำคาญจริง ๆ
แนวประกอบเองแบบนี้มักต้องมีคนที่เชี่ยวชาญกว่ามาช่วยเซ็ตให้ถึงจะทำงานดี
ฉันคุ้นกับ asp.net ซึ่งในคอมมูนิตี้นักพัฒนาสายสตาร์ตอัปมักถูกมองไม่ค่อยดี แต่จริง ๆ แล้วมันเป็น framework ที่ออกแบบมาดีมาก
มันเป็นแบบ batteries included ก็จริง แต่ฉันสามารถหลุดออกจาก framework และ override สิ่งต่าง ๆ ได้ทุกเมื่อ และไม่เคยรู้สึกเลยว่ากำลังสู้กับ framework
ทั้ง Blazor Server และ Blazor Webasm ก็ให้ใช้ C# ทำฝั่ง frontend ได้ และทั้งคู่เหมาะกับแผงจัดการภายในหรือแอป SaaS ในแบบของตัวเอง
ที่สำคัญคือแค่ traditional server-side rendering ก็แก้โจทย์ได้เกือบทั้งหมดแล้ว
ถ้าใครไม่พอใจกับ web framework ที่ใช้อยู่ ฉันอยากแนะนำให้ลองมาก
ตอนนี้รองรับ cross-platform ดีมาก เร็ว และเรียนรู้ง่าย
มี learning curve อยู่บ้าง แต่พอเข้าใจโครงสร้างโมดูลแล้วก็ override ได้ตามใจทันที
เมื่อเทียบกับ framework อื่นแล้ว แทบไม่ค่อยเจอช่วงที่ชนข้อจำกัดจริง ๆ
สำหรับคนที่คุ้นกับการประกอบทีละชิ้นแบบ NodeJS/React SPA องค์ประกอบลักษณะนั้นใน Angular อาจดูแปลก
Angular ไม่ใช่ไลบรารีแต่เป็น framework เลยมีฟังก์ชันส่วนใหญ่ที่ต้องใช้อยู่แล้วในตัว
(RxJS อาจมี learning curve บ้าง แต่ถ้าเข้าใจพื้นฐานก็ทรงพลังมาก)
โดยทั่วไปฉันแทบไม่ค่อยมีประสบการณ์ต้องไปสู้กับ framework เวลาใช้ทำ SPA
เอกสารและบทเรียนต่าง ๆ (รวมถึง Tour of Heroes) ก็ยอดเยี่ยมมาก
https://v17.angular.io/tutorial/tour-of-heroes
เอกสารล่าสุดดูได้ที่ https://angular.dev/
Laravel เป็นตัวอย่างของ abstraction แบบ over-engineering ที่ประสบความสำเร็จ
เพราะ Laravel ฉันไม่เคยเสียใจที่ใช้มันใน production เลย
พูดนอกเรื่องนิดหน่อย แต่การคอยเชื่อมเครื่องมือกับไลบรารีจุกจิกสารพัดที่เข้ากันไม่สนิทพวกนี้คือเนื้องานทั้งหมดของฉันเลย
ทีมเราขนาดเล็ก เลยต้องเสียเวลามหาศาลกับการอัปเดตและบำรุงรักษา และยังเจอปัญหาแพ็กเกจที่เลิกซัพพอร์ตไปนานแล้วบ่อยมาก
ไม่ใช่แค่ประสบการณ์ แต่เวลาเริ่มต้นสร้างระบบและต้นทุนการดูแลรักษามันสูงกว่าที่คนส่วนใหญ่คิดมาก
พอได้ลองทำเองแล้ว ฉันรู้สึกว่า Rails มี productivity สูงกว่าการเอาไลบรารี Node มาประกอบทีละชิ้นถึง 10 เท่า
ปัญหาจะเกิดก็ต่อเมื่อคุณไม่ชอบแกนและปรัชญาหลักของ framework เท่านั้น เช่น ถ้าไม่ชอบ ActiveRecord
คำพูดที่ว่า "พอความซับซ้อนเพิ่มขึ้นทุกอย่างก็พัง" เป็นเพราะความสามารถทางเทคนิคยังไม่พอมากกว่า
ฉันเป็นคนที่ปกป้อง React มาก และก็ชอบการเปลี่ยนจาก class component ไปเป็น hooks
แต่ทุกครั้งที่ใช้ Next.js ฉันจะเริ่มงงว่าเรื่องมันพังตรงไหนตั้งแต่แรก
ฉันชอบทั้ง framework จำนวนมากและภาษาแปลก ๆ แต่มีแค่ Next.js ที่ทำให้ฉันอ่าน error message ไม่เข้าใจเกินครึ่ง
โดยเฉพาะเวลาที่หมดไปกับปัญหา hydration แปลก ๆ นั้นมหาศาลมาก
ฉันไม่ได้ใช้ React หรือ Next.js
โดยส่วนตัวฉันชอบ HTML+CSS แล้วเสริม vanilla JS มากกว่า
ฉันเคยเจอแม้แต่หน้า landing page ง่าย ๆ ที่ทำด้วย Next.js พังบน Firefox
ที่หนักกว่านั้นคือรูปแบบความล้มเหลวเป็นการขึ้นจอดำพร้อมตัวอักษรสีขาวทับทุกคอนเทนต์ว่า "An application client side error has occurred"
ฉันตกใจมากที่แม้แต่ landing page ง่าย ๆ ก็ยัง render ไม่ได้ และพอรู้ว่าสาเหตุคือ JS frontend framework ก็ได้แต่คิดว่า “อ๋อ ก็สมควรอยู่”
คนในวงการที่พยายามขายของอาจยอมรับได้ แต่สำหรับคนนอกวงการมันชวนงงมาก
ฉันคิดว่า Next เป็นกรณีที่พังตัวเองไปแล้ว
ที่ไหนก็ตามที่ผ่านวัฏจักร VC มักลงเอยแบบนี้
ตอนนี้ฉันใช้มันไม่ได้อีกแล้ว และ Vite กลายเป็นตัวเลือก default
ฉันชอบโซลูชันที่เบากว่าเสมอ
คำว่า “middleware” ใน Next.js ชวนให้เข้าใจผิดง่าย
จริง ๆ แล้วมันคือ edge function น้ำหนักเบาที่รันก่อน request จะไปถึงแอป (เช็ก header, routing, simple guard ฯลฯ)
มันรันบน edge runtime ซึ่งเป็นสภาพแวดล้อมแยกจาก app server
ดูเหมือนผู้เขียนเองก็สับสนระหว่าง edge กับ server runtime
ฉันเองตอนแรกก็สับสนกับเส้นแบ่งนี้เหมือนกัน และเพราะทุกอย่างเป็น JavaScript เลยทำให้ขอบเขตพร่าเลือน
ฉันคิดว่าจำเป็นต้องมี mental model ที่ชัดเจน
การโทษความซับซ้อนของ Next.js ก็เหมือนโทษกล่องเครื่องมือที่มีมากกว่าค้อนแค่อย่างเดียว
ปัญหาคือความซับซ้อนของ Next.js เป็นสิ่งที่มันก่อขึ้นเอง
คำว่า middleware มีความหมายที่ค่อนข้างชัดเจนในแทบทุก framework อยู่แล้ว
โดยทั่วไป middleware คือ chain ของฟังก์ชันที่ถูกเรียกก่อน request ใน runtime เดียวกันและอยู่ใน process เดียวกัน
แต่ Next.js กลับเอาไปผูกกับ edge และอนุญาตแค่ตัวเดียว
สำหรับแอปส่วนใหญ่ เราไม่จำเป็นต้องใช้ฟีเจอร์ edge เลย และควรต้องเป็นสิ่งที่ opt-in เมื่อต้องการจริง ๆ
ถ้าจะเปรียบกับกล่องเครื่องมือ ก็ควรเพิ่มเฉพาะเครื่องมือที่ต้องใช้จริง
ไม่ควรใช้คำว่า “middleware” ในบริบทนี้ของ Next.js
นี่ไม่ใช่แค่การใช้ผิด แต่เป็นการใช้คำแบบพร่ำเพรื่อ
middleware มีนิยามที่ใช้กันมานานในอุตสาหกรรมเว็บแอป ถ้าจะหมายถึงอย่างอื่นโดยสิ้นเชิง ก็ไม่ควรใช้คำนี้ตั้งแต่แรก
ฉันใช้ Next.js app router อยู่และค่อนข้างพอใจ
การสลับไปมาระหว่าง frontend กับ backend ใน Next.js ทำได้ง่ายมาก จนคนอาจเข้าใจผิดว่าส่วนนี้ถูก abstract ไว้หมดแล้ว
ในความเป็นจริงมันเป็นระบบที่ซับซ้อนมาก และคุณต้องรับมือกับความซับซ้อนนี้ด้วยตัวเอง
ความซับซ้อนที่สูงขึ้นไม่ได้แปลว่าจะช้าหรือไม่มีประสิทธิผลเสมอไป
ระบบที่แยก frontend กับ backend ออกจากกันชัดเจนจัดการง่ายกว่ามากก็จริง แต่ก็ยุ่งยากกว่าเช่นกัน
ถึงจะรู้ React แต่การเรียน Next.js ก็ยังเหมือนเริ่มใหม่หมด และมีหลายอย่างที่ไม่มีทางเข้าใจได้ถ้าไม่เจอเอง
แต่ถ้าคุ้นเคยได้ในระดับหนึ่ง มันก็เป็นระบบที่สะดวกมากในการข้ามไปมาระหว่าง frontend และ backend
มีคนกดไม่ชอบคอมเมนต์ของฉันเยอะมาก อยากรู้เหตุผลเหมือนกัน
ฉันพร้อมเรียนรู้อยู่เสมอ
ในการถกเถียงแบบนี้อยากให้คุยกันจริงจังมากกว่าปฏิเสธแบบไม่ลืมหูลืมตา
ในที่สุดก็ได้เห็นความเห็นที่มีเหตุผล
ยกตัวอย่าง ถ้าคุณสับสนเอาแนวคิด package/module ของ Python ไปปนกับแนวคิด module ของ Go แบบไม่คิดให้ดี แล้วบ่นว่า Go แย่ ก็คงประหลาด
ไม่ว่าจะใช้อะไร ก็ต้องมีความเข้าใจพื้นฐานในเทคโนโลยีนั้นก่อน
ตั้งแต่ Next.js เปลี่ยนมาใช้ app router ฉันรู้สึกเหมือนเอาการปรับปรุง express API ไปฝากไว้กับเด็กจบบูตแคมป์
ในเมื่อ server interface ทั้งหลาย เช่น servlet, rack, plug ฯลฯ ต่างก็ลงตัวกับการออกแบบแบบตุ๊กตารัสเซียที่สั่งสมกันมาหลายปี express API ก็ยังถือว่าเป็นแนวทางที่โตเต็มที่
นอกจาก middleware API ที่แย่มากแล้ว การเอา request parameter ออกแล้วแทนด้วยฟังก์ชัน global อย่าง
cookies()/headers()ก็เป็นการตัดสินใจที่ประหลาดอาจมีข้อจำกัดทางการออกแบบพื้นฐานบางอย่างซ่อนอยู่ แต่จากมุมคนนอก มันดูเหมือนโยนบทเรียนทั้งหมดที่ผ่านมาในอดีตทิ้ง แล้วกลับไปทำผิดซ้ำใหม่อีกครั้ง
และพอรวมกับการรองรับ edge runtime แบบ lowest common denominator (แบบที่ใช้ได้กว้างที่สุด) ข้อจำกัดก็ยิ่งหนักขึ้น
ฉันมักพยายามใช้ stack หลากหลายในโปรเจกต์ใหม่เสมอ
ทั้ง express+react, angular, vue, next, nuxt, go, .net, node, php ฯลฯ ใช้มาทั้งฝั่ง frontend และ backend
framework ส่วนใหญ่ฉันมักเห็นทั้งข้อดีข้อเสีย และก็สนุกกับการเรียนรู้ของใหม่
แต่ Next.js เป็นข้อยกเว้น ตอนทำแอปค่อนข้างใหญ่ ฉันรู้สึกว่าตั้งแต่ต้นจนจบ ทุกอย่างทั้งแปลก ช้า น่าอึดอัด หรือออกแบบมาแบบไร้เหตุผล
จนตอนนี้ยังต้องดูแลรักษาอยู่ และมันคือสิ่งเดียวที่ฉันเกลียดจริง ๆ
หลายคนบอกว่า ecosystem ดีและได้รับความนิยมมาก แต่จากประสบการณ์จริงของฉัน มันแย่แบบแก้กลับไม่ได้
มันแปลก แต่ก็เป็นความจริง
มีใครรู้ที่อยู่ไปรษณีย์ของ Vercel ไหม?
อีกไม่นาน issue นี้จะถึงวัยเข้าโรงเรียนประถมแล้ว ฉันเลยอยากส่งการ์ดไปอวยพรว่า “ขอให้มีชีวิตในโรงเรียนที่ดีนะ!” ให้บริษัทหน่อย
https://github.com/vercel/next.js/issues/10084
คำพูดในความเห็น Hacker News ด้านล่างนี่ตรงเผงเลย
"Next.js มีชั้น abstraction มหาศาลที่ไม่จำเป็นสำหรับ 99.9999% ของโปรเจกต์ และในกรณีส่วนน้อยที่จำเป็นต้องใช้ของแบบนี้จริง ๆ ผมคิดว่าทำโซลูชันแบบคัสตอมจากชิ้นส่วนระดับล่างจะดีกว่าเสียอีก"
API ที่ซับซ้อนเกินจำเป็นอย่างไร้สาระ, สภาพที่ทั้งไม่เสถียรและไม่สมบูรณ์แต่ก็ยังหน้าด้านโปรโมตว่า production ready, และการพึ่งพา vercel อย่างหนักจนถ้าไม่ใช้ vercel ก็แทบจะรันงานจริงจังได้ยาก