2 คะแนน โดย GN⁺ 6 일 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • HTMX คือแนวทางที่ยกระดับฟรอนต์เอนด์แบบค่อยเป็นค่อยไปโดยยึด HTML ที่เรนเดอร์จากเซิร์ฟเวอร์เป็นศูนย์กลาง และพัฒนาต่อจากวิธีการก่อนที่ JavaScript UI สมัยใหม่แบบ React จะขยายใหญ่เทอะทะ
  • ระหว่างรีแฟกเตอร์เซิร์ฟเวอร์ของ podcast web app ที่โฮสต์เอง เมื่อลองแทนที่ SvelteKit ด้วย DinoSsr ก็พบปัญหาว่าการย้ายหน้าทำให้การเล่นเสียงหยุดลง และสามารถใช้ HTMX อัปเดตเฉพาะส่วน `` เพื่อคงคอมโพเนนต์เสียงไว้ได้
  • แม้ HTMX จะถูกแจกจ่ายเป็นไลบรารีฝั่งฟรอนต์เอนด์ แต่ส่วนสำคัญของการติดตั้งใช้งานกลับอยู่ที่เทมเพลตฝั่งแบ็กเอนด์และการตั้งค่าเซิร์ฟเวอร์ โดยคำขอ HTTP ที่ส่งคืน HTML ทำหน้าที่เป็น HTMX API โดยพฤตินัย
  • ตัวอย่างขั้นสูงที่มีแอตทริบิวต์ hx-*, ตัวอย่าง `` ที่คลิกได้ และ inline JavaScript จำนวนมาก สะท้อนข้อจำกัดของ declarative attribute template และเป็นจุดที่ผู้เขียนไม่ค่อยพอใจในเอกสาร
  • มินิอิมพลีเมนเทชันที่ผู้เขียนทำเองใช้ 304 caching, History API, การแทนที่ `` และการพรีโหลดด้วย pointer events เป็นองค์ประกอบหลัก และทำให้ codebase เล็กลงกับเรียบง่ายขึ้นด้วยการลด JavaScript ในเบราว์เซอร์

ตำแหน่งของ HTMX

  • HTMX ปฏิเสธ JavaScript UI สมัยใหม่และเลือกใช้ HTML ที่เรนเดอร์จากเซิร์ฟเวอร์ โดยเป็นแนวทางที่ต่อยอดจากวิธีการก่อนที่ฟรอนต์เอนด์จะพองตัวจาก React
  • infinite scroll และผลการค้นหาแบบเรียลไทม์เป็นตัวอย่างยอดนิยมของ HTMX และแม้ HTMX จะดูมีขอบเขตจำกัด ไม่ได้พยายามแก้ทุกปัญหาแบบที่ React และเครื่องมือคล้ายกันทำ แต่ภายในข้อจำกัดนั้นมันก็มีคุณค่าสูง
  • HTMX ไม่ใช่ “magic bullet” และประเด็นสำคัญคือมุมมองที่ว่าแนวคิดบางอย่างเบื้องหลัง HTMX สำคัญกว่าตัว HTMX เอง

การทดลอง

  • แค่อ่านเอกสารยังไม่พอ จึงลองใช้งานจริง และงานรีแฟกเตอร์เซิร์ฟเวอร์ของ podcast web app ที่โฮสต์เองก็เป็นเป้าหมายสำหรับการนำ HTMX มาใช้
  • อิมพลีเมนเทชันเดิมใช้ SvelteKit ซึ่งแม้จะเป็นเครื่องมือที่ชอบ แต่ก็อาจหนักเกินไปสำหรับเว็บไซต์ขนาดเล็ก
  • สิ่งที่นำมาแทนคือ DinoSsr ที่ผู้เขียนกำลังสร้างเอง และโปรเจกต์เดียวกันนี้ยังใช้สำหรับสร้าง static site และให้บริการบล็อกบุ๊กมาร์กด้วย
  • DinoSsr ทำงานฝั่งเซิร์ฟเวอร์เป็นหลัก และแม้จะส่งมอบคอมโพเนนต์แบบฟรอนต์เอนด์ “islands” ได้ แต่โครงสร้างนี้ไม่ได้รองรับปฏิสัมพันธ์ระดับทั้งหน้า
  • คอมโพเนนต์เครื่องเล่นเสียงต้องคงอยู่ระหว่างการย้ายหน้า และหากการย้ายหน้าทำให้ทั้งหน้าโหลดใหม่ ประสบการณ์การเล่นก็จะจบลงอย่างรวดเร็ว
  • SvelteKit จัดการทั้งการอัปเดต UI และฟรอนต์เอนด์ routing แต่ในบิลด์ใหม่มีเพียงคอมโพเนนต์เครื่องเล่นเสียงเท่านั้นที่ใช้ JavaScript ฝั่งฟรอนต์เอนด์ และ DinoSsr ก็จงใจไม่พยายามทำ client-side routing
  • บางหน้ามีเพียงส่วน `` ที่ต่างกัน ดังนั้นถ้าใช้ HTMX ยกระดับลิงก์แบบค่อยเป็นค่อยไปแล้วอัปเดตเฉพาะบริเวณนี้ ก็จะคงคอมโพเนนต์เสียงไว้ได้โดยไม่ต้องโหลดทั้งหน้าใหม่
  • การใช้ HTMX ให้ผลลัพธ์ที่ดี แต่ไม่นานก็ถอด HTMX ออกแล้วเปลี่ยนเป็นเวอร์ชันมินิที่ทำเองจากแนวคิดเดียวกัน

