1 คะแนน โดย GN⁺ 2023-10-27 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • หากต้องการดูแลเดโมแบบอินเทอร์แอคทีฟของบทเรียน CRDT ให้เป็น คอนเทนต์ที่คงอยู่ได้นาน Web Components ที่ใส่ลงใน HTML ได้โดยตรงจะเหมาะกว่าการใช้ framework เฉพาะ
  • คอมโพเนนต์ MDX ของ Astro ให้ความสะดวกอย่างระบบ build, scope ของ CSS และ TypeScript แต่หาก ย้ายออกจาก Astro อาจมีต้นทุนในการเขียนใหม่
  • Web Components สามารถใส่ custom tag อย่าง <pixelart-demo></pixelart-demo> ลงใน Markdown และเมื่อโหลดสคริปต์แล้ว ก็สามารถ นำกลับมาใช้ซ้ำตาม tag ได้ทุกที่ในหน้า
  • Framework และ TypeScript ก็เป็น dependency เช่นกัน จึงมีการสะสมของการเปลี่ยนแปลงด้าน version, API และ compatibility และโค้ดที่ถูกปล่อยทิ้งไว้นานจะกู้คืนได้ยากขึ้น ยิ่งมี dependency มาก
  • Web Platform มีความเสถียรพอที่เว็บไซต์เก่ายังทำงานได้บน browser สมัยใหม่ ดังนั้นงานที่ต้องการให้เข้าถึงได้ในอีก 5, 10 หรือ 20 ปีข้างหน้า แนวทางแบบ อิงมาตรฐาน จะได้เปรียบกว่า

เก็บรักษาเดโมแบบอินเทอร์แอคทีฟให้เหมือนคอนเทนต์

  • ซีรีส์บล็อก CRDT ต้องการ เดโมแบบอินเทอร์แอคทีฟ เพื่อแสดงแนวคิด และใช้ editor สำหรับ collaborative pixel art เป็นตัวอย่าง
  • เกณฑ์ในการเลือกเทคโนโลยีคือ แม้เดโมจะสร้างด้วย HTML, CSS และ JS แต่ก็ใกล้เคียงกับ คอนเทนต์ ที่ถูกฝังอยู่ในบทความบล็อก
    • คล้ายกับสิ่งที่แทรกในบทความ เช่น รูปภาพหรือวิดีโอ
    • ควรย้ายไปที่ไหนก็ได้ที่สามารถ render HTML ได้
  • เว็บไซต์นี้สร้างด้วย Astro ณ ปี 2023 แต่ก่อนหน้านั้นเคยผ่าน static site generator ที่ทำเอง, Hugo, PHP custom CMS, Tumblr, Movable Type, WordPress และอื่น ๆ
  • แม้ตอนนี้จะชอบ Astro แต่ก็ยากที่จะสมมติว่าเว็บไซต์จะรันอยู่บน Astro ตลอดไป

Markdown ช่วยลดต้นทุนการ migration อย่างไร

  • เหตุผลที่การ migration ล่าสุดทำได้ง่ายคือการเก็บคอนเทนต์ไว้เป็น ไฟล์ข้อความธรรมดา Markdown
  • งานที่มักต้องทำเมื่อต้องย้ายระบบจึงลดลง
    • export จากระบบหนึ่งแล้ว import ไปยังอีกระบบหนึ่ง
    • แก้ปัญหา compatibility
    • ลบองค์ประกอบที่หาวิธีย้ายไม่ได้
  • เมื่อนำไฟล์ Markdown ไปใส่ในเว็บไซต์ใหม่ ส่วนใหญ่ก็ทำงานได้เหมือนเดิม
  • Markdown สามารถเขียน HTML ได้โดยตรง ดังนั้นหาก diagram แบบอินเทอร์แอคทีฟที่ซับซ้อนสามารถแสดงเป็น tag HTML ทั่วไป ได้ ก็จะย้ายได้เหมือนคอนเทนต์ส่วนอื่น

ความสะดวกของ Astro MDX และข้อจำกัดด้านการย้าย

  • การผสาน MDX ของ Astro ทำให้สามารถ render คอมโพเนนต์ Astro ภายใน Markdown ได้
  • คอมโพเนนต์ Astro ใช้ความสะดวกหลายอย่างจากระบบ build ได้
    • เขียน HTML, CSS, JS ในไฟล์เดียว
    • จัดการ scope ของ selector ใน CSS
    • compile TypeScript
    • render markup แบบมีเงื่อนไข
    • optimization อื่น ๆ
  • ปัญหาคือความสะดวกทั้งหมดนี้ทำงานได้อย่างเสถียร เฉพาะภายใน Astro เท่านั้น
  • หากย้ายไปยัง site generator อื่น อาจต้องเขียนคอมโพเนนต์ใหม่
    • อาจต้องแยก HTML, CSS และ JS ออกจากกัน
    • อาจต้องตั้งค่าระบบ build ใหม่
    • อาจต้องหาวิธีจัดการ scope ของ style ใหม่
  • ดังนั้นแม้ฟีเจอร์เฉพาะของ Astro จะสะดวก แต่ก็กลายเป็นตัวเลือกที่ไม่เหมาะกับเดโมที่ต้องการเก็บรักษาระยะยาว

สิ่งที่ Web Components ช่วยแก้ได้

  • Web Components คือชุด เทคโนโลยีมาตรฐานเว็บ สำหรับสร้างองค์ประกอบ HTML ที่นำกลับมาใช้ซ้ำได้
  • วิธีใช้งานคือเขียน class ของ custom element, ลงทะเบียนชื่อ tag แล้วใช้ tag นั้นใน markup
  • เดโม pixel art ถูกฝังใน Markdown ด้วย HTML ต่อไปนี้เท่านั้น
<pixelart-demo></pixelart-demo>
  • ไม่ต้องมีการตั้งค่าพิเศษหรือขั้นตอนที่ต้องวางองค์ประกอบบางอย่างไว้ก่อนแล้วค่อยเรียก function
  • ยังต้องเก็บไฟล์ JS และเชื่อมด้วย tag <script> แต่ในแง่ที่ต้องมีวิธีอ้างอิง media จากในคอนเทนต์ข้อความ ก็เหมือนกับ media อื่น ๆ
  • เมื่อโหลดสคริปต์แล้ว ชื่อ tag จะถูกลงทะเบียน และแม้ markup จะมีอยู่ก่อนที่ JavaScript จะเริ่มทำงาน ก็ใช้งานได้ทุกที่ในหน้า

