2 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Wordgard 0.1 คือไลบรารีแก้ไข rich text สำหรับ JavaScript ที่สร้างขึ้นใหม่ โดยสะท้อนประสบการณ์ 9 ปีหลัง ProseMirror เสถียร และแนวทางการออกแบบของ CodeMirror 6
  • แทนที่จะเปลี่ยน ProseMirror เดิมเป็น 2.0 หรือเสริมเพิ่มเข้าไปใน 1.x จึงออกแบบใหม่ด้วยชื่อแยกต่างหากและ API ใหม่ที่ไม่ต้องแบกรับภาระด้านความเข้ากันได้
  • การออกแบบหลักใช้ โมเดลตามส่วนของการเปลี่ยนแปลง แทน steps และผสานชนิด node/mark ที่เป็นอิสระเข้ากับระบบขยายแบบ facet สไตล์ CodeMirror
  • ลดการพึ่งพาพฤติกรรมการเลือกของเบราว์เซอร์ โดยจัดการการเลือกด้วย pointer และ keyboard เอง แต่ การเลือกด้วย touch ยังคงใช้การทำงานของเบราว์เซอร์ เพราะปัญหาเมนูบริบทแบบ native
  • ติดตั้งได้จาก npm ด้วย wordgard และมีเอกสารกับคู่มืออ้างอิงเผยแพร่แล้ว แต่จะยังคงอยู่ใน เวอร์ชัน 0.x ไปอีกระยะเพื่อรับ feedback และแก้บั๊ก

ลักษณะของ Wordgard และสถานะการเผยแพร่

  • Wordgard เป็นโปรเจกต์ที่ทำซ้ำระบบแก้ไข rich text สไตล์ ProseMirror ขึ้นมาใหม่
  • ได้รับอิทธิพลอย่างมากจากสิ่งที่เรียนรู้ตลอด 9 ปีหลัง ProseMirror เสถียร และจากการออกแบบใหม่ของ CodeMirror เวอร์ชัน 6
  • เป็น ไลบรารี JavaScript ที่แสดงอินเทอร์เฟซของ editor ผ่าน DOM ของเบราว์เซอร์ และใช้ไลเซนส์ MIT
  • โค้ดเผยแพร่บน เซิร์ฟเวอร์ Forgejo
  • ติดตั้งได้จาก npm registry ด้วย wordgard และดูวิธีใช้งานได้บนเว็บไซต์

เหตุผลที่สร้างระบบใหม่แทนการเปลี่ยน ProseMirror

  • ProseMirror จะยังได้รับการดูแลต่อไป แต่บางส่วนของการออกแบบยังเป็นจุดที่หากมองจากปัจจุบันก็ควรทำต่างออกไป
  • หากออก ProseMirror 2.0 ที่มีอินเทอร์เฟซไม่เข้ากัน อาจทำให้คลุมเครือว่าเมื่อคนพูดถึง “ProseMirror” หมายถึงอะไร
  • หากนำไอเดียใหม่ไปต่อเติมใน ProseMirror 1.x แบบรักษาความเข้ากันได้ย้อนหลัง โครงสร้างอาจต้องประนีประนอม
  • Wordgard นำไอเดียจำนวนมากจาก ProseMirror มาใช้ แต่ อินเทอร์เฟซสำหรับโปรแกรมมิง ถูกออกแบบใหม่ตั้งแต่ต้นโดยไม่คำนึงถึงความเข้ากันได้

