2 คะแนน โดย GN⁺ 2024-05-19 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เป็นไลบรารีที่ช่วยให้นักพัฒนา Go สามารถสร้าง GUI แบบ immediate mode สำหรับหลายระบบปฏิบัติการและ WebAssembly ได้
  • รองรับ ขอบเขตแพลตฟอร์ม ที่กว้าง ตั้งแต่ Linux, macOS, Windows, Android, iOS, FreeBSD, OpenBSD ไปจนถึง WebAssembly
  • ออกแบบมาเพื่อลดการพึ่งพา และใช้ ไลบรารีของแต่ละแพลตฟอร์ม สำหรับการจัดการหน้าต่าง, อินพุต และการวาดด้วย GPU
  • การเรนเดอร์มี Pathfinder vector renderer ที่ทำงานบน OpenGL ES และ Direct3D 11 และกำลังย้ายไปใช้คอมพิวต์เชดเดอร์เรนเดอเรอร์ที่อิงกับ piet-gpu
  • เรนเดอร์ข้อความและรูปทรงด้วย เส้นขอบ แทนการ bake เป็นเท็กซ์เจอร์ จึงรองรับแอนิเมชัน, การวาดแบบแปลงรูป, และความเป็นอิสระจากความละเอียดพิกเซล

จุดประสงค์และขอบเขตการรองรับของ Gio

  • Gio เป็นไลบรารีสำหรับสร้าง GUI ที่มีประสิทธิภาพ ลื่นไหล และพกพาได้ด้วย Go
  • แพลตฟอร์มที่รองรับคือ Linux, macOS, Windows, Android, iOS, FreeBSD, OpenBSD, WebAssembly
  • มีเดโม WebAssembly สำหรับการสาธิตอย่างรวดเร็ว และต้องใช้ เบราว์เซอร์ที่รองรับ WebAssembly ในการรัน
  • สามารถดูซอร์สตัวอย่างได้ที่ Kitchen project

การติดตั้งและเส้นทางการเรียนรู้

  • Gio ถูกออกแบบโดยมีเป้าหมายคือ การพึ่งพาให้น้อย
  • สามารถตรวจสอบ dependency ที่จำเป็นได้จากเอกสารการติดตั้งของแต่ละแพลตฟอร์ม
  • หลังติดตั้งแล้วสามารถเริ่มได้จากเอกสาร Learn และ Hello World
  • ในโชว์เคสมี godcr, Tailscale, gotraceui, Sointu, Protonet รวมอยู่ด้วย

เทคโนโลยีการเรนเดอร์

  • Gio ผสานความยืดหยุ่นของแนวคิดกราฟิกแบบ immediate mode เข้ากับ เทคโนโลยีกราฟิก 2D สมัยใหม่
  • vector renderer อิงจาก Pathfinder project และทำงานบน OpenGL ES และ Direct3D 11
  • เรนเดอเรอร์กำลังย้ายไปสู่ เรนเดอเรอร์แบบคอมพิวต์เชดเดอร์ ที่มีประสิทธิภาพมากกว่า ซึ่งสร้างบน piet-gpu
  • ข้อความและรูปทรงจะ เรนเดอร์โดยใช้เฉพาะเส้นขอบ โดยไม่ bake ล่วงหน้าเป็นภาพเท็กซ์เจอร์
    • รองรับแอนิเมชันได้อย่างมีประสิทธิภาพ
    • เหมาะกับการวาดที่มีการแปลงรูป
    • คงความเป็นอิสระจากความละเอียดพิกเซลได้

