• หลายคนพูดถึง htmx ราวกับว่ามันจะมากอบกู้เว็บจาก SPA
  • Carson Gross ผู้สร้าง htmx อธิบายพลวัตนี้อย่างมีอารมณ์ขันว่าเป็น "วิภาษวิธีของเฮเกล":
    • ปฏิพจน์ (thesis): MPA แบบดั้งเดิม
    • ปฏิปักษ์ (antithesis): SPA
    • สังเคราะห์ (synthesis): แอปพลิเคชันที่ประกอบด้วย interactive islands บนพื้นฐานของ hypermedia
  • แต่ผมมองไม่เห็นภาพนั้น และก่อนหน้านี้ก็เคย "สร้าง SPA ด้วย htmx"
  • นี่เป็น PoC ของแอป ToDo list แบบง่าย ๆ
    • เมื่อหน้าโหลดเสร็จแล้ว จะไม่สื่อสารกับเซิร์ฟเวอร์อีกต่อไป
    • ทุกอย่างถูกประมวลผลแบบโลคัลบนฝั่งไคลเอนต์
    • ถ้า htmx โฟกัสที่การจัดการการแลกเปลี่ยน hypermedia ผ่านเครือข่าย แล้วสิ่งนี้ทำงานได้อย่างไร?
    • มีทริกง่าย ๆ อยู่ข้อหนึ่ง: โค้ด "ฝั่งเซิร์ฟเวอร์" ทำงานอยู่ใน Service Worker

Service Worker

  • ทำหน้าที่เป็นพร็อกซีระหว่างเว็บเพจกับอินเทอร์เน็ต
  • สามารถดักจับและปรับแต่งคำขอเครือข่ายได้
  • แก้ไขคำขอ, แคชการตอบสนองสำหรับออฟไลน์, และสร้างการตอบสนองใหม่ได้โดยไม่ต้องส่งคำขอออกนอกเบราว์เซอร์
  • ความสามารถข้อสุดท้ายนี่เองคือแกนหลักของ single-page app นี้
  • เมื่อ htmx ส่งคำขอเครือข่าย Service Worker จะดักจับไว้
  • จากนั้น Service Worker จะรัน business logic และสร้าง HTML ใหม่
  • htmx จะสลับ HTML ใหม่เข้าไปใน DOM

ข้อดีเมื่อเทียบกับ SPA แบบเดิม

  • Service Worker จำเป็นต้องใช้ IndexedDB เป็นสตอเรจ
  • นั่นทำให้สถานะคงอยู่ข้ามการโหลดหน้าได้
  • ปิดหน้าไปแล้วกลับมาใหม่ แอปก็ยังจำข้อมูลได้
  • นี่เป็นผลดีที่ได้มาแบบ "ฟรี" จากการเลือกสถาปัตยกรรมนี้
  • ทำให้รองรับการทำงานแบบออฟไลน์ได้ง่าย

ข้อเสีย

  • การรองรับในเครื่องมือนักพัฒนาแย่
    • console.log หลุดหายเป็นบางครั้ง
    • การรายงานว่า Service Worker ถูกติดตั้งหรือไม่นั้นเชื่อถือไม่ได้
  • Firefox ยังไม่รองรับ ES modules
    • ต้องรวมโค้ดทั้งหมดไว้ในไฟล์เดียว
  • ประสบการณ์การพัฒนาโดยรวม "ไม่สนุก"

ถึงอย่างนั้น htmx SPA ก็ทำงานได้ดี


รายละเอียดการใช้งานจริง

  • HTML พื้นฐานเป็นโครงว่างเปล่าของ single-page app
  • แท็ก <body> ใช้ htmx เพื่อตั้งค่าตัวแอปหลัก
    • hx-boost="true": สั่งให้ htmx แทนที่ผลลัพธ์ของการคลิกลิงก์และการส่งฟอร์มด้วย Ajax โดยไม่ต้องนำทางทั้งหน้า
    • hx-push-url="false": ทำให้ htmx ไม่เปลี่ยน URL ตามการคลิกลิงก์และการส่งฟอร์ม
    • hx-get="./ui": สั่งให้ดึงหน้าเว็บจาก /ui มาแทนที่เมื่อหน้าโหลด
    • hx-target="body": สั่งให้แทนที่ผลลัพธ์ลงในองค์ประกอบ <body>
    • hx-trigger="load": สั่งให้ทำทั้งหมดนี้เมื่อหน้าโหลด

เอนด์พอยต์ /ui

  • ส่งคืนมาร์กอัปจริงของแอป
  • หลังจากนั้น htmx จะควบคุมลิงก์และฟอร์มเพื่อทำให้เกิดการโต้ตอบ
  • Service Worker จัดการ routing ของคำขอด้วยไลบรารีสไตล์ Express
    • setFilter และ listTodos เป็นฟังก์ชันง่าย ๆ ที่ครอบ IDB Keyval ไว้
    • คอมโพเนนต์ App ประกอบด้วยฟอร์มตัวกรอง รายการงาน และฟอร์มเพิ่มงาน

เอนด์พอยต์ /todos/add

  • หลังบันทึกงานแล้ว จะส่งคืนการตอบสนองที่ re-render UI ใหม่
  • htmx จะสลับการตอบสนองนั้นเข้าไปใน DOM

คอมโพเนนต์ Todo

  • ประกอบด้วยเช็กบ็อกซ์ ปุ่มลบ และข้อความของงาน
  • เช็กบ็อกซ์จะทริกเกอร์คำขอไปที่ /todos/${id}/update
  • ปุ่มลบจะทริกเกอร์คำขอลบไปที่ /todos/${id}
  • ข้อความของงานมีสองสถานะคือ "normal" และ "editing"
    • htmx รอฟังเหตุการณ์ดับเบิลคลิก
    • ส่งคำขอไปที่ /ui/todos/${id}?editable=true
    • Service Worker จะส่งคืน HTML ของ Todo ที่มี <input> อยู่ภายใน
    • htmx จะแทนที่รายการงานปัจจุบันด้วย HTML จากการตอบสนอง

สรุป

  • ในเชิงเทคนิค มันใช้งานได้
  • แต่มันเป็นความคิดที่ดีไหม? เป็นจุดสูงสุดของแอปแบบ hypermedia จริงหรือ? ควรทิ้ง React แล้วมาสร้างแบบนี้หรือเปล่า?
  • สำหรับแอปที่เป็นโลคัลทั้งหมด ความอ้อมของ htmx ให้ความรู้สึกเป็นภาระมากกว่าความปลดปล่อย
  • แอปส่วนใหญ่ไม่ได้เป็นโลคัลทั้งหมด
  • มองว่าแพตเทิร์น "interactive islands" ดีกว่าการแยกโค้ด "ฝั่งเซิร์ฟเวอร์" ออกเป็น Service Worker กับเซิร์ฟเวอร์จริง
  • นี่เป็นความพยายามเชิงทดลองเพื่อแสดงให้เห็นว่าสามารถสร้าง single-page app แบบโลคัลทั้งหมดด้วย hypermedia ได้

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น