ที่จริงแล้วผมอยากจะเขียนบทความนี้มาตั้งนานแล้ว แต่ด้วยความขี้เกียจ จึงไม่ได้ลงมือเขียนซักที แต่ก่อนที่ผมจะลืมรายละเอียดในการสร้างเว็บ blog.dsjin.co (ซึ่งเอาจริงก็เริ่มลืมๆ ไปบ้าง) ผมจึงตัดสินใจเขียนบทความนี้เพื่อเป็นการบันทึกเหตุผล กระบวนการสร้าง เพื่อในอนาคตผมอาจจะกลับมาอ่านและเตือนความทรงจำว่าผมสร้างเว็บนี้ยังไง 😂
(Update 2025) ผมกำลังโอนย้ายข้อมูลจาก Blog เก่ามา ไว้เดี้ยวผมมาโพสอีกทีนะครับ :)
Photo by Aaron Burden / Unsplash
จุดเริ่มต้น
ถ้าว่าตามความเป็นจริงเราก็มี Blog providers หลายๆตัวที่ให้บริการอยู่ ซึ่งจริงๆผมก็มี medium ที่สามารถเขียน Blog ไว้ได้อยู่แล้ว แต่ทำไมผมจึงตัดสินใจสร้างเว็บนี้ขึ้นมา ผมจะลองไล่ออกมาเป็นข้อๆ
- Medium ถ้าไม่ใช่เป็น Publications จะไม่สามารถทำ Custom Domain ได้
- หน้าตาของ Blog ค่อนข้าง Customize ได้จำกัด (อันนี้เข้าใจได้เพราะเป็น Blog สำเร็จรูป)
- อยากสร้างเว็บเป็นของตัวเอง
แต่เหตุผลจริงๆ คือว่าง แค่นั้นเลย 😂
แต่ก็ยังมีเรื่องที่คิดหนักอยู่คือเรื่อง SEO เพราะด้วยความที่ domain medium ถูกปรับแต่งมาให้บริการโดยเฉพาะ ดังนั้นจึงติดหน้าค้นหาได้ดีมากๆ นั้นเอง (แต่ก็ไม่มีอะไรมากั้นความอยากได้หรอก 😉)
การตัดสินใจเลือก Tech Stack และการออกแบบระบบ
Photo by Joshua Aragon / Unsplash
จริงๆ ผมตั้งธงไว้ในใจแล้วว่าอยากจะใช้ Ghost เป็น CMS ในการทำเว็บนี้ ด้วยความที่มันเหมาะสำหรับการ Blog มาก เพราะเขาเคลมว่าเป็น CMS ที่ Focus การเขียน Blog เป็นสำคัญ ฉะนั้นหลังบ้านไม่ว่าจะตัวเมนู หรือ editor ก็ดู lean เพื่อให้เราใช้งานได้ง่าย และอีกเหตุผลคือ Ghost เป็นหนึ่งในตัวเลือกในการทำ JAM Stack เป็นอันดับต้นๆ ฉะนั้นสามารถ หา document อ้างอิงต่างๆ ได้ง่ายอีกด้วย ดังนั้นผมจังเลือก Gridsome (ผมเขียน Vue.js ละนะ) + Ghost (CMS Headless) เป็น Base tech stack เอาไว้
โดยมี Requirement ที่ผมต้องการคร่าวๆดังนี้
- General
- เมื่อ Ghost มีการอัพเดต (มีโพสใหม่, ลบโพส) ให้ทำการ Build ตัวเว็บใหม่
- เมื่อมีการ commit บน main ให้ทำการ build ตัวเว็บใหม่
- รูปภาพของบทความทั้งหมดให้ upload ไปยัง CDN เพื่อ Serve รูปที่เหมาะสมของแต่ละ Request
- All resources (Web server etc.) should be FREE!!
- Page (บทความ)
- รองรับ Reponsive ในระดับหนึ่ง
- ทำ Lazyload ของรูปภาพ
- มีช่อง Comment
จากการสรุปจาก Requirement และ ความรู้อันน้อยนิดของผม ทำให้ผมตัดสินใจใช้ Tech Stack and tools อื่นๆดังนี้
- Hosting : Firebase (Website), Heroku (Ghost)
- CDN : Cloudinary (Image Storing and serving)
- CI/CD : Circle CI
- Comment : disqus
อะไรประมาณนี้แหละครับ
ลงมือทำ
จริงๆ ผมได้เริ่มต้นวางแผนที่จะทำเว็บนี้มาตั้งแต่กลางปีที่แล้ว แต่ประกอบกับทุกอย่างค่อนข้างใหม่สำหรับผมทั้งหมด ( JAMStack, Image Serving, CI/CD etc. ) บวกกับความขี้เกียจส่วนตัว กว่าจะเริ่มเป็นรูปเป็นร่างจริงๆ ก็มาปลายปี 2020 แล้ว และก็ใช้เวลาปั่น 2-3 วัน และก็ได้ออก version 1 ออกมาเป็นที่เรียบร้อย
สำหรับตัว Ghost เนื่องจากต้องหา Host เอาไว้ Deploy โดยโจทย์ที่ผมตั้งเอาไว้คือฟรี ดังนั้นผมจึงเลือกใช้ heroku โดย Button ของ ghost-on-heroku โดยการคลิก 1 ที สิ่งที่ผมต้องการคือ Ghost และ Cloudinary ก็ Setup มาให้ผมพร้อมเลยสะดวกจริงๆ (มีที่ผมต้องเข้าไปตั้งค่าเองนิดหน่อย แต่โดยรวมคือใช้ได้เลย)
ปัญหาที่เจอตอนกำลังพัฒนา
- Gridsome กับ Ghost - ตามที่บอกไว้ตอนต้นว่า Ghost เหมาะกับการเป็น CMS Headless มาก แต่ปัญหาก็คือ plugin ที่เอาไว้ plug ระหว่าง Grisome กับ Ghost มันอยู่ในระหว่างการพัฒนา (ซึ่งผมก็ใช้ตัวที่มันพัฒนานั้นแหละ) ดังนั้นตัว document ที่ออกมาจึงไม่ละเอียดเลย บาง type ของ GraphQL ก็ออกมาไม่สมบูรณ์ แต่ด้วยมัน based on gatsby’s plugin ดังนั้นผมจึงอ่านตัว document ของ Gatsby ทดแทนพร้อมกับดูโค้ดข้างในงมไปด้วย จนสามารถใช้งานตามที่ผมต้องการในโปรเจคได้ ดังนั้นผมแนะนำใครอยากใช้ Gridsome กับ Ghost รอให้ stable ก่อนจะดีกว่า
- Circle CI กับ Ghost - เนื่องจากผมต้องการให้มีการ Rebuild และ Deploy เมื่อมีการเปลี่ยนแปลงใน Ghost ดังนั้นผมต้องทำ Custom integrations เพื่อ Invoke Pipeline Webhook ของ Circle CI แต่ปัญหาก็คือผมไม่สามารถส่ง Payload อะไรไปได้เลย (รวมไปถึง authorization header) ดังนั้นผมจึงใช้ Default ได้อย่างเดียว (ไม่ Flexible เอาซะเลย)
นอกนั้นผมก็ลืมๆไปแล้ว ไว้ถ้านึกออกจากมาใส่เพิ่มนะครับ 😅
สุดท้ายนี้ ก็ขอฝาก Blog ของผมเอาไว้ด้วย โดยผมตั้งใจไว้ว่าจะอัพบ่อยๆ แต่คงไม่ Technical จ๋าขนาดนั้น เพราะผมไม่อยากแนะนำอะไรผิดๆไป 😂 มีอะไรติชมสามารถ comment ไว้ด้านล่างได้เลยนะครับ ขอบคุณที่อ่านจนจบนะครับ ไว้เจอกันใหม่ สวัสดี 🤟