บันทึกการทำบล็อกด้วย Gatsby บนเว็บ Devahoy
หลังจากบทความก่อนหน้านี้ 3 เดือนที่แล้ว ผมเขียนบอกไว้ว่า Migrate จาก Middleman มา Gatsby แล้ว ซึ่งต่อจากนั้น ก็ไม่ได้มีเวลาอัพเดทเลย แถมปล่อยให้ link ที่เราเปลี่ยน permalink เน่าตาย ลืมเปลี่ยนในบทความด้วย สุดท้าย google index หายเลย เพิ่งจะเริ่มมีเวลากลับมาแก้ มาเปลี่ยน ก็ช่วง 2-3 สัปดาห์ที่ผ่านมา ก็เลยได้ redesign ต่อหลังจาก migrate แล้วก็ปรับโค๊ด ปรับ Performance
บทความนี้จะเน้นไปที่ภาพรวมนะครับ ส่วนเชิงลึกเช่น Gatsby, GraphQL หรืออะไรพวกนี้ เดี๋ยวค่อยเขียนบทความอีกทีละกัน
วันนี้ก็เลยถือโอกาส เอาบันทึกการทำบล็อก Gatsby มาเขียนเป็นบทความซะเลย หวังว่าจะเป็น Use case หรือเป็นตัวอย่าง เป็นแนวทางให้ใครหลายๆคนนะครับ หน้า Showcase เว็บที่ใช้ Gatsby ครับ
Language และ Tools ที่ผมใช้ในเว็บบล็อกก็คือ
- Gatsby : แน่นอนแหละ เป็น core ทำให้เกิดบล็อกแห่งนี้ได้ หลักๆคือเอาไว้ development แล้วจากนั้นก็ build เป็น static file.
- React : แน่นอน Gatsby นั้นมันก็คือ React นั่นเอง
- GraphQL : การใช้ Gatsby นั้นก็จำเป็นต้องรู้ GraphQL แต่ไม่ต้องกังวล ไม่เคยเขียน GraphQL มาก่อน ก็สามารถเขียน Gatsby ได้ ดูตัวอย่าง หรือลอง debug ลอง query ผ่าน explorer ก็จะเข้าใจครับ
- Github Pages : ผมโอสไว้ที่ Github Pages ครับ (จริงๆ ส่วนใหญ่จะใช้ Netlify เป็น Hosting ซึ่งก็สะดวกดีครับ)
- Cloudflare : เป็น CDN เอาไว้ช่วย caching เอาไว้กันเว็บโดนยิง เว็บล่มอะไรพวกนี้
- Semaphore CI : เป็น CI/CD ที่ผมเลือกใช้ครับ เนื่องจากว่าผมติดใจเรื่องความไวในการรัน การเทส ไวกว่าทุกเจ้า ก็เลยใช้มาเรื่อยๆ แล้วก็ตอนนี้มีฟรี $20 ทุกเดือน ก็เลยใช้ 😂
ซึ่งจะเห็นว่าผมใช้ Github Pages + Cloudflare โดยปกติจะเห็นหลายๆคนเลือกใช้ Gatsby + Netlify ด้วยความง่าย จริงๆเว็บลูกค้า หรือเว็บทำเล่นๆผมก็ใช้ Netlify ครับ โดยที่ Netlify มี DNS, HTTPS และเป็น CDN ได้ในตัว เรียกได้ว่าใช้ Netlify ก็ไม่จำเป็นต้องใช้ Cloudflare ก็ได้ แต่ผมลอง Netlify กับบล็อกนี้แล้วไม่ไหวครับ ตอน build แล้ว timeout เนื่องจาก image กับ query เยอะไปหน่อย
Getting stared with Gatsby
เริ่มแรกก็ไม่รอช้า ผมใช้ Gatsby Starter ที่มีให้แล้ว และก็เว็บผมเป็นบล็อก ผมก็เลยเลือกใช้ gatsby starter blog ครับ ติดตั้ง Gatsby CLI แบบ global
ทีนี้ก็สร้างโปรเจ็คจาก gatsby starter blog template
ทีนี้ข้อดีของ Starter blog คืออะไร?
- มีโครงสร้าง project มาให้เรียบร้อยแล้ว สามารถทำเว็บต่อยอดได้เลย จะเห็นว่า เว็บของ Dan ก็ fork มาเหมือนกัน
- ไฟล์
src/seo.js
ทำโครงไว้ให้แล้ว โดยใช้react-helmet
ข้อดีคือเราสามารถ custom meta tag ของเว็บได้ ช่วยเพิ่ม SEO รวมถึง Open graph facebook, twitter ได้ - มี Plugin ลงไว้ให้ครบ เช่น plugin ที่เอาไว้ tranform ไฟล์ markdown ที่สามารถ query ผ่าน GraphQL ได้เลย
- มีตัวอย่างการ Query หน้า
pages
และใช้StaticQuery
ใครไม่คุ้นชิน GraphQL ก็ดูตัวอย่างประกอบ หรือเรียนรู้ไม่ยากมากครับ - ตัว starter จริงๆมี
typography
เป็น library ที่ดีมาก ปรับ spacing, theming typo ของเว็บเราได้ แต่ว่าพอดีผมใช้ css โครงเก่า ก็เลยเอาออกไป
ต่อมา ก็ได้เวลา Develop
- ผมแยกไฟล์ stylesheet และ compile css ด้วย
gatsby-plugin-scss
โดยใช้ skeleton base แบบเดิม - หน้า static page ทั่วๆไป จะเป็น
.js
ธรรมดา อยู่ที่src/pages/**
- ส่วน blog บทความ จะถูกแยกไว้ที่โฟลเดอร์
content
ตรงนี้ตั้งค่าได้ที่ไฟล์gatsby-config.js
โดยใช้ plugingatsby-source-filesystem
- และ blog เขียนด้วย Markdown ทั้งหมด โดยใช้ plugin
gatsby-transformer-remark
รวมถึงรูปภาพใน markdown จะถูก optimize ให้แล้ว ด้วย plugingatsby-remark-images
ทีนี้เรื่องรูปจะมีความยุ่งยากนิดนึง (ถ้าใน Markdown ไม่มีปัญหา เพราะมี plugin ช่วย) แต่ถ้าเป็น component หรือ page การโหลด Image อาจจะยุ่งยากนิดนึง คือ
- ต้อง Query รูปก่อน เช่น
- ใช้
gatsby-image
ในการแสดงรูป เพราะว่าทำเผื่อ optimize มัน generatesrcset
ให้อัตโนมัติ เป็นอีกหนึ่งข้อที่ชื่นชอบใน Gatsby ecosystem
- ปกติ หน้า page ในโฟลเดอร์
src/pages/**
จะ built-in query ไว้ให้แล้ว คือจะ match กับ GraphQL query ใน component ที่เราสร้างไว้ แล้วก็สามารถเรียกใช้งานผ่านprops.data
ได้เลย คล้ายๆกับ Reduxconnect()(App)
ที่สามารถเรียกใช้dispatch()
ได้นั่นเอง - แต่ในขณะเดียวกัน ถ้าไม่ใช่ pages เป็น component อื่นๆ เราจำเป็นต้องใช้
StaticQuery
มาครอบอีกที
- ไม่ลืมที่จะใส่ Disqus comment ในเว็บ ทีแรกจะใช้ facebook comment plugin แต่ว่ามันโหลดนานมาก เลยเอาทิ้งไป ถ้าเทียบกันแล้ว Disqus ก็ช้า แต่ยังเร็วกว่า Facebook มาก ข้อดีคือ ใช้
disqus-react
ที่มีใน npm อยู่แล้วก็ใช้ได้เลย - ไหนๆก็เขียนบล็อก เราก็อยากมี tags มี category ได้บ้าง ก็ได้
gatsby-plugin-categories
และgatsby-plugin-tags
ช่วยชีวิตไว้ ก็แค่ระบุ template ในgatsby-config.js
ว่าจะให้ใช้ template ไหน ทีเหลือ plugin จัดการให้ สะดวกเลย
ตั้งค่า Semaphore CI
ผมใช้ Semaphore CI ในการให้มันรัน test, build และ deploy โปรเจ็คของผม เริ่มแรกผมก็ต้องสร้างไฟล์ .semaphore/semaphore.yml
ขึ้นมา ข้างในก็มี script บอกไว้ว่า ตอน test จะรันอะไร test เสร็จ สั่งลอง build ถ้า build ผ่าน ก็จะให้ deploy โดยไปเรียกอีกไฟล์ .semaphore/deploy.yml
ที่ตั้งค่าไว้ให้มัน deploy ไป github pages โดยใช้ library gh-pages
ซึ่ง Semaphore CI ไม่สามารถ commit ไป git repo แบบ private ได้ ถ้าไม่มี token ฉะนั้นผมจึงเพิ่ม private variable ใน Semaphore ผ่าน sem
(Semaphore CLI) และก็ไปกำหนด Notification เพื่อ webhook ไปบอกใน Slack ว่า status เป็นไง เริ่ม build, deploy เสร็จ เป็นต้น
Workflow การเขียนบล็อก
ต่อมาผมพูดถึง Workflow ในการเขียนบล็อกดีกว่า หลังจากช่วง develop เสร็จสิ้นไปแล้ว ทีนี้เราจะอัพเดท เพิ่มบทความ แก้ไขหน้าเว็บยังไง ใช้ Hosting อะไร? Deploy ยังไง? โอเค มาเริ่มทีละ step กันเลย
ผมวางโครงสร้างไว้ดังนี้
1. Checkout new branch from master
ทุกครั้งที่จะ implement หรือเพิ่มบทความ ผมจะ checkout branch ใหม่จาก master
2. commit, push and open PR
เมื่อเขียนบทความ หรือแก้ไขอะไรเสร็จก็แล้วแต่่ ก็ commit code, push ไป origin (github) จากนั้นก็เปิด Pull Request
3. Review and approve
ไป review ใน Github อีกรอบ เผื่อบางทีอาจจะตาลาย หลงๆลืมๆไป (จริงๆเวลาทำงานเป็นทีม ก็จะมีเพื่อนในทีมช่วยกัน review แต่นี้ก็ต้องมา review เอง approve เองเลย 😂)
ถึงแม้ repo นี้ผมจะทำคนเดียว ผมก็ยังต้องไป protect branch ไม่ให้ push ตรงๆมาที่ master ได้ ผ่าน Pull request เท่านั้นถึง merge ได้
4. merge to master
หลังจาก CI ผ่านแล้ว ก็กด rebase and merge เพื่ออัพเดทโค๊ดจาก feature/xx
ไปที่ master
ทีนี้พอโค๊ดไปที master
แล้ว ตัว Semaphore CI ก็จะไป trigger ตามที่เราเขียน script ไว้ เมื่อไม่มีอะไรผิดพลาด มันก็จะไป deploy ที่ branch gh-pages
ที่ผมตั้งไว้ เป็น branch ของ Github Pages ใช้เวลาในการ build deploy ประมาณ 3-4 นาที
เป็นอันเรียบร้อย สำหรับ Workflow ในการเขียนบล็อกของผม
ปัญหาที่เจอ
หลังจาก Deploy เว็บไปด้วย Gatsby ก็เริ่มมีปัญหาที่เจออยู่บ้าง ก็พยายามเขียนเล่าไปละกัน บางเรื่องก็ลืมๆครับ ไม่ได้เจอพร้อมกัน เจอแล้วก็แก้
เจอปัญหาเว็บ cache
ปกติเรามักจะมีปัญหาเว็บโหลดช้าเพราะไม่ยอม caching แต่ตัว Gatsby ตั้งค่า plugin มี gatsby-plugin-offline
มาช่วยเป็น Service Worker มี PWA มาในตัว ด้วย gatsby-plugin-manifest
ทำให้แทบไม่ต้องทำอะไรมาก
แต่ปัญหาคือ ผมดันไปตั้งค่า Cloudflare ในส่วน Page Rules ให้มัน cache everything ทำให้มันไป cache ไฟล์ sw.js
ด้วย ซึ่งไฟล์นี้ไม่ควรจะ cached ครับ ฉะนั้น ก็เลยต้องไปกำหนดให้
/sw.js
นั้น Cache level เป็น By Pass ซะ คือไม่ cache
ทีนี้บล็อกของผม ก็สามารถเห็นบทความใหม่แล้ว ทีแรกไปเผลอ cache ไว้ มันก็จะมองว่าเป็น sw.js
ตัวเก่า ก็จะโหลด content เดิมที่ cache ไว้ ไม่ยอมอัพเดท
Google Index
ปัญหาต่อมาคือ ช่วง 3เดือนก่อน ที่รีบย้ายเว็บ และเปลี่ยน Permalink แล้วดันลืมนึกถึงผลกระทบ คือ link พวกนั้นมัน index google อยู่ ฉะนั้นเวลาที่คนค้นหา แล้ว reach เข้าผ่าน google จะเป็น url เก่าๆ ซึ่งพอเข้าเว็บมา มันจะไม่เจอ เพราะเราเปลี่ยน URL แล้ว ทำให้ได้หน้า 404
กลับไปทุกครั้ง
พอหลายๆวันเข้า เว็บผมก็เริ่มร่วง index เริ่มหายไป
หน้า Report จาก Google Search Console (Google Webmaster เก่า)
สิ่งที่นึกออกคือ ผมลืมทำไฟล์ sitemap.xml
เนื่องจากว่าที่เคย submit ไว้ พอเปลี่ยนเว็บ ลืมทำใหม่ โชคดี gatsby มี plugin ผมใช้ gatsby-plugin-sitemap
และ gatsby-plugin-advanced-sitemap
ในการทำ sitemap เพื่อไป submit google index ใน Webmaster tool อีกที
จากนั้นเว็บผมก็กลับมา มีคน reach ผ่าน search อีกครั้ง ใช้เวลา 1สัปดาห์มั้ง ถึงจะเริ่ม index url ใหม่ๆ ไปแทนที่ url เดิม (แต่ index เก่าๆ ก็ยังเป็น URL ที่เข้ามาจะเจอ 404 อยู่ดี ตรงนี้ก็คงต้องขึ้นอยู่กับระยะเวลาแล้ว ไม่สามารถทำอะไรได้)
Audit ด้วย Lighthouse
แน่นอน Gatsby ขึ้นชื่อเรื่อง Performance อยู่แล้ว ไม่ว่าจะเป็น PWA, Caching, Service Worker หรือเรื่อง Image Optimization ซึ่งปกติเว็บส่วนใหญ่จะไม่ได้ทำรองรับ แต่ว่า Gatsby มี Plugin ทำให้หมด เรียกได้ว่า ตอนเทส ครั้งแรก 80+ ทุกตัวแต่มีเรื่อง a11y (Accessibility) นั่นแหละที่ตำกว่าเพื่อน
a11y
เลยไปหาอ่านบทความเรื่อง a11y ประกอบ พบว่า เว็บเราห่างเรื่องนี้เยอะเลย สุดท้าย ก็เลยใช้ ESLint ช่วย ให้มัน error มาให้หน่อย ว่าต้องแก้ยังไงบ้าง ด้วย eslint-plugin-jsx-a11y
เรียกได้ว่า ช่วยชีวิตไปได้เยอะ ซึ่งส่วนที่จะเจอกันเยอะเป็นพิเศษคือ <img src="" />
ไม่ใส่ alt
รวมถึง id ไม่ unique เป็นต้น
Performance
ส่วน Performance มีแนะนำให้ใช้ prefetch
, preconnect
สำหรับ google font ซึ่งทีแรกเราใช้วิธีการเรียก google font ผ่าน <link rel="">
จากนั้นเลยเปลี่ยนไปใช้ plugin gatsby-plugin-prefetch-google-fonts
และก็อีกเรื่องคือ Google Analytics ใน Audit แนะนำให้ใช้ preconnect
แต่เนื่องจากไปดูใน Gatsby แล้วรู้สึกว่าใส่มาแล้วนะ ก็เลยลองใส่เองที่ไฟล์ gatsby-ssr.js
ส่วนนี้งงว่ามันไม่เหมือนกับในตัว core ของ Gatsby ตรงไหน (จนถึงตอนนี้ก็ยังงงๆ เอาเป็นว่า ลองใช้ไปก่อน)
Best Practice
ข้อนี้เห็นส่วนใหญ่จะเป็นเรื่อง Links must have discernible text
คือไม่ได้ใส่พวก aria-label
ให้กับพวก a href
SEO
อันนี้ข้ามไป เพราะมี react-helmet
และ set ค่าไว้แล้ว ทำให้ตรง meta ไม่ต้องกังวล แต่มีบางเรื่องเช่น font เล็ก ขนาด button ไม่พอกดเวลาจอมือถือเป็นต้น
PWA
ข้อนี้ Gatsby ทำมาให้แล้ว ไม่ต้องแก้อะไรเลย 90+ ตั้งแต่แรก
สุดท้าย เทส Audit performance ด้วย Lighthouse ก็ได้ผลลัพธ์ตามรูป (แต่ละครั้งอาจจะได้ผลลัพธ์ไม่เหมือนกัน แต่ตัวเลขไม่ห่างกันมาก)
Conclusion
สรุปบทความนี้ก็เป็นการบันทึกการทำบล็อกด้วย Gatsby อาจจะไม่ได้ลงลึกรายละเอียดเท่าไหร่นัก ให้เห็นภาพรวม มุมมองต่างๆ และก็หวังว่าบทความนี้จะเป็นประโยชน์สำหรับใครที่กำลังมองว่าจะใช้ Gatsby ดีหรือเปล่าหนอ บอกได้เลยว่าไม่ผิดหวังครับ
ตอนนี้เรียกได้ว่าผมเป็น fanboy Gatsby ไปแล้วครับ แม้ว่าจะเพิ่งลองใช้ไม่นานก็เถอะ (เสียดายมากได้ยินมานานแล้ว แต่ทำไมไม่รีบใช้ไม่รู้)
และนอกเหนือจาก Workflow หรือ Stack ในบทความผม จริงๆ แล้ว Gatsby + Netlify หรือ Gatsby + Firebase ก็เป็นอีกหนึ่งตัวเลือกที่ไม่เลวทีเดียวนะครับ สุดท้ายก็ไม่มี Process หรือ Tool หรือ Stack อะไรที่มันดีที่สุด อยู่ที่ว่าถนัด ชื่นชอบ หรือตอบโจทย์ เข้ากับโปรเจ็คของเรามั้ย ก็เท่านั้นครับ
Happy Coding
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust