แปลงภาพเป็น WebP อัตโนมัติผ่าน Cloudflare Workers และ Cloudflare Images
ผ่านไปหลายปี WebP ยังเป็นเรื่องปวดหัวอยู่เรื่อยๆ กูเกิลก็พยายามเหลือเกินที่จะหักคะแนนถ้าไม่ใช้ WebP แต่ใช้ JPEG หรือ PNG มันสะดวกกับชีวิตมากกว่า พอจะหาปลั๊กอินแปลง WebP ส่วนมากก็ไม่ฟรี หรือต้องคอนฟิกอะไรเพิ่มอีกเยอะแยะ ปวดหัว
คือเมื่อไม่นานมานี้ Cloudflare สุดที่รักของเราได้เปิดให้ใช้บริการแปลงภาพเป็น WebP ได้ฟรีๆ ผ่านบริการ Cloudflare Images (แต่เดิมแถมมากับแพ็คเกจโปร แต่ตอนนี้ออกมาขายเป็นแพ็คเกจแรก และมีรุ่นฟรีให้ใช้งาน) ข้อจำกัดของ Cloudflare Images รุ่นฟรีมีดังนี้
- คิดค่าแปลงเริ่มต้น $0.5 ต่อ 1,000 ครั้งต่อเดือน (ถ้าใช้ไม่ถึง ไม่ต้องจ่าย) เรียกดูกี่ครั้งก็ได้ สิ้นเดือนนับใหม่
- 1 รูป แปลง 5 ขนาด = คิด 5 ครั้ง
- รูปที่แปลงแล้ว สามารถโยนไปเก็บไว้ที่ไหนก็ได้ หรือเก็บไว้บน Cloudflare Images ก็ได้เช่นกัน คิดราคา $5 ต่อ 100,000 รูป แปลงได้สูงสุด 20 ขนาด
- 1 รูป แปลง 20 ขนาด = คิด 1 รูป
- รูปที่เก็บไว้บน Cloudflare Images คิดค่าเปิดดู $1 ต่อ 100,000 request
เว็บใหญ่ๆ อาจจะต้องคำนวนค่าใช้จ่ายล่วงหน้ากันหน่อย แต่เว็บเล็กๆ หรือบล็อกส่วนตัวนี่ไม่น่าต้องได้เสียเงิน
มาเรื่องของเรากันต่อ คือ Cloudflare Images มันสามารถสั่งแปลงได้ผ่านทาง URL โดยตรง ด้วยฟอร์แมตแบบนี้
https://<ZONE>/cdn-cgi/image/<OPTIONS>/<SOURCE-IMAGE>
และอีกทางหนึ่งคือใช้ Workers แปลงให้
Workers คือโปรแกรม JavaScript เล็กๆ ที่รันอยู่บน Cloudflare เอาไว้ทำงานฝั่ง Server เช่นแก้ header, ทำ reverse proxy, หรือแปลงไฟล์
ข้อดีคือเราสามารถกำหนดรูปแบบ URL ยังไงก็ได้ตามใจชอบ และด้วยฟีเจอร์ Worker Routes ของ Cloudflare เอง ทำให้เราสามารถกำหนด Workers Routes ให้เสียบไปอยู่ที่ subdirectory ของเว็บเราได้ทันที (อย่างเช่นผมกำหนดให้ Workers ไปเสียบอยู่ที่ /wp-contents/uploads
เอาไว้เลย) ทำให้เราไม่จำเป็นต้องแก้ไข URL ใดๆ บนเว็บเรา แค่ดีพลอยและคอนฟิกเพิ่มนิดหน่อย ใช้ได้เลย
Worker ที่ว่า คือตัวนี้
https://github.com/IronGhost63/cf-worker-image-transformer
โคลนโปรเจ็กท์ลงมาเก็บไว้ก่อน จากนั้นเข้าไปที่โฮสต์ของเรา (ผมใช้ Cloudways) แล้วจัดการเพิ่มโดเมนสำรอง (เป็นซับโดเมนเว็บหลักก็ได้) และคอนฟิก A Record ใน DNS ให้เรียบร้อย เช่น
โดเมนหลัก: jirayu.in.th
โดเมนสำรอง: web.jirayu.in.th
ส่วนฝั่ง DNS ก็กำหนด A Record ให้ชี้ไปที่ไอพีแอดเดรสเดียวกับโดเมนหลัก เอาเป็นว่าถ้าเข้าเว็บหลักด้วยโดเมนสำรองได้ก็ถือว่าเรียบร้อย
เหตุที่เราต้องมีโดเมนสำรอง เพราะว่าพอ worker ของเราเสียบไปที่ /wp-content/uploads/*
แล้ว ทุกรีเควสท์ที่ส่งมาที่นี่จะถูกจัดการโดย worker ซึ่ง worker ของเราก็จะมีการเรียกไปที่พาธนี้เพื่อดึงรูปภาพเช่นกัน และจะเกิด infinite request loop ขึ้น ทางแก้คือเราเพิ่ม entry point ใหม่เข้าไปให้ worker ไปเรียกใช้แทน จะได้ไม่ติดลูป
เอาล่ะ เสร็จแล้วกลับมาที่ worker ที่เราโคลนเอาไว้ ให้ก็อปไฟล์ wrangler.example.toml
ตั้งชื่อใหม่เป็น wrangler.toml
แล้วแก้ค่า IMG_HOST
ให้เป็นโดเมนสำรองที่เราสร้างเอาไว้ จากนั้นดีพลอยขึ้น Cloudflare Workers ได้เลย
หลังดีพลอยเสร็จแล้วก็เข้าไปที่หน้าจัดการโดเมนของเราบน Cloudflare ไปที่เมนู Workers Routes จากนั้นสร้าง route ใหม่ขึ้นมา กำหนดค่าดังนี้
[Route]
https://<โดเมนหลัก>/wp-content/uploads/*
[Worker]
<เลือกตัวที่เราเพิ่งดีพลอยไป>
บันทึกการตั้งค่าให้เรียบร้อย ทีนี้ก็น่าจะพร้อมใช้งานแล้ว
ถ้าเราลองไปเปิดแท็บ Network ใน DevTools ดู เลือกไฟล์รูปของเราแล้วเจอว่า Content-Type: image/avif
และ X-Workers-Hello: WP63
ก็ถือว่าเรียบร้อยแล้ว
สำหรับเว็บที่รูปภาพเยอะๆ แนะนำให้ fork โปรเจ็กท์ออกไป แล้วเขียนให้มันเก็บภาพเพิ่มเอาครับ
อนึ่ง โค้ดเป็นแค่ PoC แนะนำว่าใครอยากเอาไปใช้จริง ควรแก้เพิ่มครับ