การแทนค่าการเปลี่ยนแปลง: โมเดลตาม section แทน steps

  • steps ของ ProseMirror แบ่งการเปลี่ยนแปลงเป็นการทำงานแบบอะตอมหลายรายการ โดยแต่ละ step จะถูกนำไปใช้กับเอกสารที่เกิดจาก step ก่อนหน้า
  • วิธีนี้ใช้งานได้ แต่การปรับตำแหน่งระหว่างหลาย step และการติดตามช่วงที่เปลี่ยนแปลงซับซ้อน ทำให้จัดการได้ไม่ถนัด
  • Wordgard ใช้โมเดลที่เรียบง่ายกว่า โดยอิงแนวทางจากการแทนค่าการเปลี่ยนแปลงของ CodeMirror และรูปแบบ “delta” ของ ShareJS
    • เมื่อความยาวเอกสารเป็น 10 แล้วแทรก L ที่ตำแหน่ง 4 จะแทนเป็น [keep 4] [replace 0 with "L"] [keep 6]
    • เมื่อลบอักขระสองตัวแรก จะแทนเป็น [replace 2 with ""] [keep 8]
  • เพื่อรองรับ rich text จึงเพิ่ม section ของการเปลี่ยนแปลง ทำให้สามารถเพิ่มหรือลบ mark เช่น ตัวหนา สไตล์ลิงก์ หรือข้อความ alt ของรูปภาพได้ โดยคงโครงสร้างไว้
    • หากทำให้คำตั้งแต่ 3 ถึง 6 เป็นตัวหนา จะแทนเป็น [keep 3] [update 3 +bold] [keep 4]
  • Wordgard ใช้ token-counting index เช่นเดียวกับ ProseMirror เพื่อจัดการตำแหน่งในเอกสารเป็นลำดับแบนของ token เปิด/ปิด node และ leaf token
  • transaction เดี่ยวจะมีการเปลี่ยนแปลงเพียงหนึ่งรายการเสมอ ทำให้การประกอบการเปลี่ยนแปลง การตรวจสอบ และการอนุมานง่ายขึ้น
  • รองรับ operational transformation แบบจำกัด เพื่อรวมการเปลี่ยนแปลงหลายรายการที่อธิบายบนเอกสารตั้งต้นเดียวกันได้
    • สามารถแสดง transaction ที่มีการเปลี่ยนแปลงหลายรายการได้สะดวกขึ้น
    • นำไปใช้กับ collaborative editing และการทำ undo history ที่ย้อนกลับเฉพาะบางการเปลี่ยนแปลงได้

วิธีรักษาโครงสร้างเอกสารที่ถูกต้อง

  • เอกสาร Wordgard ไม่ใช่แค่ลำดับ token ธรรมดา แต่ต้องเป็นโครงสร้างต้นไม้ที่สมดุล
  • ตัวอย่างเช่น หากลบ token ปิด node ออก อาจทำให้สมดุลของ token เสียและเกิดการเปลี่ยนแปลงที่นำไปใช้ไม่ได้
  • โค้ดที่สร้างชุดการเปลี่ยนแปลงต้องตรวจสอบและปรับแก้การเปลี่ยนแปลงเพื่อให้ผลลัพธ์เป็น โครงสร้างเอกสารที่ถูกต้อง
  • ใน operational transformation การเปลี่ยนแปลงที่ถูก transform แล้วก็ต้องไม่ทำให้เอกสารไม่ถูกต้องเช่นกัน
  • โมเดลการเปลี่ยนแปลงของ Wordgard คำนวณ fix-up change ที่ปรับแก้ผลการรวมระหว่างการ transform
    • ใช้อินพุตอย่างระมัดระวังเพื่อให้ได้การปรับแก้เดียวกันสำหรับ A-over-B และ B-over-A
    • หากไม่มีการปรับแก้ ทั้งสองลำดับอาจสร้างเอกสารเดียวกัน แต่อาจเป็นเอกสารที่ไม่ถูกต้อง
    • เมื่อประกอบการปรับแก้เดียวกัน ทั้งสองลำดับจะลู่เข้าสู่เอกสารที่ถูกต้องเดียวกัน
  • การเปลี่ยนแปลงส่วนใหญ่ไม่ต้องปรับแก้ แต่แม้จำเป็นก็ถูกออกแบบให้รักษาการลู่เข้าหากันไว้ได้