โมเดลการสนับสนุน

  • เงินทุนสำหรับการพัฒนา Gio มาจาก การสนับสนุน
  • หากโปรเจกต์นี้มีประโยชน์ คุณสามารถพิจารณาสนับสนุนได้ที่ Gio project บน OpenCollective หรือสนับสนุนนักพัฒนาโดยตรง

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

 
GN⁺ 2024-05-19
ความคิดเห็นจาก Hacker News
  • พอลองใช้งานจริงแล้ว รู้สึกว่าเอามาสร้าง แอปที่ซับซ้อนจริงจัง ไม่ได้
    ไม่มีคอมโพเนนต์อย่างวิดีโอ แผนที่ หรือ rich text ที่แพลตฟอร์มอื่นมีมาให้เป็นพื้นฐาน และก็ไม่มีแนวทางที่ชัดเจนและง่ายในการเพิ่มเข้าไปเอง
    API พังทุก ๆ ไม่กี่เดือน และก็ไม่มีวิธีใส่ธีมด้วย
    กราฟิกแบบ immediate mode นั้นดีจนกว่าจะต้องจัดการ state ที่ซับซ้อน แต่พอถึงจุดนั้นสุดท้ายก็ต้องไปทำ retained mode graphics ขึ้นมาเอง เลยกลายเป็นการดึงปัญหาเก่าที่ถูกแก้ไปนานแล้วกลับมาอีก
    เรนเดอเรอร์หรู ๆ ที่อิงกับ piet-gpu ก็รับอินพุตเป็นแค่จุดควบคุมของเส้นเบซิเยร์แล้วทำ tessellation ทั้งหมด ดังนั้นแม้คอนเซปต์จะดูเท่ แต่เวลาวาดวงกลมจริง ๆ ก็ต้องพึ่งการประมาณด้วยเบซิเยร์ 4 เส้น
    Wasm ยังใกล้เคียงกับงานพิสูจน์แนวคิดที่ทีมคอมไพเลอร์ต้องขัดเกลาเชิงวิศวกรรมอีกหลายปีกว่าจะถึงระดับพร้อมใช้งานจริง และโดยรวมแล้วมันดูโอเคสำหรับนักพัฒนา Go ที่จะทำ UI เรียบง่ายอย่างลิสต์กับช่องกรอกข้อมูล

    • ใช้สิ่งนี้ทำอะไรก็ได้ และใน v0.6 ปัญหาเหล่านี้จัดการง่ายขึ้นมากแล้ว
      มีธีม Material Design และมีทั้งโหมดสว่าง/มืด
      ตัวอย่างแอป gioui ที่ยอดเยี่ยมซึ่งมีทั้งธีมสว่าง/มืดและธีมแบบกำหนดเองคือ https://github.com/chapar-rest/chapar
      บน Mac หรือ Windows ก็แค่ go run .
      kerning ของข้อความ, ข้อความที่ไหลตามส่วนโค้ง, และ RTL/LTR ก็ทำได้ด้วย github.com/go-text/typesetting
      วิดเจ็ตซับซ้อนอย่าง calendar spinner หรือไดอะแกรมก็มีอยู่บน GitHub แต่ยังขาดความพยายามในการรวบรวมสิ่งเหล่านี้เข้าด้วยกัน
      ถ้าสิ่งเหล่านี้ถูกรวมกันได้ ก็น่าจะมีแรงจูงใจมากพอให้มีนักพัฒนาเข้ามามากขึ้น
    • การเปลี่ยน API ที่ทำให้พังทุกไม่กี่เดือน พบเห็นได้บ่อยอย่างน่าหดหู่ในโค้ดของ Google
      ดูเหมือนจะไม่มีวัฒนธรรมที่ให้ความสำคัญกับการไม่ทำให้โค้ดของผู้ใช้พัง
    • ถ้า Wasm สำคัญ Uno Platform รองรับได้ค่อนข้างดี และก็มี AvaloniaUI ด้วย
      ตอนนี้ทั้งคู่เสถียรและมีชุดคอนโทรลกับไลบรารีที่ค่อนข้างครบ
  • บนเว็บมันดูเหมือน Flutter ตรงที่เรนเดอร์ทุกอย่างลงบนแคนวาส ซึ่งเป็นแนวทางที่ขึ้นชื่อว่ามีปัญหาเรื่อง การเข้าถึง และความรู้สึกแบบเนทีฟ

    • บนเว็บมันไม่ได้ให้ความรู้สึกแบบเนทีฟจริง ๆ และการเข้าถึงก็ไม่ดี
      ใช้ Tab ย้ายระหว่างปุ่มวิทยุไม่ได้ และบน macOS CMD+A ก็ไม่ได้เลือกข้อความทั้งหมดในช่องข้อความ แต่ CTRL+A ทำได้
    • สงสัยว่ามีแนวทางดัดแปลงที่วาง DOM ที่มองไม่เห็นไว้ข้าง ๆ แคนวาสเพื่อรองรับการเข้าถึงหรือไม่
      ฟังดูน่าจะทำได้ แต่ปริมาณงานก็คงไม่น้อย
    • บน iPhone แม้แต่การคัดลอกหรือวางก็ใช้ไม่ได้เลย
    • แต่เดิมนี่ไม่ใช่เว็บแอปเฟรมเวิร์กอยู่แล้ว มันเป็น native GUI toolkit ที่ใกล้เคียงกับการมีเว็บแบ็กเอนด์มากกว่า
  • แม้จะออกนอกประเด็นไปนิด แต่ช่วงนี้ผมสงสัยว่าวิธีที่ดีที่สุดในการสร้าง แอปมือถือและเว็บแบบข้ามแพลตฟอร์ม คืออะไร
    ไม่ว่าจะเป็นกรณีที่แชร์ทั้ง business logic และ UI หรือแชร์แค่ business logic ก็ตาม
    เคยชั่งใจระหว่างตัวเลือกอย่าง gomobile, Rust, TypeScript
    ช่วงหนึ่ง TypeScript ดูเหมือนเป็นเทคโนโลยีที่พกพาได้ดีที่สุดจนคิดจะใช้กับ business logic ทั้งหมด แต่ก็พบว่าไม่มีวิธีดี ๆ ในการรัน JavaScript บน iOS ด้วยประสิทธิภาพที่น่าพอใจ

    • ตอนนี้ Flutter น่าจะเป็นตัวเลือกที่ดีที่สุด: https://flutter.dev/
      ถ้าเขียน UI แบบ native และแชร์เฉพาะ business logic ก็ใช้ Kotlin ได้เช่นกัน: https://kotlinlang.org/docs/multiplatform.html#kotlin-multip...
      ถ้าใช้ Compose ก็ทำ UI ด้วย Kotlin ได้: https://www.jetbrains.com/lp/compose-multiplatform/
      แต่การรองรับ iOS ยังอยู่ในระดับ alpha และเว็บยังเป็น “experimental” ดังนั้นถ้าไม่อยากรับความเสี่ยงที่ต้องแก้โค้ดตามการพัฒนาของเฟรมเวิร์ก Flutter ที่ค่อนข้างเสถียรแล้วในทุกแพลตฟอร์มน่าจะเหมาะกว่า
      ถ้าคุ้นกับ TypeScript และ React อยู่แล้ว React Native ก็เป็นตัวเลือกที่น่าพิจารณา แต่เรื่องประสิทธิภาพบน iOS หรือที่อื่น ๆ ยังพูดรับประกันได้ยาก: https://reactnative.dev/
    • ถ้าต้องการแอปที่ขัดเกลามาดี native UI คือคำตอบ
      เจอเฟรมเวิร์กที่สัญญาว่าจะแก้ได้ทุกอย่างแต่ทำไม่ได้จริงมาเยอะเกินไปแล้ว
      ตอนแรกเริ่มต้นได้เร็วกว่า แต่ไม่นานหลังจากนั้นพอมี OS อัปเดต ก็ต้องไปแพตช์ไลบรารีหลักเพื่อให้ FPS ใกล้เคียง native หรือให้ system animation ดูเหมือนเดิมมากขึ้น
      จะประหยัดเวลาได้ก็ต่อเมื่อไม่ได้ตั้งใจขัดเกลา UI
      แต่ logic หลักยังแชร์กันได้
      ผมใช้ gomobile และโดยรวมก็ชอบ แต่ runtime overhead 3MB ทำให้ไม่เหมาะกับเว็บ
      Kotlin Multiplatform ดูดี แต่ขาดไลบรารีพื้นฐานหลายอย่าง และเพราะ Kotlin Android มีของพวกนี้อยู่แล้ว คนเลยไม่ค่อยทำเวอร์ชันข้ามแพลตฟอร์มกัน
      Rust กับชั้น language binding ของ Mozilla ก็ดูน่าสนใจ แต่ยังไม่ได้ลองใช้
    • แนะนำ React Native คู่กับ Expo
      Flutter ก็ไม่เลว แต่บนเว็บมันเรนเดอร์ลง canvas เลยให้ความรู้สึกและการเข้าถึงที่ไม่ค่อยดี
      บน iOS เองก็ยังมีปัญหาเรื่อง latency แม้จะใช้เอนจินเรนเดอร์ Impeller แล้วก็ตาม
      ดูจากไคลเอนต์ Bluesky แล้ว ประสิทธิภาพถือว่าโอเคในทุกแพลตฟอร์มที่รองรับ และใช้ codebase เดียว
      https://github.com/bluesky-social/social-app
    • มี Uno(https://platform.uno)
      เป็นโอเพนซอร์ส และรองรับ Android, iOS, Windows, Mac, Linux: https://platform.uno/platforms/
      ใช้ C# และสร้าง view กับ control โดยอัตโนมัติด้วย native UI framework ของแต่ละแพลตฟอร์ม
      รองรับ IDE อย่าง Visual Studio, VS Code, Rider ได้ดี และไม่ได้ถูกจำกัดว่าต้องใช้เครื่องมือเฉพาะ
      ยังมีปลั๊กอิน Figma สำหรับการทำงานร่วมกับทีมออกแบบด้วย
    • พวกเราใช้ Tauri แต่จุดสำคัญคือตอนนี้ใช้กับเครื่องมือภายในเท่านั้น
      ไม่แน่ใจว่าเป็นเครื่องมือที่ดีสำหรับผลิตภัณฑ์ผู้บริโภคด้วยหรือไม่
      แต่สำหรับงานที่เราใช้มันเหมาะมาก เพราะส่วนใหญ่เป็นเครื่องมือสำหรับช่างเทคนิคโรงไฟฟ้าพลังงานแสงอาทิตย์ และการทำ TypeScript แบบข้ามแพลตฟอร์มในสภาพอินเทอร์เน็ตที่แย่มากกลายเป็นภาระหนักเกินไปสำหรับทีมเล็ก ๆ
  • ผมกำลังทำ แอปสตรีมมิง ด้วย gioui อยู่ และมันง่ายมาก แถมการอัปเกรดก็ราบรื่นเสมอ
    เพราะมันเป็น Go และทีมพัฒนาหลักก็จริงจังกับการเปลี่ยนแปลงพอสมควร
    เวลาต้องการเว็บ GUI ก็ใช้ระบบปลั๊กอิน gioui นี้: https://github.com/gioui-plugins/gio-plugins
    น่าทึ่งที่ WebView ใช้งานได้ทั้งบนเว็บ เดสก์ท็อป และมือถือ
    รองรับ deep link ด้วย ดังนั้นถ้าส่งอีเมลหรือลิงก์การแจ้งเตือน Monike แอปของผู้ใช้จะเปิดไปยังตำแหน่งที่ถูกต้องใน GUI ได้เลย
    ยังมีการแจ้งเตือนและ share extension สำหรับทุก OS จึงมองว่าเกือบเป็นระบบที่สมบูรณ์แล้วจริง ๆ
    ผมเข้าใจดีว่าการรองรับทุก OS เป็นเรื่องยาก แต่โลกทุกวันนี้มีความหลากหลายเป็นพื้นฐานอยู่แล้ว
    ผมชอบที่ทำทั้งหมดนี้ได้ด้วย Go อย่างเดียว โดยไม่ต้องสลับไปมาระหว่างหลายเทคโนโลยี
    ฝั่ง Go backend จะเขียนให้ทำงานได้เสมอทั้งกับ gio และ HTML
    ถ้าต้องการ SEO หรือการเล่นวิดีโอ ก็จัดการใน WebView ได้ และยังทำให้ Google SEO ฝั่งเว็บของ gio พอใจได้ด้วย
    ใส่ Markdown ลงใน Hugo เพื่อให้ Google SEO มองเห็น

  • ในมุมของคนที่เพิ่งเริ่มใช้ Go ฉันสงสัยส่วนนี้ของเอกสาร
    มีการบอกว่าเหตุผลที่ใช้ op.ColorOp{Color: red}.Add(ops) แทน ops.Add(ColorOp{Color: red}) ก็เพื่อไม่ให้เมธอด Add รับอาร์กิวเมนต์ชนิด interface และหลีกเลี่ยง allocation ตอนเรียกใช้ ซึ่งเป็นแกนสำคัญของแนวทางออกแบบแบบ “zero allocation” ของ Gio
    อยากรู้ว่าทำไมถึงเกิด allocation, มีอะไรที่ถูก allocate, และประหยัดได้อย่างไร

    • เรื่องนี้เกิดจากวิธีที่ Go จัดการ dynamic type ผ่าน interface และวิธีที่ struct เข้ามาเกี่ยวข้องกับสิ่งนั้น
      ถ้าฟังก์ชันรับอาร์กิวเมนต์เป็นชนิด interface แล้วส่ง struct ตรง ๆ เข้าไป Go จะสร้าง wrapper รอบค่านั้น และนี่คือ allocation ที่อ้างถึงในข้อความ
      wrapper นี้เป็นคู่ของพอยน์เตอร์ ซึ่งประกอบด้วยพอยน์เตอร์ไปยัง type/vtable และพอยน์เตอร์ไปยังข้อมูลของ struct
      วิธีนี้ทำให้มีทั้งการอนุมานชนิดตอนรันไทม์และการขยาย interface แบบ implicit ได้
      กล่าวคือ การ implement interface แค่มีเมธอดครบก็พอ ไม่จำเป็นต้องประกาศชนิดแบบชัดเจนเหมือน ByteReader extends Reader
      ค่าใช้จ่ายนี้จะเกิดเฉพาะตอนใช้งาน ดังนั้นโค้ด fast path จำนวนมากจึงพยายามใช้แต่ struct ถ้าเป็นไปได้
    • ใน Go เมื่อทำ v := interfaceType(concreteTypeValue) สิ่งที่เกิดขึ้นในระดับล่างจะประมาณนี้
      dataPtr := &concreteTypeValue, typePtr := typeData[concreteType]() แล้วสร้างค่า interface ที่มีทั้ง data pointer และ type pointer
      ตรงนี้บรรทัดแรกคือ allocation เพราะตามกฎที่ฉันจำได้ พอยน์เตอร์ใน Go จะไม่ชี้ไปยังค่าบนสแตก ดังนั้น concreteTypeValue จึงต้องถูก allocate บนฮีป
      กฎที่ว่าพอยน์เตอร์ไม่ชี้เข้าสแตกมีไว้เพื่อให้สแตกของ goroutine ขยายแบบไดนามิกได้ง่าย
      ดู https://go.dev/doc/faq#stack_or_heap
    • ในวิธีแรก ColorOp{Color: red} ต้องถูก boxing และ allocate ลงฮีป
      เพราะโดยทั่วไป ops.Add รับ fat pointer ไปยังค่าที่ implement interface หนึ่ง ไม่ได้รับค่า concrete type โดยตรง
    • มีคำตอบอื่นตอบประเด็นในคำถามไปแล้ว แต่แยกอีกเรื่องคือ op.ColorOp{Color: red}.Add(ops) อ่านแล้วแปลก
      สำหรับฉันมันเหมือน “เอา ops ไปบวกกับผลลัพธ์ของ op.ColorOp{Color: red}
      เลยอยากตั้งชื่อฟังก์ชันเป็น AddTo: op.ColorOp{Color: red}.AddTo(ops)
      ถึงจะยังไม่ค่อยเป็นธรรมเนียมนัก แต่ก็อย่างน้อยส่งสัญญาณว่าอาร์กิวเมนต์ของฟังก์ชันจะถูกแก้ไข
    • https://stackoverflow.com/questions/39492539/go-implicit-con...
  • น่าสนใจที่บนพีซีค่อนข้างธรรมดาซึ่งใช้ Windows 10 และ Chrome นั้น เดโม WASM ในหน้าแรกเรนเดอร์เป็นสี่เหลี่ยมสีดำตรงตำแหน่งที่ควรมีข้อความ
    แต่บน Chrome ของโทรศัพท์ Android กลับเรนเดอร์ได้ถูกต้อง

    • ไม่ได้เป็นอยู่คนเดียว
      แถมยังทำงานช้ามากด้วย
    • บน Edge ของ Windows 11 ก็เหมือนกัน
  • ฉันเคยทำแอปเล็ก ๆ ด้วย Fyne บน Go และคงไม่ใช้อีกแล้ว
    ทั้ง Gio และ Fyne ยังขาดความขัดเกลาและความสามารถที่ Flutter ให้มาอย่างมาก
    ฉันลงเอยด้วยการเขียนแกนหลักเป็น Golang แล้วห่อเป็นแอป Android เพราะ GUI ดูเหมือนหลุดมาจากปี 2003 และแทบไม่มีทางแก้ได้มากนัก

    • อีกตัวเลือกคือ Wails
      คุณเขียน logic ทั้งหมดด้วย Go ได้ และเขียน UI เป็น HTML จะใช้เว็บเฟรมเวิร์กหรือไม่ใช้ก็ได้
      มันคล้าย Electron แต่เบากว่าเพราะใช้ system web viewer แทนการ bundle Chrome มาด้วย
      [1] https://github.com/wailsapp/wails
    • น่าสนใจ
      ถ้าอธิบายได้ว่าเอาไปห่อเป็นแอป Android อย่างไรจะดีมาก
  • ทำไม GUI ข้ามแพลตฟอร์ม พวกนี้ถึงดูเหมือนถูกออกแบบมาเมื่อ 50 ปีก่อนกันหมด

    • อยากรู้จริง ๆ ว่าในปี 1974 เขาใช้อะไรกันถึงทำให้สิ่งนี้ดูเหมือนของยุคนั้นได้
  • เดโมใช้ไม่ได้สำหรับฉัน
    บน Chromium ของ Win 11 เห็นปุ่มอยู่ไม่กี่ปุ่ม แต่ที่เหลือเกือบทั้งหมดเป็นสีดำ

  • ต่างจาก Fyne ตรงที่ไลบรารีนี้ผ่านบททดสอบแรกที่ฉันโยนให้มันคือ การเรนเดอร์ข้อความ CJK ซึ่งถือเป็นสัญญาณที่ดี
    Fyne ทำแบบนี้ไม่ได้ถ้าไม่ป้อนฟอนต์แบบกำหนดเองเพียงตัวเดียวที่ใช้เรนเดอร์ทุกอย่าง
    การหาฟอนต์ตัวเดียวที่ครอบคลุมระบบอักษรที่ใช้กันทั่วไปทั่วโลกทั้งหมด รวมถึงอีโมจิ ได้อย่างน่าพอใจนั้นแทบต้องพึ่งดวง
    เพราะงั้นถ้าจะทำอะไรที่มีเนื้อหาจากผู้ใช้, เนื้อหาเว็บ หรือมีโอกาสต้องรองรับการแปลภาษาแม้แต่น้อย Fyne ก็หลุดออกจากตัวเลือกของฉันทันที

    • ในแง่นี้ Noto Sans ค่อนข้างดี