ความเห็นบางอย่างเกี่ยวกับ HTMX

  • ในการทดลองนี้ HTMX เป็นตัวแทนของ Svelte ฝั่งฟรอนต์เอนด์ แต่ไม่ใช่ตัวแทนแบบเสียบแทนได้ทันทีเหมือน React หากเป็นการเปลี่ยนวิธีคิดครั้งใหญ่
  • HTMX ถูกแจกจ่ายเป็นไลบรารี JavaScript ที่ยกระดับฟรอนต์เอนด์แบบค่อยเป็นค่อยไป แต่การติดตั้งใช้งานส่วนใหญ่เกิดขึ้นที่แบ็กเอนด์ โดยต้องเตรียมเทมเพลตและการตั้งค่าเซิร์ฟเวอร์เอง
  • คำขอ HTTP ที่ส่ง HTML กลับมาทำหน้าที่เป็น HTMX API โดยพฤตินัย และรายละเอียดอย่างการตั้งค่า HTTP headers ให้ถูกต้องเพื่อการแคชที่เหมาะสมก็สำคัญมาก
  • แม้จะมีแอตทริบิวต์มาตรฐาน data-* และ dataset อยู่แล้ว แต่การใช้แอตทริบิวต์พรีฟิกซ์ hx-* ที่ไม่ใช่มาตรฐานก็เป็นจุดขัดใจเล็กน้อย
  • เอกสารของ HTMX มีตัวอย่าง `` จำนวนมาก และตัวอย่างด้านล่างคือโครงสร้างที่เมื่อผู้ใช้คลิก div จะส่งคำขอ PUT ไปที่ /messages และโหลดผลลัพธ์กลับเข้า div นั้น

    Put To Messages

  • มีคำวิจารณ์ว่าตัวอย่างที่ให้ผู้ใช้ต้องคลิกองค์ประกอบ `` นั้นไม่ใช่แนวทางที่พึงประสงค์
  • ตัวอย่าง HTMX ขั้นสูงบางส่วนที่ใช้ inline JavaScript ก็ดูรกพอสมควร และแสดงให้เห็นข้อจำกัดของ declarative attribute template
  • แม้จะมีข้อวิจารณ์เหล่านี้ HTMX ก็ยังมอบชุดความสามารถที่มีขอบเขตจำกัดแต่มีประโยชน์ และเป็นเครื่องมือที่ช่วยยกระดับแพตเทิร์นการออกแบบเว็บทั่วไปได้หลายแบบ