การประกอบ schema และการทำให้ mark ทั่วไปขึ้น

  • schema เอกสารของ ProseMirror ระบุความสัมพันธ์ระหว่าง node โดยตรง จึงมักต้องตั้งค่าด้วยมือ
  • ชนิด node และ mark ของ ProseMirror มีอยู่ได้เฉพาะภายใน schema หนึ่ง ๆ และไม่มีตัวตนของ node ที่แชร์ข้าม schema ได้
  • ใน Wordgard ชนิด node และ mark เป็นออบเจ็กต์อิสระที่สามารถรวมอยู่ใน schema เอกสารหลายชุดได้
  • ออบเจ็กต์เหล่านี้ทำงานเหมือน handle ที่รองรับการกำหนดชนิดและ auto-completion ทำให้นำองค์ประกอบที่ต้องการมาประกอบเป็น schema ได้ง่าย
  • schema สามารถ override ความสัมพันธ์ขององค์ประกอบที่มีอยู่ได้
    • นิยาม node หรือ mark จะกำหนดเนื้อหาเริ่มต้นหรือชนิดเป้าหมาย
    • เมื่ออยากใช้องค์ประกอบเดียวกันต่างแบบ schema สามารถเปลี่ยนความสัมพันธ์นั้นได้
  • สามารถให้ node พื้นฐานในตัวมาพร้อมความสามารถมากขึ้น ทำให้ผูกการขยายการสนับสนุนการแก้ไขหรือการรวมระบบอย่างปุ่มเมนูเข้ากับ node นั้นโดยตรงได้ง่าย
  • ฟีเจอร์ที่เคยผูกกับคุณสมบัติของ node เฉพาะ เช่น การจัดแนวข้อความหรือข้อความ alt สามารถเพิ่มแบบโมดูลาร์มากขึ้นผ่าน การทำให้ mark ทั่วไปขึ้น
  • ชนิด node เองไม่จำเป็นต้องรู้ว่า mark ใดมุ่งเป้ามาที่ตัวเอง

เหตุผลที่ผ่อนคลายข้อจำกัดของเนื้อหา

  • การระบุเนื้อหาที่อนุญาตตาม regular expression ซึ่งเป็นฟีเจอร์เด่นของ ProseMirror ไม่รองรับใน Wordgard
  • คำอธิบายเนื้อหา node ของ Wordgard จำกัดเพียงว่ารองรับชนิดลูกใดบ้าง แต่ไม่จำกัด ลำดับ ของลูกเหล่านั้น
  • ข้อจำกัดแบบ regular expression ทำให้เขียนโค้ดจัดการเอกสารทั่วไปได้ยาก
    • โค้ดที่ไม่ได้เขียนให้เข้ากับ schema เฉพาะแทบจะตั้งสมมติฐานไม่ได้ว่า transformation ใดถูกต้อง
    • ทุกการทำงานต้องนำไปเทียบกับข้อจำกัดของเนื้อหา และกระบวนการนี้ละเอียดอ่อนและเป็นภาระ
  • ข้อจำกัดที่ล็อกหน้าตาเอกสารอย่างเข้มงวดอาจขัดขวางขั้นตอนการแก้ไขระหว่างทางที่ผู้ใช้ต้องผ่านเพื่อไปสู่รูปแบบที่ตั้งใจ ทำให้ประสบการณ์ผู้ใช้แย่ลง
  • Wordgard สนับสนุนแนวทางรูปแบบเอกสารที่ยืดหยุ่นกว่า
  • เมื่อจำเป็นต้องมี invariant ที่เกินกฎของ schema จะมี abstraction ชื่อ correction ให้ใช้
    • ปรับแก้รูปแบบเอกสารที่ไม่ต้องการอนุญาตด้วยโปรแกรม
    • ทำการปรับแก้ที่ฉลาดกว่าและคำนึงถึงบริบทมากกว่าการบังคับ content expression ได้
    • ใช้กับเงื่อนไขอย่างการรับประกันว่าตารางเป็นสี่เหลี่ยมผืนผ้า ซึ่งแม้ข้อจำกัดของ ProseMirror ก็อธิบายไม่ได้

ระบบขยาย: facet สไตล์ CodeMirror 6

  • ระบบขยายของ ProseMirror เป็นแบบที่ plugin รับหลายหน้าที่ และลำดับใน array ส่งผลต่อ priority
  • อาจเกิดสถานการณ์ที่ plugin หนึ่งต้องมี priority ต่ำใน hook หนึ่ง แต่ต้องมี priority สูงในอีก hook หนึ่ง
  • ระบบที่อิง facets ของ CodeMirror ทำให้ extension ละเอียดขึ้น และให้ค่า extension แต่ละตัวตั้งหมวด priority ของตัวเองได้
  • Facet คือจุดขยายที่มี type กำกับ และไม่ใช่แค่ตัวไลบรารีเองเท่านั้น แต่โค้ดใด ๆ ก็สามารถนิยามได้
  • Wordgard นำระบบของ CodeMirror ในส่วนนี้มาแทบทั้งหมด รวมถึงกลไกการอัปเดตสถานะและการ reconfiguration
  • configuration ไม่ใช่ array ของ plugin แต่เป็น ต้นไม้ของ extension
    • นิยาม event handler
    • ตั้งค่าคุณสมบัติของ editor
    • เพิ่มสถานะ editor ใหม่
  • การทำฟีเจอร์มักประกอบด้วยชุด extension ที่ทำงานร่วมกัน
  • องค์ประกอบพื้นฐานถูกออกแบบให้ bundle ของ extension ส่วนใหญ่ประกอบกันได้ดีเพียงแค่ใส่เข้าไปในการตั้งค่า