โครงสร้างไฟล์เดียวและ Shadow DOM

  • Web Components สามารถ encapsulate HTML, CSS และ JS ไว้ ในไฟล์เดียว ได้ และไม่ต้องใช้ระบบ build แยกต่างหาก
  • เมื่อโค้ดคอมโพเนนต์รวมอยู่ในที่เดียว ภาระทางความคิดจะลดลง และ single-file component ก็มีข้อดีในแง่ developer experience ด้วย
  • คอมโพเนนต์ตัวอย่าง <pixelart-demo> สืบทอดจาก HTMLElement และแนบ Shadow DOM ด้วย attachShadow({ mode: "closed" }) จากนั้นจึง render markup และ style ภายใน
  • import PixelEditor from "./PixelEditor.js"; ที่ด้านบนของไฟล์เป็น ES module import จึงไม่พึ่งพาระบบ build แยกต่างหาก
  • หากเก็บไฟล์ที่เกี่ยวข้องไว้ด้วยกัน browser จะจัดการ module ให้
  • Shadow DOM แยกคอมโพเนนต์ออกจากหน้ารอบข้าง
    • อาจรู้สึกไม่ลงตัวเมื่อจำเป็นต้องแชร์ style กับทั้งแอป
    • เหมาะกับกรณีที่ต้องแยกออกจากกันโดยสมบูรณ์
    • สามารถคงรูปลักษณ์และพฤติกรรมเดิมได้ไม่ว่าจะนำไปใช้ที่ไหน เหมือนรูปภาพหรือวิดีโอ

รับการตั้งค่าภายนอกผ่าน attribute

  • Web Components สามารถเปิดเผย attribute ที่ตั้งค่าจากภายนอกได้
  • attribute ใช้งานได้เหมือน attribute แบบ native
  • ตัวแปร CSS เป็นหนึ่งในค่าไม่กี่ประเภทที่เข้าไปใน Shadow DOM ได้ ดังนั้นตัวอย่าง range slider จึงตั้งค่าสี accent ดังนี้
<range-slider style="--accent: #0085F2"></range-slider>
  • เดโม pixel art เปลี่ยนความละเอียดเป็น 20 และแสดงข้อมูล debug ของแต่ละ pixel ผ่าน attribute
<pixelart-demo debug resolution="20"></pixelart-demo>
  • การเรียก getAttribute และ hasAttribute ใน class ของคอมโพเนนต์ใช้สำหรับอ่านค่า attribute เหล่านี้
  • สิ่งนี้มีประโยชน์ในการนำคอมโพเนนต์เดียวกันกลับมาใช้ซ้ำในหลายขั้นตอนของบทเรียน พร้อมเปิดใช้ฟีเจอร์บางอย่างตามขั้นตอนความคืบหน้า

Framework และ TypeScript ก็เป็น dependency

  • มีเครื่องมืออย่าง Lit, Stencil, Svelte ที่ compile เป็น Web Components ได้ แต่สุดท้าย framework ก็คือ dependency
  • trade-off ที่น่ากังวลที่สุดในที่นี้คือต้นทุนการดูแลระยะยาว
  • TypeScript ก็ไม่ใช่ฐาน native ของเว็บ จึงถือเป็น dependency เช่นกัน
  • TypeScript 15 version ล่าสุดมี breaking change และแม้การเปลี่ยนแปลงจำนวนมากจะเป็นฟีเจอร์ใหม่ที่มีประโยชน์ แต่ก็ต้องแก้โค้ด
  • เมื่อใช้ dependency ก็จะมีต้นทุนจาก release version ใหม่, การเปลี่ยน API และการตรวจสอบ compatibility ตามมา
  • โค้ดนี้ไม่ได้มีแผนจะเข้าไปแก้ต่อเนื่อง ดังนั้นในอนาคตหากจำเป็นต้องแก้จริง ๆ ก็ไม่อยากต้องจัดการ update หลายปีในคราวเดียว