สร้างเอง

  • หลังเพิ่ม HTMX ได้สำเร็จก็ถอดมันออกทันที แล้วทำเวอร์ชันมินิของตัวเองจากแนวคิดเดียวกัน
  • เพื่อให้คำขอ fetch ที่แคชได้ทำงานได้ จึงใช้ HTTP headers last-modified, if-modified-since และการตอบกลับ 304
  • สำหรับการผสานกับ history พื้นฐาน ใช้ pushState และ popstate
  • มีการเพิ่มโค้ดสำหรับดึงและแทนที่องค์ประกอบ `` และฝังการพรีโหลดแบบ pointer events โดยได้รับแรงบันดาลใจจาก HTMX preload extension
  • การพรีโหลดแบบ pointer events จะเริ่มคำขอ fetch ก่อนที่เหตุการณ์ click จะเกิดขึ้น ทำให้ได้การปรับปรุงด้านประสิทธิภาพเล็กน้อย
  • ซอร์สโค้ด สำหรับการทดลองนี้ยังพื้นฐานมาก แต่ก็แสดงให้เห็นว่า JavaScript ที่จำเป็นจริง ๆ ในเบราว์เซอร์มีน้อยเพียงใด
  • ไม่ว่าจะใช้ HTMX หรือแนวทาง “we have HTMX at home” ผลลัพธ์คือ codebase เล็กลงและเรียบง่ายขึ้นมาก

JavaScript ฝั่งฟรอนต์เอนด์

  • เทมเพลตและคอมโพเนนต์เป็นสิ่งจำเป็นในทางปฏิบัติสำหรับการจัดระเบียบโค้ดและการนำกลับมาใช้ใหม่ เว้นแต่จะเป็นเว็บไซต์ที่เล็กมาก และสามารถทำฝั่งเซิร์ฟเวอร์ได้ด้วย PHP, Ruby, Go, JavaScript และอื่น ๆ
  • ไม่จำเป็นต้องทำซ้ำโครงสร้างนี้ในเบราว์เซอร์ หรือทำมันเฉพาะในเบราว์เซอร์เท่านั้น แต่ความนิยมของ React และเครื่องมือคล้ายกันทำให้นักพัฒนาจำนวนมากเลิกตั้งคำถามนี้ไปแล้ว
  • ความเหนื่อยล้าจาก JavaScript ฝั่งฟรอนต์เอนด์เป็นเรื่องจริง และสัมพันธ์กับประสบการณ์ที่แม้จะชอบเทมเพลตฝั่งเซิร์ฟเวอร์แบบเก่า แต่ก็ยังออกแบบ JS UI เกินความจำเป็นมาโดยตลอด
  • ถึงจะมองว่า HTMX เองไม่ได้ยอดเยี่ยมมากนัก ปรัชญาของมันก็ยังเป็นแนวทางที่มีคุณค่ามากพอจะทำให้นักพัฒนา JavaScript สมัยใหม่ต้องอายได้