การลดการพึ่งพาเบราว์เซอร์และการจัดการ selection

  • ปัญหาหลายอย่างของ ProseMirror เกี่ยวข้องกับวิธีที่พึ่งพาพฤติกรรม selection แบบ native ของเบราว์เซอร์
  • แนวทางเดิมคือปล่อยให้เบราว์เซอร์จัดการการเลื่อน cursor ในข้อความสองทิศทางหรือเนื้อหาที่มีสไตล์แปลก ๆ แล้วสะท้อนผลลัพธ์นั้นเข้ามาในโมเดล selection ของตัวเอง
  • ในความเป็นจริง เบราว์เซอร์อาจไม่เลื่อน cursor ผ่านเนื้อหาบางส่วน ไม่วาด cursor วาดผิดตำแหน่ง หรือมีพฤติกรรมผิดปกติเมื่อ drag เลือกด้วยเมาส์
  • Wordgard จัดการ selection ที่อิง pointer และ keyboard เองแทบทั้งหมด
    • implement การจัดการข้อความสองทิศทาง
    • สร้างโมเดลการจัดวางเนื้อหา
    • วาด cursor เอง
  • การเลือกด้วย touch เป็นข้อยกเว้นที่ยังใช้ implementation แบบ native
    • หาก implement ใหม่ ดูเหมือนจะทำให้เมนูบริบทแบบ native เสีย
    • บนโทรศัพท์และแท็บเล็ต การทดแทนเมนูบริบททำได้ยาก
    • การเลือกด้วย touch มักมีพฤติกรรมแปลกน้อยกว่าการเลือกด้วย keyboard

การจัดการ input event และการเลิกเฝ้าดูการเปลี่ยนแปลง DOM

  • ตลอด 9 ปีที่ผ่านมา การรองรับ edit event ของเบราว์เซอร์ โดยเฉพาะ beforeinput มีความสม่ำเสมอมากขึ้น
  • ยังต้องทดสอบในสภาพแวดล้อมใช้งานจริง แต่ดูเหมือนว่า Wordgard จะทำงานได้โดยไม่ต้องใช้การเฝ้าดูการเปลี่ยนแปลง DOM และเทคนิค parse เนื้อหาที่เปลี่ยนไปซึ่ง ProseMirror เคยพึ่งพา
  • Wordgard จัดการ event beforeinput สำหรับทุกอย่าง ยกเว้นการป้อนข้อความแบบ composition
  • แนวทางนี้หลีกเลี่ยงกลุ่มปัญหาที่ต้องใช้ workaround สกปรกหลายอย่าง

ความเสถียร แผนเวอร์ชัน และไลเซนส์

  • Wordgard อยู่ในสถานะที่คืบหน้ากว่าเล็กน้อยเมื่อเทียบกับสถานะของโปรเจกต์ก่อนหน้าตอนประกาศ
  • อินเทอร์เฟซหลักรองรับฟีเจอร์ที่ต้องการเกือบทั้งหมดแล้ว และมีการเขียน extension หลายตัวเพื่อยืนยันว่าการออกแบบใช้งานได้จริง
  • เอกสารยังค่อนข้างหยาบอยู่บ้าง แต่ คู่มืออ้างอิง เสร็จสมบูรณ์และใช้งานได้แล้ว
  • ปัญหาหลายอย่างอาจยังไม่ปรากฏจนกว่าจะมีคนใช้กับงานจริง
  • ยังมีฟีเจอร์ที่อยากเพิ่มในอนาคต และคาดหวังว่าหลังเผยแพร่แล้วคนอื่น ๆ จะเข้ามาดูด้วย
  • อินเทอร์เฟซสาธารณะบางส่วนอาจต้องคิดใหม่ตาม insight ที่เพิ่มขึ้น
  • เวอร์ชันแรกคือ 0.1 และจะอยู่ในเวอร์ชัน 0.x ไปอีกระยะเพื่อรวบรวม feedback แก้บั๊ก และเก็บรายละเอียดส่วนที่ยังหยาบ
    • คาดว่าระยะเวลาอย่างน้อยประมาณ 1 ปี
  • ไลเซนส์คือ MIT เช่นเดียวกับโปรเจกต์ก่อนหน้า
  • เคยพิจารณาไลเซนส์ที่จำกัดกว่านี้ แต่เลือกไลเซนส์แบบ permissive เพราะสนใจให้มีการใช้งานอย่างแพร่หลายมากกว่า