ประสบการณ์กู้คืนเว็บไซต์เก่าและความเสถียรของ Web Platform

  • ระหว่างสร้างพิพิธภัณฑ์ออนไลน์ มีการกู้คืนโค้ดเก่าที่เก็บไว้ใน laptop ที่ไม่ได้เปิดมา 10 ปี และพบว่า ยิ่งเว็บไซต์มี dependency มาก ก็ยิ่งทำให้กลับมาทำงานได้ยาก
  • ตลอดราว 20 ปีที่ทำเว็บ ได้เห็นการเกิด การเติบโต และการเสื่อมความนิยมของ jQuery รวมถึงการกำเนิดของ Node.js และการ fork เป็น io.js แล้ว merge กลับ
  • Backbone ถูกแทนที่อย่างรวดเร็วด้วย AngularJS, AngularJS ถูกแทนที่ด้วย React และ React เองก็ผ่านวิธีเขียนคอมโพเนนต์หลายแบบในช่วงเวลาประมาณครึ่งหนึ่งของนั้น
  • ขณะที่ ecosystem เปลี่ยนไป Web Platform เองก็เปลี่ยนแปลงอย่างระมัดระวังเพื่อไม่ให้เว็บไซต์เดิมพัง จึงคง ความเสถียรค่อนข้างสูง ไว้ได้
  • เว็บไซต์เก่าก็ยังทำงานบน browser สมัยใหม่
  • หากต้องการงานที่ยังเข้าถึงได้ในอีก 5, 10 หรือ 20 ปีข้างหน้า การลด dependency ที่ควบคุมไม่ได้ และยึดกับ มาตรฐานเว็บ ที่มีโอกาสพังน้อยกว่า จะเหมาะสมกว่า
  • แม้เว็บจะมีข้อบกพร่อง แต่เมื่อสร้างโดยคำนึงถึงคุณลักษณะของมันโดยไม่พึ่ง layer ตรงกลาง เว็บก็กลายเป็นแพลตฟอร์มคอมพิวติ้งที่ยืดหยุ่น ย้ายได้ และมองไปข้างหน้า

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

 
GN⁺ 2023-10-27
ความเห็นจาก Hacker News
  • htmx ไม่ใช่เฟรมเวิร์กแต่เป็น ไลบรารี และเมื่อบทความพูดถึงมันไว้ จึงอยากตอบบางประเด็น
    อย่างแรก บทความไม่ได้พูดถึงปัญหาการซิงก์เซิร์ฟเวอร์กับสถานะ แต่ htmx มุ่งเน้นปัญหานี้โดยตรงผ่านการแลกเปลี่ยนแบบไฮเปอร์มีเดีย ดังนั้นในมุมนี้ htmx กับ Web Components จึงเป็นสิ่งที่ตั้งฉากกัน
    การมี dependency มักมาพร้อมเวอร์ชันใหม่ การเปลี่ยน API และต้นทุนในการรักษาความเข้ากันได้ ดังนั้น htmx จึงไม่มี dependency และให้ความสำคัญกับ ความเข้ากันได้ย้อนหลัง อย่างมาก ตัวอย่างเช่น มันรองรับ IE11 และ intercooler.js ซึ่งเทียบได้กับ htmx 1.0 เปิดตัวในปี 2013 โดยมี dependency เพียง jQuery ตัวเดียว และยังคงได้รับการสนับสนุนอยู่
    ไลบรารี JavaScript จำนวนมากมีวัฒนธรรมของการเขียน API ใหม่และการอัปเกรดที่ยุ่งยาก แต่ htmx ประกาศชัดว่าไม่เป็นแบบนั้น และไม่ควรถูกเหมารวมไปกับกรณีทั่วไปเหล่านั้น การเปลี่ยนแบบ breaking change เพียงอย่างเดียวของ htmx 2.0 อาจเป็นแค่การเลิกรองรับ IE
    Web Components น่าจะอยู่ได้นานกว่า htmx เพราะเป็นส่วนหนึ่งของเบราว์เซอร์ แต่เท่าที่ทำได้ htmx จะยังคงเสถียรมากและเปลี่ยนแปลงน้อยต่อไป API ของมันโดยพื้นฐานมาถูกทางแล้ว และไม่จำเป็นต้องเขียนทุกอย่างใหม่เพียงเพื่อความบริสุทธิ์หรือความเท่
    ที่สำคัญที่สุด htmx ตอบคำถามคนละข้อกับ Web Components นั่นคือ จะซิงก์เซิร์ฟเวอร์กับสถานะอย่างไร

    • ที่บริษัทเราแทนที่ React ด้วย Htmx มาได้ราว 1 ปีแล้ว และ Web Components มีประโยชน์มากในการนำ React คอมโพเนนต์ที่อยากเก็บไว้กลับมาใช้ซ้ำเหมือนเป็นวิดเจ็ตของเบราว์เซอร์แบบเนทีฟ
      เมื่อใช้ WebComponent ก็สามารถผูกเข้ากับ lifecycle ของ DOM element ที่ถูกแก้ไขจากภายนอกได้แบบเดียวกับ morphdom ของ Htmx หากแอตทริบิวต์เปลี่ยน ก็ต้องแจ้งให้ React คอมโพเนนต์รู้ และถ้าโหนดถูกลบออกจาก DOM ก็ต้องแจ้งให้ React รันขั้นตอน cleanup หากไม่มี WebComponents ก็มองว่ายากที่จะทำสิ่งนี้ได้อย่างสะอาดและมีประสิทธิภาพ
      ผลลัพธ์คือเรายังสามารถอยู่กับแนวทางของ Htmx ที่เก็บสถานะของ business logic ทั้งหมดไว้บนเซิร์ฟเวอร์ และเก็บไว้ฝั่งไคลเอนต์เพียงส่วนน้อยแบบอนุรักษ์นิยม เช่น element ที่กำลังโฟกัสอยู่หรือข้อความที่กำลังพิมพ์ ยิ่งไปในทิศทางนี้มากเท่าไร บั๊กและ race condition ก็ยิ่งลดลง และประสบการณ์ผู้ใช้ก็ดีขึ้นมาก จึงคุ้มค่าที่จะทำ
    • ผมเป็นผู้เขียนบทความเอง และเพราะดูเหมือนว่าประโยคนั้นจะถูกตีความไปต่างจากเจตนา ผมจะลบมันออก ผมก็เขียนไว้ใน Twitter เหมือนกันว่า Web Components เข้ากันได้อย่างเป็นธรรมชาติกับ การเขียนสคริปต์ที่เป็นมิตรกับไฮเปอร์มีเดีย ตามที่คุณอธิบายในบทความของคุณ และผมก็ชอบบทความนั้นมากทีเดียว
      https://x.com/jlazaroff/status/1717176726248108469
      https://htmx.org/essays/hypermedia-friendly-scripting/
    • แทนที่ htmx จะจบลงแค่เป็นไลบรารี JavaScript ธรรมดา เดิมทีผมหวังว่าในระยะยาวมันจะกลายเป็น มาตรฐานของ HTML เอง
      ข้อจำกัดที่ว่ามีเพียงฟอร์มเท่านั้นที่ทำ POST ได้ และวิธีเดียวในการจัดการ response คือเขียนทับทั้งหน้าใหม่ ดูเป็นข้อจำกัดที่ถูกกำหนดขึ้นมาอย่างไม่มีเหตุผลนัก หาก htmx กลายเป็นอะไรแบบ HTML6 มันก็จะอยู่ได้นานกว่า JavaScript framework ทั้งหมด
    • ดีใจมากที่ได้ยินว่า htmx จะเสถียรมากและเปลี่ยนแปลงน้อยในอนาคต
      ผมเป็นวิศวกรที่โฟกัสแบ็กเอนด์เป็นหลัก ดังนั้นไลบรารี JS ส่วนใหญ่ที่หยิบมาใช้มักกลายเป็นภาระการบำรุงรักษาภายหลัง และมีการเปลี่ยน API ใหญ่ ๆ บ่อยด้วย ผมคิดว่าจะลองใช้ htmx กับโปรเจ็กต์ส่วนตัวสักครั้ง
    • เคยอยาก เขียน SPA ใหม่ด้วย htmx สำหรับโปรเจ็กต์ข้าง ๆ ของตัวเอง ผมไม่ได้สนใจ Web Components มากนัก แต่การใช้มันร่วมกับ htmx เป็นแนวคิดที่น่าสนใจ
      เทมเพลตฝั่งเซิร์ฟเวอร์ที่ใช้สร้างชิ้นส่วน HTML ก็น่าจะซับซ้อนน้อยลงด้วย
      ตัว htmx เองเป็นแนวคิดที่น่าเชื่อถือมากจริง ๆ แต่ก็อยากให้มีคอมมูนิตี้ที่ใหญ่กว่านี้ แม้จะเป็นปัญหาไก่กับไข่ก็ตาม แต่เมื่อเทียบกับเว็บเฟรมเวิร์กอื่น ๆ แล้ว เนื้อหาอย่างบล็อกโพสต์หรือวิดีโอยังมีไม่มากนัก เช่น แม้แต่เรื่องพื้นฐานอย่างการรวมการยืนยันตัวตนของ Auth0 เข้ากับแอป htmx ก็ยังหาข้อมูลได้ยาก
  • non.io ทั้งหมดเขียนด้วย Web Components แบบล้วน ๆ และเป็น SPA เต็มรูปแบบ มีบางอย่างที่ได้เรียนรู้เมื่อก้าวพ้นจากคอมโพเนนต์บล็อกแบบซ้อนกันง่าย ๆ
    การจัดการสถานะก็ยังไม่มีคำตอบตายตัวอยู่ดี ถ้าไม่ใช้ wrapper framework ก็ต้องทำหลายอย่างเอง ข้อดีอย่างหนึ่งของ React คือเรื่องการจัดการสถานะถูกแก้ไว้ค่อนข้างดีแล้ว และมีแพตเทิร์นกับความคาดหวังที่มีอยู่เดิม ในโลกของ Web Components มันยังเหมือนแดนตะวันตกยุคบุกเบิก และไม่สามารถส่งอ็อบเจ็กต์ซับซ้อนผ่านแอตทริบิวต์แบบ JSX ได้ จึงต้องปนกันไปทั้งแอตทริบิวต์, อีเวนต์ และการเรียกฟังก์ชันของคลาสโดยตรง
    ด้านประสิทธิภาพก็ไม่ได้ดีขึ้นมากอย่างที่คาดไว้ องค์ประกอบเล็กระดับอะตอม เช่นไอคอน ถ้ามีอยู่เป็นร้อยบนหน้า ต้นทุนการสร้างอินสแตนซ์จะสูงเกินกว่าคุณค่าที่ได้ จึงถอยกลับจากการใช้ Web Components สำหรับส่วนนี้ องค์ประกอบแบบสแตติกแม้จะช่วยให้อ่านโค้ดง่ายขึ้น ก็ยังไม่น่าคุ้มพอจะใช้ Web Components ซึ่งค่อนข้างน่าผิดหวัง
    ถึงอย่างนั้นก็ยังมีจุดที่ชอบมาก อย่างที่ผู้เขียนบอกไว้ การเพิ่มคอมโพเนนต์ลงในหน้าใหม่ทำได้ง่ายมากโดยไม่ขึ้นกับเฟรมเวิร์กที่ใช้อยู่ ถ้าสร้างด้วย Web Components ก็เอาไปใช้ที่ไหนก็ได้จริง ๆ ตอนทำเว็บไซต์ประกอบอย่างเอกสาร API ของ nonio ที่ใช้สแตกต่างกัน ก็สะดวกมากที่เลือกหยิบเฉพาะคอมโพเนนต์ที่ต้องการมาใช้ได้ ถ้าต้อง embed คอมโพเนนต์ ก็แค่นำเข้า JS แล้วเพิ่ม HTML ก็จบ
    การห่อหุ้มสไตล์ ของ shadow root ก็ค่อนข้างดี ชอบตรงที่เวลาทำงานกับหน้าเว็บไม่ต้องกังวลว่าจะเผลอทำสไตล์ของคอมโพเนนต์ไหนพัง ลดการต้องเดาและคอยเช็กว่าสไตล์จะไปทับองค์ประกอบอื่นหรือไม่ และยังลดความจำเป็นของเฟรมเวิร์กตรวจสอบความต่างเชิงภาพที่ใช้เพื่อรับประกันเรื่องนี้ด้วย
    ขนาดแพ็กเกจก็เล็กเป็นข้อดีเช่นกัน ไม่มีไลบรารีหรือโหลดเพิ่ม ทุกอย่างมีมาในตัว และเพราะเลือกใช้เฉพาะคอมโพเนนต์ที่ต้องการได้ง่าย จึงรักษาขนาดแพ็กเกจให้เล็กไว้ได้ไม่ยาก
    ซอร์สคอมโพเนนต์ของ nonio อยู่ที่นี่: https://github.com/jjcm/nonio-frontend/tree/master/component...

    • ประเด็นที่ว่ส่งอ็อบเจ็กต์ผ่านแอตทริบิวต์ไม่ได้ จริง ๆ แล้วส่งผ่าน พร็อพเพอร์ตี ขององค์ประกอบได้
      ส่วนเรื่องการจัดการสถานะ ก็ไม่มีอะไรขวางการเชื่อมต่อกับโซลูชันจัดการสถานะแบบไหนก็ตามที่ต้องการเลย ถ้าเป้าหมายคือการลด dependency ให้เหลือน้อยที่สุด ก็เคยเห็นโซลูชันที่ใช้โมเดลอีเวนต์ที่มีมาในเบราว์เซอร์อยู่พอสมควร
      สุดท้ายแล้ว การเขียนทั้งแอปด้วย Web Components ล้วน ๆ โดยส่วนตัวมองว่าเป็นแนวคิดที่ค่อนข้างฝืน ถ้าใช้ Lit ขนาด 5KB จะได้ประสบการณ์นักพัฒนาที่ดีกว่ามาก: https://lit.dev
    • ประสิทธิภาพมันเป็นข้อได้เปรียบจริงหรือ? คาดว่ามันจะให้ประสิทธิภาพแย่กว่าการใช้เว็บเฟรมเวิร์กทั่วไปอย่าง React, Vue, Svelte เป็นต้น
      เฟรมเวิร์กเหล่านี้มักได้ประสิทธิภาพจากการจัดการ DOM แบบเป็นชุดในระดับทั้งหน้า ซึ่งใน Web Components ทำแบบนั้นไม่ได้
      แค่เหตุผลนี้อย่างเดียวก็มองว่า Web Components แทบเป็นทางตันแล้ว ถึงอย่างนั้น ถ้าต้องการเพียงเกาะฟังก์ชันเล็ก ๆ มากกว่าหน้าแบบ client-rendered ทั้งหมด มันก็อาจมีประโยชน์
    • อยากรู้ว่าใน Web Components ที่ไม่ใช้ shadow DOM ก็เจอปัญหาประสิทธิภาพเหมือนกันหรือเปล่า
      ผมก็เคยเจอ ข้อจำกัดด้านประสิทธิภาพ คล้ายกัน แต่คิดมาตลอดว่าเป็นเพราะ shadow DOM หนักเกินไป ตอนนี้เลยเริ่มสงสัยว่าจริง ๆ แล้วตัวการสร้างอินสแตนซ์เองหรือเปล่าที่หนัก
      เรื่องการจัดการสถานะก็รู้สึกเจอปัญหาเดียวกัน และกำลังคิดว่าจะลองยืมแนวคิดจากการพัฒนาเดสก์ท็อปมาใช้ โดยมี message bus ระดับหน้าต่างให้ทุกคอมโพเนนต์ subscribe และ filter แล้ว publish การเปลี่ยนสถานะทั้งหมดไปยัง message bus นั้น
    • สามารถ ส่งอ็อบเจ็กต์ซับซ้อนผ่านแอตทริบิวต์ แบบ JSX ได้
      ตัวอย่างการส่งอ็อบเจ็กต์ซับซ้อนผ่านแอตทริบิวต์ ดู zx-listeditor ได้ที่นี่:
      https://github.com/wisercoder/uibuilder/blob/master/WebCompo...
      ตัว Web Component เองอยู่ที่นี่:
      https://github.com/wisercoder/uibuilder/blob/master/WebCompo...
      ไลบรารีเล็ก ๆ ขนาด 500 บรรทัดที่ทำให้สิ่งนี้เป็นไปได้อยู่ที่นี่:
      https://github.com/wisercoder/uibuilder/#jsx-for-web-compone...
    • มีการแชร์โปรเจกต์ที่มุ่งแก้ปัญหาว่าการจัดการสถานะของ Web Components ยังเป็นโจทย์ที่ยังไม่คลี่คลาย: https://github.com/launchscout/live_state
      แพตเทิร์นพื้นฐานของ LiveState คือ “dispatch อีเวนต์ แล้ว subscribe สถานะ” อีเวนต์และการอัปเดตสถานะจะถูกส่งผ่านการเชื่อมต่อ WebSocket และไลบรารีฝั่งฟรอนต์เอนด์กับแบ็กเอนด์เป็นชั้นบาง ๆ บน Phoenix Channels
      ตอนนี้ฟังก์ชันตัวจัดการอีเวนต์ยังเขียนด้วย Elixir แต่กำลังมีการทำงานเพื่อให้สามารถเขียนด้วยภาษาใดก็ได้ที่คอมไพล์เป็น WebAssembly
  • ไม่ได้คาดหวังว่าเฟรมเวิร์ก JS ที่ชอบจะยังคงเป็นตัวเดิมตลอดไป รู้ว่าอายุของมันสั้น และชอบตรงนั้น
    เหตุผลที่ใช้ React, Vue, Svelte ฯลฯ ก็เพราะต้องการก้าวต่อไป พัฒนา และปรับปรุง ไม่ได้ต้องการอะไรที่หยุดนิ่งในตอนนี้ เพราะไม่มีเฟรมเวิร์กตัวไหนที่ใช้ได้ในปัจจุบัน รวมถึง Web Components ที่จะแก้ปัญหาเหล่านี้ได้อย่างสง่างามเป็นพิเศษ
    ถ้าจะอ้างว่าเว็บไซต์ที่สร้างด้วย Web Components จะอยู่ได้นานกว่าเว็บไซต์ที่สร้างด้วยเฟรมเวิร์ก JS ก็อยากพนันดู พูดตามตรง มองว่าภายใน 20 ปีข้างหน้า ความเป็นไปได้ที่บางส่วนของเทคโนโลยีสแตก Web Components จะถูกถอดออกจาก Chrome, Safari, Firefox จนทำให้แอปพัง มีสูงกว่าความเป็นไปได้ที่แอป React 16 ที่เขียนเมื่อ 2 ปีก่อนจะพังเพราะการเปลี่ยนแปลงของ JavaScript

    • พนันแบบนั้นมีโอกาสชนะสูง แต่ตั้งเงื่อนไขจนแทบไม่มีความหมาย
      ถ้าตรึงเวอร์ชัน dependency ทั้งหมดของแอป React 16 ไว้แบบตายตัว มันอาจไม่พังก็จริง แต่แบบนั้นใกล้เคียงกับการรันโปรแกรมเก่าใน VM หรืออีมูเลเตอร์ มากกว่าจะเรียกว่า “ยังทำงานและแฮ็กต่อบนแอป React 16 ได้”
      พนันที่มีความหมายกว่าน่าจะเป็น “ยังพัฒนาต่อบนแอป React ZZZ ได้หรือไม่ vs ยังพัฒนาต่อบนแอปที่สร้างด้วย Web Components ได้หรือไม่”
      ถ้าจะตั้งเงื่อนไขให้เข้าทางตัวเองแต่ยังมีความหมายมากขึ้น ก็คงเป็น “ต้นทุนในการอัปเดตแอป React เพื่อไล่ตามการอัปเดต dependency ตลอด N ปี มากหรือน้อยกว่าแอป Web Components” ถ้าแอป Web Components ไม่ได้ยัด dependency แปลก ๆ ไว้เต็มไปหมด ก็มีโอกาสสูงมากที่ฝั่งแอป React จะมีต้นทุนการอัปเดตสูงกว่า
      โดยพื้นฐานแล้วคือเดิมพันว่า ผู้พัฒนาเบราว์เซอร์ จะทำลายความเข้ากันได้ย้อนหลังน้อยกว่าผู้เขียน React
    • เรื่องแบบนั้นเคยเกิดขึ้นแล้ว
      HTML Imports ถูกยกเลิกไปเพราะหันไปนิยมวิธีแก้แบบ JS ล้วน และ Firefox ก็เคย implement มันแล้ว
      Custom Elements v0 ก็ถูกยกเลิกเช่นกัน โดย Chrome เคย implement และ YouTube ก็เคยรีบเขียนใหม่ด้วยสิ่งนี้ ต้องรออยู่ราว 4 ปีจึงจะถอด implementation ออกได้ เพราะ YouTube ใช้เวลานานขนาดนั้นกว่าจะย้ายออก
    • มองว่าหากรันโค้ดเก่าและไม่อัปเดต dependency เว็บไซต์ก็อาจเสี่ยงต่อ ช่องโหว่ความปลอดภัย ที่ถูกค้นพบตามเวลาและถูกแก้ในไลบรารีเวอร์ชันใหม่
      ถ้าจะทำให้โค้ดปลอดภัย ก็ต้องอัปเดตไลบรารี แต่ไลบรารีเวอร์ชันเก่าจะหมดการสนับสนุน และเริ่มสะสมช่องโหว่ที่รู้กันอยู่แล้วแต่แก้ไม่ได้ ผู้โจมตีน่าจะมีโปรแกรมที่สแกนหาเว็บไซต์ที่มีช่องโหว่ที่รู้จักและโจมตีแบบอัตโนมัติ
      ในทางกลับกัน ถ้าใช้ไลบรารีหรือแพลตฟอร์มที่ให้ความสำคัญกับความเข้ากันได้ย้อนหลังอย่าง Web Components ก็อาจรักษาความปลอดภัยไว้ได้พร้อมกับรองรับโค้ดเก่าได้นานกว่า
  • เริ่มโฟกัสที่ คน มากกว่าเทคโนโลยี
    ถ้าจะเริ่มโปรเจกต์ใหม่ ก่อนอื่นจะดูว่าคนที่จะมาทำงานในโปรเจกต์นั้นรู้อะไรบ้าง ถ้ามีตัวเลือกที่เป็นจุดร่วมกันหรือมี best practice อยู่แล้ว อย่างที่ทุกวันนี้ React เป็นในฝั่งฟรอนต์เอนด์ ก็จะใช้สิ่งนั้นไปเลย
    ไม่ได้กังวลกับการตัดสินใจทางเทคนิคแบบนี้มากนัก เพราะองค์ประกอบของทีม ตลาดแรงงาน และอันดับเทคโนโลยีบน StackOverflow มักตอบคำถามพวกนี้ได้ง่ายอยู่แล้ว

    • มองว่าแนวทางนั้นเข้าใจได้และใช้งานได้จริง
      แต่ถ้าทุกคนคิดแบบนั้น ต่อให้มีคำตอบที่ดีกว่าสำหรับการสร้างซอฟต์แวร์ เราก็จะใช้ React ไปตลอดกาล การเลือกใช้สิ่งที่ได้รับความนิยม หมายถึงการฝากความหวังเรื่องการปรับปรุงสแตกเทคโนโลยีไว้กับคนอื่นให้ไปหาทางออกทางเทคนิคที่ดีกว่าแล้วทำให้มันได้รับความนิยม
      พูดอีกแบบคือ กลยุทธ์นี้อยู่ฝั่งผู้ยอมรับช่วงกลางถึงปลายของ adoption curve อย่างชัดเจน และบทความกับการถกเถียงแบบนี้จำนวนมากก็เขียนขึ้นสำหรับผู้ยอมรับในช่วงที่เร็วกว่านั้น
  • เนื่องจากสามารถใช้ HTML ภายใน Markdown ได้ ดังนั้นแนวคิดที่ว่าหากสามารถแสดงไดอะแกรมแบบโต้ตอบที่หวือหวาด้วยแท็ก HTML ปกติได้ มันก็จะพกพาได้เหมือนส่วนอื่น ๆ ของ Markdown นั้น MDX ก็ทำสิ่งเดียวกันนี้ได้อย่างตรงตัว
    เทคโนโลยีที่ชื่อว่า Web Components เองไม่ได้ช่วยอะไรในจุดนี้ สิ่งที่ผู้เขียนสนใจคืออินเทอร์เฟซระหว่างมาร์กอัปกับชิ้นส่วนโค้ดที่นำความสามารถของรันไทม์มาใช้ Web Components ในที่นี้เป็นเพียงรายละเอียดการติดตั้งใช้งานเท่านั้น ไม่สำคัญว่าชื่อที่อยู่ระหว่างวงเล็บมุมจะอ้างถึง React component, อะไรสักอย่างของ Astro หรือ Web Component ประเด็นสำคัญคือมีอย่างอื่นบางอย่างถูกเรียกใช้งาน
    ข้อเสียของ Web Components ในที่นี้คือโดยพื้นฐานแล้วมันทำงานได้แค่ฝั่งไคลเอนต์เท่านั้น ไม่มีวิธีส่งต่อเนื้อหา shadow DOM ที่เรนเดอร์จากเซิร์ฟเวอร์ไปยังไคลเอนต์ ดังนั้นต่อให้ Web Component จะไม่โต้ตอบเลย ก็ยังต้องใช้ client-side JS เพื่อเรนเดอร์ ซึ่งเฟรมเวิร์กอื่นไม่ได้เป็นแบบนั้น
    ไม่ได้หมายความว่าประเด็นของผู้เขียนผิด Web Components ในฐานะวิธีจัดระบบอินเทอร์เฟซระหว่างชิ้นส่วนโค้ดต่าง ๆ อาจเป็นวิธีที่ดีที่สุดและอยู่ได้นานที่สุดก็ได้ แต่บนเซิร์ฟเวอร์ Web Components ไม่ได้ช่วยอะไร มันไม่ถูกเรนเดอร์ อินเทอร์เฟซก็ใช้งานยุ่งยาก และโค้ดก็มักจะถูกเขียนไว้ในรูปแบบที่จัดการทั้งระบบได้อยู่แล้ว ถ้าบนเซิร์ฟเวอร์คุณใช้ Astro ก็ใช้ Astro ต่อไปได้เลย จะเป็น React, Vue หรืออะไรก็เหมือนกัน
    จุดที่ Web Components เปล่งประกายคือฝั่งไคลเอนต์ เวลาใช้คอมโพเนนต์ของบุคคลที่สามซึ่งอาจไม่ได้เขียนด้วยเฟรมเวิร์กที่คุณเลือก คุณไม่จำเป็นต้องรู้ว่าคอมโพเนนต์ที่วางบนหน้านั้นสร้างมาด้วยเฟรมเวิร์กอะไร แค่ใช้แท็ก HTML มันก็ทำงานได้แล้ว กลไกของอินเทอร์เฟซจึงถูกยกระดับขึ้นไปอยู่ที่ระดับเบราว์เซอร์ ทำให้สองเฟรมเวิร์กไม่จำเป็นต้องรู้รายละเอียดการติดตั้งใช้งานของกันและกัน

    • ตอนแรกนึกว่ากำลังจะอ้างว่าแท็กบนเซิร์ฟเวอร์ไม่มีทางได้ HTML ภายในของตัวเองมาแบบมหัศจรรย์
      ในแง่นั้นก็ถูกว่าต้องมีเครื่องมือบางอย่าง เพียงแต่ว่าเครื่องมือนั้นจะเป็น template engine ฝั่งเซิร์ฟเวอร์ตัวไหนก็ได้ที่ช่วยเติม initial HTML เพื่อบูตสแตรป
      แต่ shadow DOM ที่เรนเดอร์จากเซิร์ฟเวอร์สามารถส่งต่อไปยังไคลเอนต์ได้ เรียกว่า Declarative Shadow DOM และใช้งานได้ในเบราว์เซอร์หลักทุกตัว ยกเว้น Firefox ซึ่งก็กำลังทำอยู่ตอนนี้และมี polyfill ด้วย
    • อยากชี้ให้เห็นว่าคุณสมบัตินี้มีอยู่ใน HTML ปกติด้วย
    • มีข้อเสนอสำหรับการส่ง shadow DOM ที่เรนเดอร์จากเซิร์ฟเวอร์ไปยังไคลเอนต์อยู่ เพียงแต่ไม่มีใครรู้ว่าระยะยาวแล้วมันจะอยู่รอดไหม
      https://developer.chrome.com/articles/declarative-shadow-dom...
      อนึ่ง polyfill นี้ค่อนข้างทำได้ง่าย ดังนั้นถึงตอนนี้เบราว์เซอร์ของคุณจะยังไม่รองรับก็อาจใช้งานได้
    • ผมชอบใช้ Web Components ควบคู่กับเครื่องมือดี ๆ ที่ Lit มีให้ แต่ก็เห็นด้วยว่าการขาด server-side rendering และ hydration ทำให้มันใช้งานได้จริงน้อยกว่าไลบรารี progressive enhancement ฝั่งเซิร์ฟเวอร์อย่าง Stimulus หรือ Alpine
      ถ้ามี Web Components ที่เรนเดอร์ได้บนเซิร์ฟเวอร์ ก็จะเปิดโอกาสมากมายในการทำให้ประสบการณ์ผู้ใช้ของแอปหลายหน้าให้ดีขึ้น
  • โลกของ JS ยังหมกมุ่นกับ thick client ที่ควบคุมทุกอย่างมากเกินไป จนพลาดสิ่งน่าสนใจที่กำลังเกิดขึ้นในโลกฝั่งเซิร์ฟเวอร์
    โซลูชันอย่าง Rails Hotwire, Phoenix LiveView และ Laravel Livewire สามารถแก้โจทย์ฟรอนต์เอนด์ได้ 80% ด้วย JS เพียงเล็กน้อยและแทบไม่มีความซับซ้อนด้านประสบการณ์นักพัฒนาเลย

    • มันเป็นไปได้ไม่ใช่หรือที่ทั้งฟรอนต์เอนด์และแบ็กเอนด์จะเติบโตเต็มที่และทรงพลังขึ้นพร้อมกัน? นั่นไม่ใช่สิ่งที่เราต้องการหรือ?
      ผมเคยสร้างแอปฟรอนต์เอนด์ที่ฟีเจอร์ครบถ้วน ซึ่งอ่านและเขียนฐานข้อมูลกับ object storage ได้โดยไม่ต้องมีเซิร์ฟเวอร์ด้วยซ้ำ มันพกพาได้ดีมาก และขั้นตอนติดตั้งก็มีแค่อัปโหลดไฟล์ไม่กี่ไฟล์ รันตรงจาก CDN ธรรมดาได้เลยและเร็วมาก
      นักพัฒนาฟรอนต์เอนด์ส่วนใหญ่ที่ผมรู้จักก็รู้จักสาย Hotwire อยู่แล้ว แต่สำหรับพวกเขา สแตกแบบนั้นกลับเพิ่มความซับซ้อนด้านประสบการณ์นักพัฒนา บางครั้งคนพูดว่า “ความซับซ้อน” แต่จริง ๆ หมายถึง “ความไม่คุ้นเคย” ทั้งฟรอนต์เอนด์และแบ็กเอนด์อาจซับซ้อนเกินไปได้ทั้งคู่ แต่ก็ไม่จำเป็นต้องเป็นอย่างนั้นเสมอไป
    • ความซับซ้อนต้องมีอยู่ที่ไหนสักแห่ง จะอยู่ในมือวิศวกร หรือถูกกวาดซ่อนไว้ใต้พรมเพื่อให้เฟรมเวิร์กเล่นกลได้ อย่างหลังนี่ทำให้นึกถึง Rails ecosystem โดยเฉพาะ
      เวลาที่อะไร ๆ ผิดพลาด ผมคิดว่าการมีอำนาจควบคุมมากกว่าย่อมดีกว่า โดยเฉพาะในสภาพแวดล้อมที่ลูกค้าเรียกร้องความเร็วในทันที
    • มันคือการเขียน HTML ใน JavaScript หรือไม่ก็เขียน JavaScript ใน HTML
      ส่วนตัวแล้วผมคิดว่าการเขียนทุกอย่างเป็น JavaScript/TypeScript ไปเลยดีกว่า แทนที่จะโรย syntactic sugar ลงบน HTML
    • นี่ไม่ใช่พื้นที่ของ trade-off เดิม ๆ เรื่องว่าจะทำให้ UI บางแค่ไหน ที่เราสำรวจกันมาตั้งแต่ยุคเริ่มต้นของ UI หรอกหรือ?
      การย้ายไปไว้ฝั่งเซิร์ฟเวอร์แบบ Livewire ไม่ได้ทำให้ข้อเสียแรง ๆ อย่าง latency หายไป
    • ผมเองก็อยากเรียนรู้ Inertia ฝั่ง Laravel ให้มากขึ้น แต่ในฐานะนักพัฒนา Laravel แล้ว Livewire โดยเฉพาะเมื่อใช้คู่กับ Filament ให้ความรู้สึกว่าทำงานได้อย่างเหลือเชื่อมาก
  • ชื่อเรื่องอาจจะถูกก็ได้ แต่ไม่รู้ว่ามันสำคัญหรือเปล่า แอปส่วนใหญ่ไม่ได้มีอายุยืนขนาดนั้น
    ผมเพิ่งลองใช้ Web Components ไม่นานนี้เอง แล้วพบว่าแม้แต่ฟังก์ชันง่าย ๆ มาก ๆ ในเฟรมเวิร์กไหนก็ตาม กลับตั้งค่าได้สับสนและซับซ้อนมาก ถ้าคอมโพเนนต์เรียบง่ายมากก็อาจไม่เป็นไร แต่ถ้าคุณสร้างแอปด้วย JS slot เป็นฟีเจอร์หลักเพราะมันทำให้สร้างคอมโพเนนต์ที่ประกอบต่อกันได้
    การดีบัก shadow DOM ใน devtools ก็สับสนมากจริง ๆ

    • บางอย่างแทบเป็นไปไม่ได้เลยที่จะทำให้ทำงานได้อย่างถูกต้องหากไม่มี MutationObserver หรือ polyfill ของมัน
      renderProp ของ React หรือ scoped slot ของ Vue ถูกใช้กันบ่อยมากในการส่งข้อมูลจากคอมโพเนนต์พ่อไปยังคอมโพเนนต์ลูก แต่การจำลองพฤติกรรมแบบนั้นใน Web Component แทบเป็นไปไม่ได้เลยหากไม่มีการแฮ็กด้วย MutationObserver สมมติฐานของ Web Component ที่ว่าคอมโพเนนต์ลูกและพ่อไม่จำเป็นต้องรู้ข้อมูลของกันและกันนั้นไม่สอดคล้องกับโลกความเป็นจริง
      สมมติฐานที่ว่าคอมโพเนนต์ลูกจะถูกโหลดและ initialize เสมอโดยไม่ขึ้นกับพ่อ ก็ไม่จริงในเฟรมเวิร์กส่วนใหญ่เช่นกัน ในเฟรมเวิร์กส่วนใหญ่ คอมโพเนนต์พ่อจะเป็นผู้ตัดสินใจว่าจะโหลดหรือ initialize คอมโพเนนต์ลูกจริงหรือไม่
  • Web Components อาจดีกว่าสำหรับการเขียนคอมโพเนนต์ที่แยกขาดและนำกลับมาใช้ซ้ำได้ แต่ DOM API ที่ใช้เอานั่นเอานี่มาต่อกันให้แอปพลิเคชันทำงานได้นั้นแย่มากจริง ๆ
    มันยังให้ความรู้สึกชัดเจนว่าเดิมทีถูกสร้างมาเพื่อแก้ไขเอกสาร XML
    ยังมีอีกเหตุผลหนึ่งที่ไม่ทำ Web Components แม้แต่สำหรับคอมโพเนนต์ที่แยกขาดและใช้ซ้ำได้: ไม่มี editor ตัวไหนช่วยจัดการอย่างเหมาะสมในเรื่องอย่างการเติมชื่อแอตทริบิวต์หรือชื่ออีเวนต์อัตโนมัติ หรือการตรวจจับคำพิมพ์ผิด

  • ถ้าจะทำให้มีประโยชน์ ก็ต้องเอา dependency หลายตัวมาต่อกัน และ dependency เหล่านั้นก็คงไม่ได้รับการดูแลรักษาดีเท่า React
    ผมเคยทำงานที่บริษัทที่ยึดแนวคิดแบบนี้ ทุก UI component เป็น Web Component ที่มี npm package ให้ติดตั้งแยกของตัวเอง มันก็ใช้งานได้ แต่ไม่มีข้อดีอะไรเลย ตอนนี้ผ่านไป 6 ปีแล้วก็ยังไม่มีข้อดีอยู่ดี เท่ากับกำลัง optimize เพื่ออนาคตที่อาจไม่มีวันมาถึง

  • HTML/CSS site จะอยู่ยาวกว่าทั้งหมด
    เพราะข้อความ รูปภาพ และเลย์เอาต์อยู่ในสิ่งที่เป็น static จริง ๆ และสามารถอยู่ได้ตลอดไปโดยไม่ต้องไปแตะต้องมัน และไม่ต้องรันโค้ดซับซ้อนหรือคอยรักษา quasi-standard ที่คลุมเครือและเปลี่ยนเร็ว
    ถ้าคุณอยากสร้างเว็บไซต์ที่อยู่ได้นานและมีเทคโนโลยีที่อยู่ได้นาน ก็แค่เรียนรู้วิธีสร้างเว็บไซต์ HTML ที่ปรับปรุงแบบค่อยเป็นค่อยไปก็พอ ส่วนวิธีแบบ Web Components ที่สร้าง element HTML มีขีดคั่นที่ยังไม่ถูกนิยามและค่อยไปรัน JavaScript กองโตเพื่อกำหนดมันทีหลัง หรือ JavaScript framework ที่ไม่แม้แต่จะแกล้งทำเป็นใช้ HTML นั้น อยู่ได้แค่ไม่กี่ปี
    อย่างน้อยก็คงเป็นแบบนั้นจนกว่าบราว์เซอร์จะเลิกสนับสนุน HTTP/1.1

    • อยากรู้ว่าส่วนไหนของ Web Components ที่ไม่ตรงกับนิยามของ progressive enhancement
    • อยากรู้ว่าคุณเห็นไหมว่าผมใช้ Web Components ตรงไหนในบทความ จะสร้างบทความสอนที่มี เดโมโต้ตอบได้ โดยไม่ใช้ JavaScript ได้อย่างไร?