1 ความคิดเห็น

 
GN⁺ 6 일 전
ความเห็นจาก Lobste.rs
  • เป็นการจับผิดเล็ก ๆ น้อย ๆ แต่ผมไม่ค่อยชอบที่ใช้แอตทริบิวต์ HTML แบบมีคำนำหน้า hx-* ในจุดที่ควรใช้ data-* Htmx รองรับคำนำหน้า data- มานานแล้ว ถ้าประเด็นคือไม่ควรทำให้ผู้ใช้ต้องคลิก `` ก็การใช้ hx-boost ของ htmx กับแท็ก anchor และ form น่าจะดีที่สุด เพราะมันช่วยเสริมความสามารถให้แท็กพวกนี้อย่างถูกวิธีโดยอัตโนมัติ จึงหลีกเลี่ยงการใช้ div ที่คลิกได้ นี่เป็นโปรเจกต์ที่แสดงให้เห็นว่าเบราว์เซอร์ต้องการ JavaScript จริง ๆ น้อยแค่ไหน และต่อจากนี้การบำรุงรักษาก็น่าจะมีน้อยมาก รวมถึงแทบไม่ต้องมีแพตช์ความปลอดภัยเลยด้วย น่ายินดีด้วย

  • HTMX เรนเดอร์ทุกอย่าง แบบนี้ไม่ได้ทำให้เซิร์ฟเวอร์ทำงานหนักเกินไปหรือ? ให้ความรู้สึกคล้าย ปัญหา CGI ที่เราเคยเจอเมื่อก่อน

    • เกือบจะแน่นอนว่าไม่ใช่ ปัญหาของ CGI หลัก ๆ คือค่าใช้จ่ายจากการสปินโปรเซสอายุสั้นจำนวนมาก ซึ่งแก้ได้ด้วย FastCGI และอย่างอื่น การสร้าง HTML ไม่ใช่งานที่แพงเป็นพิเศษ และก็ยากจะบอกว่าแพงกว่าการสร้าง JSON ปริมาณพอ ๆ กันในแนวทางทางเลือก
    • ไม่เข้าใจว่าคำว่า “เรา” หมายถึงใคร บล็อก ของผมใช้ CGI, ให้เซิร์ฟเวอร์เรนเดอร์ HTML และไม่มี JavaScript เลย ตั้งแต่ปี 1999 ก็ไม่มีปัญหาอะไร และตามปกติแล้วต้องดูด้วย profiling ว่าคอขวดจริงอยู่ตรงไหน
    • ปกติเราเรียกสิ่งนี้ว่า server-side rendering แต่จริง ๆ แล้วมันใกล้เคียงกับการให้เซิร์ฟเวอร์สร้าง HTML ดิบมากกว่า การเรนเดอร์จริงและการสร้าง DOM ก็ยังเป็นหน้าที่ของเบราว์เซอร์อยู่ดี และก็เป็นแบบนั้นมาตลอด ต่อให้จะนับ PHP รวมอยู่ในหมวด CGI ด้วย ก็ดูเหมือนกำลังข้ามช่วงราวสิบห้าปีของการพัฒนาเว็บที่วิธีแบบนี้เคยเป็นเรื่องปกติไป จริงอยู่ว่านี่ทำให้เซิร์ฟเวอร์ต้องทำงานมากขึ้น แต่ผมมองว่าเหตุผลหลักที่ย้ายงานจำนวนมากไปฝั่งไคลเอนต์ตลอดหลายปีที่ผ่านมา เป็นความเสี่ยงที่คำนวณมาแล้วเพื่อประหยัดต้นทุน ผู้ใช้ปลายทางจำนวนมากอาจไม่ทันสังเกตว่าเบราว์เซอร์ต้องทำงานมากขึ้น แต่บนอุปกรณ์เก่าหรือประสิทธิภาพต่ำ ประสบการณ์ก็แย่ลงมาตลอด โดยเฉพาะช่วงเริ่มต้น อย่างไรก็ตาม HTMX ก็ไม่เหมือน SSR แบบเต็มรูปแบบเสียทีเดียว แทนที่ API จะส่งข้อมูลเป็น JSON แล้วให้ไคลเอนต์เรนเดอร์เป็น HTML มันคือให้เซิร์ฟเวอร์ส่งข้อมูลเดียวกันมาเป็น ชิ้นส่วน HTML แทน ถึงอย่างนั้น ถ้าเซิร์ฟเวอร์โดนใช้งานหนัก ก็มีแนวโน้มว่าไม่ได้เป็นเพราะมันใช้ทรัพยากรมากกว่า REST API โดยเนื้อแท้ แต่เป็นเพราะปัจจัยอื่นมากกว่า
    • ถ้าไม่มีเบนช์มาร์กก็คงฟันธงยาก แต่ก็น่าจะใกล้เคียงกัน เพราะสุดท้ายทั้งสองกรณีก็คือการปล่อยก้อนข้อความออกมา ความต่างอยู่ที่ว่าการเรนเดอร์ข้อความแพงกว่าหรือการสร้าง JSON แพงกว่ากัน จากประสบการณ์ของผม เวลาทำงานกับ JSON เรามักจะซีเรียลไลซ์อะไรเยอะกว่า แต่ผมก็ไม่แน่ใจว่าจะเทียบกันอย่างเหมาะสมยังไง
    • ในแอปพลิเคชันฝั่งเซิร์ฟเวอร์ แทบไม่เคยมีกรณีที่ขั้นตอน เรนเดอร์ HTML เองเป็นคอขวด โดยปกติคอขวดมักอยู่ก่อนหน้านั้น
  • ด้วยเหตุผลคล้ายกัน ผมใช้ alpine-ajax ซึ่งคล้าย htmx มาก

    • ผมก็ชอบ alpine-ajax มากเหมือนกัน ถ้าจะเริ่มใหม่โดยมีโจทย์ว่า “เอาข้อดีของ SPA มาไว้บน SSR” ก็คงจะเลือกทางนั้น ยังไงเสียผมก็ใช้ alpine อยู่แล้วสำหรับฟีเจอร์ฝั่งไคลเอนต์แบบโต้ตอบได้ เพียงแต่ตอนนี้ในรีโพซิทอรีมี htmx อยู่เยอะแล้ว และผมก็ไม่ได้มีอะไรคาใจกับ htmx
    • ผมใช้ datastar อยู่ และมันก็ทำงานได้ราบรื่นดีทีเดียว