- เป็นรูปแบบไฟล์เก็บถาวร HTML แบบไฟล์เดียวที่เว็บเบราว์เซอร์สามารถทำ lazy-loading ได้อย่างมีประสิทธิภาพ โดยรวมทุกแอสเซ็ตไว้ครบถ้วน พร้อมบรรลุทั้งความเป็นสแตติก ความเป็นไฟล์เดียว และประสิทธิภาพไปพร้อมกัน
- เป็นโครงสร้างที่นำ HTML ต้นฉบับและแอสเซ็ตในรูปแบบ tarball มาต่อเข้าหลังส่วนหัว HTML และ JavaScript แล้วให้ JS โหลดเฉพาะส่วนที่จำเป็นผ่าน HTTP Range request
- โซลูชันเดิมอย่าง SingleFile หรือ MHTML มีความเป็นสแตติกและเป็นไฟล์เดียว แต่ยังขาดประสิทธิภาพ และ Gwtar เข้ามาแก้ปัญหานี้
- ทำงานได้ด้วย ความสามารถมาตรฐานของเบราว์เซอร์เท่านั้น โดยไม่ต้องตั้งค่าเพิ่มเติมฝั่งเซิร์ฟเวอร์ และในบางสภาพแวดล้อมอย่าง Cloudflare จะรองรับด้วย MIME type
x-gwtar
- ช่วยรักษาทั้ง ความคงทนในการเก็บรักษา และ การเข้าถึงได้ ของหน้า HTML ขนาดใหญ่ จึงเหมาะกับการทำ web archiving ระยะยาวและการเก็บรักษาสื่อวิจัยที่ทำซ้ำได้
ภาพรวมของ Gwtar
- Gwtar คือ รูปแบบไฟล์เก็บถาวรแบบ Polyglot ใหม่ที่ประกอบด้วย ไฟล์ HTML เดียว โดยเบราว์เซอร์จะโหลดเฉพาะส่วนที่ต้องใช้ผ่าน HTTP Range request
- ถูกใช้เพื่อให้บริการคลัง HTML ขนาดใหญ่ของ Gwern.net
- JS ในส่วนหัว HTML จะหยุดการดาวน์โหลดไฟล์ทั้งก้อน และโหลดเฉพาะแอสเซ็ตที่จำเป็นด้วย partial request (range request)
- ผลลัพธ์คือเซิร์ฟเวอร์ให้บริการเพียงไฟล์ HTML เดียว แต่ผู้ใช้จะดาวน์โหลดเฉพาะแอสเซ็ตที่จำเป็น
- ทุกความสามารถถูกสร้างขึ้นด้วยฟังก์ชันมาตรฐานของเบราว์เซอร์ จึงมี ความเข้ากันได้ในอนาคต
ไตรภาวะกลืนไม่เข้าคายไม่ออกของการเก็บถาวร HTML
- การเก็บถาวร HTML มีข้อจำกัดเดิมที่ทำได้เพียงสองในสามอย่างระหว่าง ความเป็นสแตติก, การเป็นไฟล์เดียว, และ ประสิทธิภาพ
- เช่น SingleFile เป็นสแตติกและเป็นไฟล์เดียว แต่ไม่มีประสิทธิภาพ ส่วน WARC เป็นสแตติกและมีประสิทธิภาพ แต่ไม่ใช่ไฟล์เดียว
- สแนปช็อตที่สร้างด้วย SingleFile ให้หน้าเว็บสแตติกสมบูรณ์ แต่ inline แอสเซ็ตทั้งหมดด้วย Base64 ทำให้ไฟล์มีขนาดใหญ่ถึงหลายร้อย MB
- ผู้ใช้แม้จะดูเพียงบางส่วนของหน้า ก็ยังต้องดาวน์โหลดทั้งไฟล์ ทำให้ไม่มีประสิทธิภาพ
- Gwern.net เคยแก้ปัญหานี้ด้วย deconstruct_singlefile.php เพื่อแยกแอสเซ็ตออกมา แต่ก็สูญเสียความเป็นไฟล์เดียว
แนวทางเชิงเทคนิคของ Gwtar
- ใช้ HTTP Range request เพื่อให้ ดาวน์โหลดเฉพาะบางส่วนของไฟล์ได้อย่างเลือกสรร
- ใช้ โครงสร้างไฟล์เก็บถาวรแบบ concatenated ที่รวม HTML + ส่วนหัว JS ไว้ด้านหน้า แล้วตามด้วย tarball
- ใช้คำสั่ง
window.stop() ใน JS เพื่อหยุดการดาวน์โหลดหลังส่วนหัว และร้องขอเฉพาะแอสเซ็ตที่จำเป็น
- เบราว์เซอร์เรนเดอร์เหมือน HTML ปกติ ขณะที่ JS จะดักคำขอแอสเซ็ตแล้วแปลงเป็น Range request
การสร้างและการนำไปใช้
- สามารถแปลง SingleFile HTML เป็น Gwtar ได้ด้วยสคริปต์ PHP deconstruct_singlefile.php
- รองรับการบีบอัดซ้ำ JPG/PNG/GIF และการเพิ่มข้อมูล PAR2 FEC (การแก้ไขข้อผิดพลาดล่วงหน้า)
- หลัง JS ทำงาน เบราว์เซอร์จะโหลดเฉพาะแอสเซ็ตที่จำเป็นผ่าน Range request และหากปิด JS จะเปลี่ยนไปดาวน์โหลดทั้งไฟล์แทน
- ด้วยการยึดตามมาตรฐาน จึง ไม่ต้องตั้งค่าเซิร์ฟเวอร์หรือใช้ซอฟต์แวร์เพิ่มเติม และยังสามารถกู้คืนจากไฟล์เดียวกลับเป็น HTML แบบหลายไฟล์ได้
ประสิทธิภาพและความเข้ากันได้
- หากไม่รองรับ Range request จะดาวน์โหลดทั้งไฟล์ แต่ยังพอชดเชยความเร็วได้ด้วย การบีบอัด gzip/Brotli
- Cloudflare จะลบ Range header ของการตอบกลับ
text/html ออก ดังนั้น Gwern.net จึงเลี่ยงปัญหาด้วยการตั้ง MIME type เป็น x-gwtar
- ไม่สามารถเปิดดูไฟล์ในเครื่องได้ :
- จุดนี้เหมือนกับ SingleFileZ เช่นกัน เพราะนโยบายความปลอดภัยของเบราว์เซอร์ (เช่น CORS) จะบล็อกคำขอจาก JS
- แม้น่าเสียดาย แต่ถูกมองว่าเป็น trade-off ที่ยอมรับได้ และการเปิดดูแบบโลคัลสามารถแก้ได้ด้วยการแปลงเป็นไฟล์ที่ไม่พึ่งพา JS
ความสามารถในการขยาย
- สามารถแนบ ข้อมูลไบนารีเพิ่มเติม ที่ท้ายไฟล์ Gwtar ได้ (เช่น FEC, ลายเซ็น, เมทาดาทา)
- ใช้ PAR2 เพื่อกู้คืนได้เมื่อบางส่วนของไฟล์เสียหาย
- สามารถแทรกลายเซ็น GPG ในรูปแบบคอมเมนต์ HTML เพื่อ ตรวจสอบความสมบูรณ์ ได้
- ในเวอร์ชันถัดไปมีแผนเพิ่ม การตรวจสอบแฮชของแอสเซ็ต, prefetch อัตโนมัติ, การบีบอัดในตัว, การรองรับหลายหน้า เป็นต้น
ความเป็นไปได้ในการใช้งาน
- เหมาะกับหน้า HTML ขนาดใหญ่หรือ ชุดข้อมูลวิจัย (เช่น SQLite3) ที่ใช้ในงานวิทยาศาสตร์แบบทำซ้ำได้
- สามารถโหลดฐานข้อมูลในเบราว์เซอร์โดยตรงผ่าน Range request เพื่อนำมาวิเคราะห์ได้
- ถูกเสนอให้เป็น รูปแบบสำหรับ web archiving ที่รักษาได้พร้อมกันทั้งความคงทนระยะยาวและการเข้าถึง
ไลเซนส์และการพัฒนาในอนาคต
- เอกสารและโค้ดของ Gwtar เผยแพร่ภายใต้ CC-0 public domain
- ในเวอร์ชันถัดไป (v2) กำลังพิจารณา การบังคับใช้ FEC, การบีบอัดในตัว, การรองรับหลายเอกสาร, การปรับปรุงการกำจัดข้อมูลซ้ำซ้อน เป็นต้น
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
วันนี้เพิ่งรู้จัก window.stop() เป็นครั้งแรก
ฟังก์ชันนี้ใช้หยุดไม่ให้เบราว์เซอร์โหลดทรัพยากรเพิ่มเติม
เบราว์เซอร์หลัก ๆ รองรับมานานเกิน 10 ปีแล้ว (เอกสาร MDN, Can I Use)
ดูตัวอย่างการใช้งานได้จากภาพหน้าจอนี้
รายละเอียดเพิ่มเติมฉันสรุปไว้ในบล็อกโพสต์ของฉัน
แต่ถ้าต้องการทำ download หรือ lazy-loading เองในลอจิกแบบ server-centric มันก็อาจเป็นแนวทางที่น่าสนใจ
นอกจากกรณีพิเศษอย่างสคริปต์เริ่มต้นระบบหรือรีไดเร็กต์แล้ว ก็ไม่ค่อยอยากแนะนำเท่าไร
ฉันเผยแพร่ไฟล์เป็นชังก์ base64 ที่บีบอัดผ่านตัว bundler ที่ทำเอง ซึ่งคล้ายกับวิธีนี้
ถ้ามันทำงานได้ในสภาพแวดล้อมการแชร์ไฟล์เดี่ยวแบบนี้ ก็แอบคิดว่าแพลตฟอร์มอาจจะบล็อกมัน
ใน PHP ก็มีฟังก์ชันคล้ายกันคือ __halt_compiler() เลยเคยใช้มันเพื่อใส่เอกสารหรือข้อมูลไว้ท้ายไฟล์โดยไม่ต้องคอมเมนต์
ตอนแรกก็น่าสนใจ แต่พอเห็นว่าฟอร์แมตนี้เปิดจาก ไฟล์ในเครื่อง โดยตรงไม่ได้ก็เริ่มลังเล
ถ้าเป็นฟอร์แมตสำหรับเก็บถาวร การเข้าถึงแบบโลคัลก็น่าจะเป็นกรณีใช้งานหลักอย่างหนึ่ง
แต่ถ้าเปิดจากโลคัลโดยตรงไม่ได้ ข้อดีก็ลดลงไปมาก (ดูแนวคิด backdoor pilot)
ทั้งรูปภาพ CSS และ JS ใส่ inline เป็น data-uri ได้หมด รวมถึงฟอนต์ด้วย
กลับกัน ถ้าฟอร์แมตเอกสารของโปรแกรมประมวลผลคำใช้ HTML ก็น่าจะยืดหยุ่นกว่านี้
python -m http.serverเพื่อเปิดโลคัลเซิร์ฟเวอร์ก็แก้ได้ง่ายใช้คำสั่ง Claude ก็ได้เหมือนกัน
ถ้าผู้เขียนมาเห็นคอมเมนต์นี้ อยากให้เพิ่ม ฟิลด์ภาพหน้าจอแบบ BASE64, ฟิลด์คำอธิบาย และ ISO timestamp ในฟอร์แมตเก็บถาวร
ถ้าต่อไปเก็บได้หลายเวอร์ชันของ URL เดียวกัน และมีฟีเจอร์ ลบทรัพยากรซ้ำซ้อน ได้ด้วยก็คงยิ่งดี
ไม่เข้าใจว่าทำไมผู้เขียนถึงมอง WARC ในแง่ลบ
กลับกัน Gwtar ดูซับซ้อนกว่าและยืดหยุ่นน้อยกว่าด้วยซ้ำ
อยากรู้ว่าทำไมถึงบอกว่าฟอร์แมต ZIP/HTML polyglot ของ SingleFileนั้น “คงที่และเป็นไฟล์เดียว แต่ไม่มีประสิทธิภาพ”
เมื่อเทียบกับ Gwtar แล้ว จุดไหนที่ไม่มีประสิทธิภาพกว่ากัน?
ประเด็นสำคัญคือเบราว์เซอร์สามารถใช้ range request เพื่อดึงเฉพาะส่วนที่ต้องใช้ได้หรือไม่ โดยไม่ต้องโหลดทั้งไฟล์ก่อน
เป็นไอเดียที่เจ๋งมาก
ฉันคิดว่า เว็บแอป HTML แบบไฟล์เดียว คือรูปแบบซอฟต์แวร์ที่อยู่ได้นานที่สุด
ตัวอย่างที่ฉันทำมี FuzzyGraph และ HyperVault
ฉันก็เคยคิดจะทำอะไรคล้าย ๆ กันในระดับ Service Worker
คือคงหน้าเพจไว้เหมือนเดิม แล้วดักทุก HTTP request
โครงสร้างจะคล้าย window.stop() คือรับมาแค่บางส่วนของ HTML แล้วจัดการส่วนที่เหลือเป็น asset blob
ถ้าใส่ Service Worker เองเป็น dataURI ได้ ก็จะกลายเป็นไฟล์เดียวแบบสมบูรณ์
น่าสนใจ แต่ยังไม่ค่อยเข้าใจว่าทำไม lazy load ถึงจำเป็นสำหรับไฟล์ในเครื่อง
ไฟล์จะใหญ่ขนาดนั้นเลยหรือ? หรือแค่ต้องการคงฟังก์ชันที่มีอยู่แล้วไว้?
ต้องใช้ range request เพื่อขอเฉพาะส่วนที่ต้องใช้ แทนการดึงทั้งไฟล์ผ่านเครือข่าย
แน่นอนว่าการแยกเป็นหลายไฟล์เป็นวิธีที่พบได้บ่อยกว่า แต่บางครั้งการจัดการไฟล์เดียวก็สะดวกกว่า
น่าจะเกี่ยวข้องกับโครงสร้างไซต์ของ Gwern ที่ใช้ MediaWiki ด้วย
เมื่อก่อนฉันก็เคยทำอะไรคล้ายกัน — เป็นโปรเจกต์ชื่อ Zundler ซึ่งเป็นแนวทางที่ค่อนข้าง แฮ็ก ๆ
มันทำงานบนโลคัลได้ด้วย แต่ตอนเริ่มต้นต้องแตกไฟล์บีบอัดทั้งหมดก่อน
แค่อยากรู้ว่ามันหลบ ข้อจำกัดด้านความปลอดภัย ได้อย่างไร
ในคำอธิบายพูดถึงแค่เรื่อง single-origin เลยยังเข้าใจได้ไม่หมด