บันทึกแปลงร่างบล็อกเป็น Headless WordPress กับ Astro บน Cloudflare Pages

บันทึกแปลงร่างบล็อกเป็น Headless WordPress กับ Astro บน Cloudflare Pages

คือจริงๆ มีแผนนานแล้วว่าจะเปลี่ยนเว็บจาก WordPress เต็มสแต็ค ไปเป็น Headless WordPress ร่วมกับ Static Site Generator สักตัว แผนแรกจะใช้ Gatsby เพราะที่บริษัทเดิมใช้ แต่ตอนหลังเปลี่ยนมาใช้ Astro แทน

หลักการของมันก็ง่ายๆ คือเราเขียนเว็บด้วย Astro ให้เรียบร้อย แล้วตอนบิวด์ static site ก็ให้ต่อไปที่ API ของ WordPress เพื่อดึงข้อมูลมาบิวด์แต่ละหน้าออกมา ด้วยไอเดียมันก็ดี แต่พอใช้งานจริงเจอปัญหาว่ามันต้องต่อ API มาเพื่อดึงข้อมูลทีละหน้าๆ ทำให้ขั้นตอนการบิวด์เว็บไซต์มันนานเกินจำเป็น ยิ่งถ้าคึกกดบิวด์ถี่ๆ (เช่นมีอัปเดตโค้ดนิดๆ หน่อยๆ) มันบิวด์ซ้ำๆ จนเว็บล่มได้เลย

สร้าง API Endpoint เฉพาะสำหรับการบิวด์ Static Site

ทางออกแบบบ้านๆ คือเราสร้าง API Endpoint เพิ่มขึ้นมาอีกตัวหนึ่งเพื่อใช้แสดงข้อมูลบล็อกโพสต์ทั้งหมด ให้ build script มันมาขอทีเดียวแล้วได้เลยทั้งก้อน แต่ตอนทดลองกับบล็อกที่โพสต์เยอะๆ (จริงๆ บล็อกนี้ก็มีโพสต์เยอะอยู่ แต่ unpublish ทิ้งไป) ก็เจอปัญหาเดิมคือคิวรี่ข้อมูลนาน และใช้ทรัพยากรสูงเกินไปหน่อย ยิ่งตอนผมทดสอบกับเว็บลูกค้าที่เป็น WPML+WooCommerce คือแทบร้องขอชีวิต

ซิงก์ข้อมูลไปยัง Cloudflare

Cloudflare มีบริการ D1 ที่เป็นฐานข้อมูล SQLite ให้ใช้ได้ฟรีอยู่ เลยเกิดไอเดียว่าซิงก์ข้อมูลไปเก็บไว้บน D1 สิ แล้วก็คิวรี่ออกมาตอนบิวด์เว็บไซต์ เลยได้ไอเดียทำ Worker ตัวนึงขึ้นมา

  • https://github.com/IronGhost63/wp63-blog-sync

ตัว Cloudflare Workers มันมี trigger อยู่ 3 แบบ คือ

  1. http อันนี้เป็นเข้าผ่าน http ปกติ
  2. schedule คือทำงานตามเวลาที่ตั้งไว้
  3. queue เอาไว้ให้ระบบคิวเรียกใช้งาน

ตัว Worker ที่เขียน ก็จะใช้ schedule ในการเข้าไปเช็คเว็บไซต์วันละครั้ง มันจะดึง post id ทั้งหมดออกมา แล้วสร้างเป็น task โยนเข้าไปในระบบคิว ซึ่งระบบคิว (ที่ตั้งดีเลย์เอาไว้ 2 นาทีต่องาน) จะเปิดกลับเข้าไปที่เว็บไซต์เพื่อดึงข้อมูลมาเก็บเอาไว้ใน D1 อีกทีนึง

ดึงข้อมูลสำหรับการบิวด์ Static Site

แล้วก็มาพบความจริงอันโหดร้ายว่า Cloudflare Pages จะไม่สามารถ bind กับ D1 ในขั้นตอนการบิวด์เว็บไซต์ได้ ทำให้แผนที่จะต่อเข้า D1 แล้วคิวรี่โพสต์มาบิวด์โดยตรงต้องหงอยลงไป

ด้วยความดื้ออยากได้ Static Site มากกว่าที่จะเป็น Dynamic SSR เต็มตัว เลยย้อนกลับไปที่ Worker ตัวเดิม แล้วเขียน http trigger เพิ่ม ทำเป็น API สำหรับโชว์โพสต์ทั้งหมด ให้ระบบบิวด์สามารถดึงไปใช้ได้ในก้อนเดียว

คือด้วยความที่ว่าโพสต์ที่ซิงก์มา มันถูกจัดรูปแบบเอาไว้แล้ว เป็นตารางง่ายๆ ตารางเดียว เก็บข้อมูลที่ต้องแสดงทั้งหมดเอาไว้แล้ว การคิวรี่มันเป็นแค่ SELECT ธรรมดาไม่มีอะไรซับซ้อน ไม่มี JOIN ใดๆ ทั้งสิ้น ดังนั้นต่อให้มีเป็นร้อยเป็นพันโพสต์มันก็ไม่เสียเวลาและทรัพยากรในการคิวรี่ออกมามากนัก

พอทุกอย่างพร้อมใช้งาน ก็เขียน content collection ให้ไปดึงข้อมูลจาก Worker ออกมาเพื่อใช้ในการ build เป็นอันจบ

  • https://github.com/IronGhost63/astro-blog

ข้อดีอีกอย่างนึงคือมันสามารถใช้ข้อมูลก้อนนี้เป็น index ป้อนให้กับ Fuse.js สำหรับทำ Fuzzy Search ได้ทันทีเลยด้วย

ข้อดีข้อเสียหลังจากย้ายมาเป็น Static Site

ข้อดีอย่างแรกเลยคือมันเร็วขึ้นเยอะ เราสามารถควบคุมทุกส่วนในเว็บได้อย่างอิสระ เราโยนให้ WordPress มีหน้าที่แค่จัดการเนื้อหาจริงๆ ส่วนการปรับ SEO ใดๆ สามารถทำที่ตัวเว็บได้ทันทีโดยไม่ต้องกลัวว่าปลั๊กอินจะตีกัน ไม่ต้องวุ่นวายกับการทำแคช เราสามารถเพิ่มฟีเจอร์และลูกเล่นต่างๆ เข้าไปได้โดยไม่ต้องกังวลว่าจะกระทบอะไรมากนัก และทำให้เซิร์ฟเวอร์ใช้ทรัพยากรลดลงด้วย

ลองนึกภาพว่าเราเปิด Cloudways ตัวถูกสักตัวนึง ใส่เว็บลูกค้าไว้เป็นสิบยี่สิบเว็บ ตัวเซิร์ฟเวอร์จะทำงานเฉพาะตอนลูกค้าเข้ามาอัปเดตข้อมูล แต่ตอนคนเข้าชมนั้นไม่กวนแรงเซิร์ฟเวอร์เลยแม้แต่นิดเดียว เพราะเว็บทั้งหมดถูกเจนออกมาเป็น HTML เก็บไว้บน Cloudflare หมดแล้ว

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