นโยบายเกี่ยวกับโมเดล AI, การสร้างโค้ด และ pull request

  • ไม่มีการใช้ language model ในการสร้างซอฟต์แวร์นี้
  • เนื่องจากโค้ด JavaScript อยู่บนเว็บและเอกสารถูกเผยแพร่ จึงมองว่าไม่มีวิธีที่น่าเชื่อถือในการป้องกันไม่ให้โค้ดและไอเดียที่เผยแพร่แล้วเข้าไปอยู่ใน large language model
  • Wordgard ทดลองไม่รับ pull request ซึ่งต่างจากแนวปฏิบัติมาตรฐานของโอเพนซอร์ส
  • กระบวนการรีวิวการเปลี่ยนแปลงขนาดใหญ่และปรับให้ตรงกับความคาดหวังมักใช้แรงงานมากกว่าการ implement เอง
  • เมื่อต้นทุนการสร้างโค้ดลดลงมาก โครงสร้างที่คนอื่นโยนโค้ดมา แล้ว maintainer ต้องรีวิว ดูแลต่อ หรืออธิบายเหตุผลในการปฏิเสธ ก็ยิ่งไม่น่าสนใจมากขึ้น

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

 
GN⁺ 4 시간 전
ความคิดเห็นบน Lobste.rs
  • ในฐานะผู้เขียน หากมีคำถามหรือฟีดแบ็ก ผม/ฉันจะเข้ามาดูเธรดนี้เป็นระยะ

    • ดูน่าทึ่งทีเดียว ใน FAQ ไม่เห็นมีพูดถึง เลยสงสัยว่าจะใช้หรือกำหนดค่าอย่างไรกับ การแก้ไข Markdown
      น่าจะสร้าง HTML ด้วย Markdown renderer แล้วให้แก้ไขใน Wordgard ได้ แต่หลังจากนั้นจะดึง Markdown ออกจากเนื้อหาในตัวแก้ไขได้อย่างไร?
    • สงสัยว่าคนที่ใช้ ProseMirror จะมีเส้นทางการย้ายอย่างไร
      สุดท้ายจะย้ายไป Wordgard กันไหม? ถ้ามีคนจะใช้ ProseMirror ในโปรเจกต์ใหม่ ควรเลือก Wordgard เมื่อไหร่?
  • Contains 0% AI

    Not having PRs is an effective way to nip the problem of people submitting LLM-generated slop code in the bud.

    และยังมีงานอาร์ตสวย ๆ ที่ทำโดย ศิลปินมนุษย์ตัวจริง ด้วย
    ดีเลย

  • ขอแสดงความยินดีอย่างยิ่งกับโปรเจกต์และการเปิดตัวของ Marijn ดูยอดเยี่ยม และผม/ฉันก็ชอบ งานอาร์ตของ Kamila Stankiewicz ด้วย

  • โฮมเพจหลักของโปรเจกต์คือ https://wordgard.net/

  • As a deviation from standard open-source practice, I'm doing an experiment where I don't take pull requests for Wordgard.

    ส่วนนี้ โดยเฉพาะทั้งย่อหน้าสุดท้าย น่าสนใจมากจริง ๆ
    ก็สงสัยเหมือนกันว่าวิธีแบบนี้อาจพบเห็นได้บ่อยขึ้นไปอีกสักระยะ จนกว่าเราจะมีความสัมพันธ์ที่ดีกว่านี้กับ การสร้างโค้ดด้วย AI หรือไม่ก็เลือกที่จะไม่ข้องเกี่ยวกับมันเลย
    หมายเหตุ โค้ดใช้ไลเซนส์ MIT