เมื่อเราอยากจะ Optimize เว็บให้เร็วขึ้น เราต้องทำอะไรบ้าง (และทำอะไรไปแล้วบ้าง)

Tananan Tangthanachaikul
TakeMeTour Engineering
8 min readJun 11, 2018

สืบมาจากบล็อกของทีม Design ที่ TakeMeTour ที่ได้เล่าเรื่องของการ Rebranding TakeMeTour โฉมใหม่เฟี้ยวฟ้าวและเรียบง่ายกว่าเดิมตามยุคสมัย หลังจากของเดิมโดนทักว่าเป็นเพนกวิ้นบ้าง เป็นเป็ดบ้าง

ใครที่เป็นดีไซน์เนอร์ ผมบอกเลยว่าบล็อกที่เล่าเรื่องการ rebranding เป็นอะไรที่น่าอ่านจริงๆ ตามอ่านได้ในนี้เลยครับ

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

แต่ฝั่งทีม Dev เองก็เริ่มเห็นแล้วว่า เว็บเริ่มจะอืดขึ้นพอสมควร จึงเลยถือโอกาสนี้ที่ได้ปรับหน้าตาเว็บ ได้ลอง optimize เว็บให้เร็วขึ้น(มาอีกนิ๊ดดดดดดดดนึง) ด้วย

วันนี้เลยจะมาเล่าให้ฟังว่า เราจะทำยังไงให้บ้างเพื่อที่จะ optimize เว็บให้ไวขึ้น มีอะไรที่เราทำไปแล้วแล้วเห็นผลชัดเจน และอะไรที่เราอยากจะทำต่อไปในอนาคต

ทำไมเราควรจะทำให้เว็บโหลดไวขึ้น

ตัดมาจากสไลด์ https://speakerdeck.com/addyosmani/web-performance-made-easy?slide=5

Addy Osmani Engineer ของ Google ได้บอกไว้ในสไลด์ด้านบนว่า ถ้า user ไม่ได้เห็นหน้าเว็บในเร็ววัน จะรู้สึกร้อนรน และจะรู้สึกว่าโหลดไม่ขึ้น ส่งผลให้ user อาจลาจากเราไปก่อนได้ นั่นทำให้ก็จะมีผลในเชิง UX ด้วย หากเว็บไซต์โหลดช้า

ผมเองก็เคยอ่านเจอมาสักที่เหมือนกัน เขาบอกว่าถ้าในเวลา 4–5 วินาทีเขาไม่เห็นหน้าเว็บไซต์เลย มีความเป็นไปได้ที่เขาจะกดออกไปเลยทันที! (ขออภัยที่จำ reference ไม่ได้)

ทำเว็บให้โหลดไวขึ้น ก็เหมือนกับการวาดรูปม้า!

ตัดมาจากสไลด์ https://speakerdeck.com/addyosmani/web-performance-made-easy?slide=10

และนั่นแหละครับ Addy ก็บอกว่า การทำให้เว็บโหลดไวขึ้น มันก็ง่ายๆ เหมือนกับการวาดรูปม้านั่นแหละ

ชิบ ตูวาดไม่เป็น

ผมเองก็วาดไม่เป็นเหมือนกันแหละครับ…แต่สิ่งที่ Addy และสไลด์นี้จะสื่อให้กับเรานั้นเข้าใจง่ายมากครับ นั่นคือ “วาดให้เห็นไปก่อนว่าเป็นอะไร และทยอยๆ วาดจนสวยงาม”

และหากท่านเคยได้ยินคำว่า First-paint มาก่อน นี่แหละครับ คือความหมายของ First-paint!

Google จึงได้ออก metric ใหม่ที่ไว้วัด performance ของเว็บ โดยอิงจาก “ประสบการณ์การใช้งานของ user” และเรียกมันว่า User-centric performance metrics metric ที่ว่ามี 4 ตัว

  • First Paint (FP): เริ่มเห็นว่ามีอะไรสักอย่างขึ้นมาละ
  • First Contentful Paint (FCP): เริ่มเห็นโครงสร้างบางส่วนของเว็บ พร้อม content ที่เขากำลังจะเจอด้วย อย่างเคสนี้ user จะเห็นแล้วว่า เรากำลัง search Google หาว่า sundar pichai คือใคร แต่ก็ยังไม่เห็นผลลัพธ์
  • First Meaningful Paint (FMP): เริ่มเห็นผลลัพธ์ของหน้าเว็บแล้ว แต่ก็อาจจะยังเห็นรูปไม่ครบ แต่ content ส่วนมากจะสามารถอ่านได้แล้ว
  • Time to Interactive (TTI): เป็นจุดสุดท้ายของการโหลดเว็บ คือเว็บโหลดเสร็จเรียบร้อย และสามารถใช้งานทุกอย่างได้แล้ว (เว้นแต่จะเจอบั๊ค ก็อีกเรื่องนึง)

ซึ่งเลข 4 ตัวนี้จะเป็นมาตรวัดความเร็วที่ใน Lighthouse ที่ตัววัดประสิทธิภาพเว็บของ Chrome จะบอกกับเรา ยิ่งแต่ละเลขยิ่งน้อย ก็จะยิ่งทำให้เว็บโหลดไวขึ้น และ UX ก็จะดีขึ้นด้วย

ถ้าสังเกตจากรูป แล้วเทียบกับการวาดม้า จะเห็นว่ามันก็คล้ายๆ กันเลย ตอนแรกจะวาดอะไรที่ไม่ค่อยเห็นความหมายมันก่อน แต่สักพักก็จะเริ่มรู้แล้วว่าเป็นอะไร และเป็นรูปม้าที่สวยงามในที่สุด

วัดยังไงว่าเร็วไม่เร็ว?

จริงๆ คำว่าเร็วไม่เร็วจะวัดยังไง มันก็มีมาตรวัดหลายๆ ตัวให้วัดเยอะแยะเต็มไปหมดเลยครับ จะใช้ perception ของคนก็ได้ (คือให้ลองใช้แล้วเขาคิดว่าเร็วหรือช้า) หรือถ้าอยากได้เป็นตัวเลข หรือ automation บ่อยๆ ก็อาจจะใช้เครื่องมืออื่นๆ ครับ

เช่น PageSpeed Insights ของ Google เอง ซึ่งจริงๆ แล้วหลังๆ มานี้ PageSpeed ก็มีการอัพเดตเพิ่ม score ส่วนของ Speed ขึ้นมาด้วย จากเดิมที่มีแค่ Optimization

หรือใน Chrome เวอร์ชันใหม่ๆ เองก็มี tool ยอดฮิตอย่าง Lighthouse ไว้ให้ audit เว็บสำหรับ PWA ด้วย ตัวนี้ผมจะใช้อ้างอิงเยอะพอสมควร เพราะจริงๆ การเทสของ Lighthouse ถือว่าโหดมาก เพราะเทสบน mobile first และเทสที่สปีดต่ำๆ อีกอย่างคือมันกดเทสง่ายดี เปิด Dev tools audit ได้ทันที

Lighthouse ใน Chrome เทสได้ตั้งแต่ performance ยัน SEO

และมีอีกตัวที่ผมได้ใช้ด้วยคือ GTMetrix ครับ ตัวนี้ก็จะบอกด้วยว่าเราสามารถ optimization อะไรได้บ้าง เช่น minify JavaScript หรือยัง

ดังนั้นในทุกการพยายามลอง experiment ผมจะพยายามใช้ tools 3 ตัวนี้ + perception ของการลองใช้งานเองกับคนในทีมดูว่าการลอง optimize ในแต่ละประเด็นมันช่วยอะไรได้บ้างไหม

เริ่มจาก Research ว่าจะทำอะไรได้บ้าง

ในตอนแรกๆ เอาตรงๆ พอพูดถึงเรื่อง optimize แล้วเนี่ยมักจะมีอารมณ์แบบ จะไปทางไหนดี แต่ก็โชคดีที่เริ่มไปเจอบล็อกของพี่ตั้ง warat wongmaneekit GDE เว็บ ที่เอาเรื่องของการพยายามลอง optimize เว็บแบบที่ Addy ที่เป็น Engineer ของ Google ได้บอกไว้ เขียนเป็นบล็อกสั้นสองตอน

ก็เลยรู้สึก อืมมมมมมมมมม น่าสนใจดี เลยเริ่มจากบล็อกนี้นี่แหละ

โชคดีที่เราทำ caching + network infra ไว้ดีระดับนึง

TakeMeTour เองมีการทำ static caching อยู่แล้วสำหรับหน้าเว็บ ซึ่งด้วยความที่เราใช้ Next.js เป็น Server-side rendering เราจึงทำการ cache ตัว static HTML ทั้งก้อนนี่แหละไว้ 1 ชม.เมื่อมี cache hit และเราเองก็มี cache server วางไว้อยู่ในหลายมุมของโลกด้วย

ผลก็คือถ้า cache hit หน้าเว็บจะตอบกลับมาไวมากๆ รวมถึงเราใช้ HTTP/2 แล้ว พร้อมทั้งทำ GZip ไว้แล้วด้วยที่ตัว server ทำให้เราโชคดีที่การ optimize ในเชิง network จึงทำไปแล้วโดยปริยาย เย้

ซึ่งพี่ Panjamapong Sermsawatsri ก็เคย talk เรื่องนี้ไว้ในงาน React Bangkok 2.0.0 ที่ผ่านมาครับ ว่าเราวาง infrastructure อย่างไรไปบ้าง

โอเค ในเชิง network, infra อาจจะพร้อมละ แต่อีที่เหลือนี่สิ…

ไปลง Webpack Bundle Analyzer ก่อนเลยจ้า

ก่อนจะทำทุกสิ่งอย่าง สิ่งแรกที่ควรทำคือติดตั้ง webpack-bundle-analyzer ก่อนเลย

ตัวนี้จะช่วยให้เราเห็นภาพ bundle size สุดท้ายที่ build ออกมาได้ชัดเจนขึ้นว่า ไอ้ที่ไฟล์ build เรามันใหญ่ๆ เนี่ยมันมาจากส่วนไหนกันบ้าง ซึ่งเราก็จะดวงตาเห็นธรรมชัดขึ้นมากว่า อ๋อ ไอ้ที่มันใหญ่ๆ เพราะอีนี่มันใหญ่นี่เอง และพอเราทำอะไรเพิ่มไป ก็จะดูได้ว่ามันเล็กลงหรือใหญ่ขึ้น

webpack-bundle-analyzer ช่วยให้เราเห็นชัดๆ จะๆ ตาเลยว่าอะไรใหญ่เว่อร์มากๆ

ซึ่งแน่นอนว่าประการแรกที่เราควรทำ คือพยายามลดขนาดของ bundle size ให้เล็กที่สุดเท่าที่จะเป็นไปได้

Library บางตัวใหญ่มากกกกกกกกกกกก

Library ยอดนิยมในโลก JavaScript เช่น moment.js ที่จัดการเรื่องเวลา / lodash ที่จัดการเรื่อง data นั้นมีขนาดไฟล์ใหญ่มากกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกก แต่ส่วนที่เราเอามาใช้นั้นมันมีจิ๊ดเดียวเอง

เช่น moment.js เองที่มันใหญ่มากเพราะว่ามันมี localization ครบทุกภาษาบนโลก Addy บอกว่า ถ้ายูไม่ได้ใช้มันทุกภาษา ยูก็ strip เอาเฉพาะภาษาที่ใช้สิ

ซึ่งวิธีการก็คือ ตัว webpack เองก็มี plugin ช่วยอยู่คือ ContextReplacementPlugin ที่ช่วยเราได้ ก็ให้ trim เหลือแต่ภาษาที่เราใช้

new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|th/)

อย่างตัวอย่างบนก็คือ เหลือแค่ไทยกับอังกฤษ

ซึ่งก็เห็นผลครับ ขนาดของ moment.js บางลงไปเยอะ

ตัว lodash เองก็เช่นกันครับ มี plugin ช่วยสองตัวด้านล่างนี้เลย

หรือถ้าใครไม่ได้ใช้ moment.js แบบพิสดารพันลึกเยอะแยะขนาดนั้น ตอนนี้มีอีกทางเลือกคือใช้ dayjs แทน ซึ่งตัว API ที่ใช้เหมือน moment เปี๊ยบ แต่ bundle size ของ dayjs นั้นเบาหวิวมาก แค่ 2KB เท่านั้น! (ซึ่งผมเองยังไม่กล้าเปลี่ยน เพราะกลัวกระทบหลายจุดเนื่องจากระบบเราใช้ moment.js ซะเยอะไปแล้ว แต่ก็อยากเปลี่ยนเหมือนกัน)

รูปใหญ่มากกกกกกกกกกกก

ถ้านอกเหนือจากว่าเราควรลดขนาดของ js แล้ว resource อื่นๆ เช่น รูป ก็ควรลดขนาดเช่นกัน

Addy เองก็มีเขียนบล็อกเรื่องรูป (แค่เรื่องรูปจริงๆ) ยาวเป็นมหากาพย์ยังกะนิยายเลยจ้า

ประเด็นหลักๆ ที่น่าสนใจของบล็อกด้านบนคือ Compress รูปให้เหมาะสมกับการใช้งาน ดู nature ของรูปกับ file type ที่ใช้ เพราะรูปบางประเภทถ้าใช้ jpg จะดีกว่า png และบางประเภทใช้ png จะดีกว่า jpg

ถ้าเอาแบบคนขี้เกียจ 2018 ผมขอแนะนำแอพที่ชื่อว่า ImageOptim เลยขรั่บสำหรับชาว Mac

มันทำงานง่ายมาก คือแค่โยนไฟล์รูปไปให้มัน มันจะ compress ให้ แล้วบอกด้วยว่าเรา compress ไปได้กี่ % ซึ่งผลที่ได้ประทับใจครับ คือลดขนาดไฟล์รวมๆ ไปได้ประมาณ 37% หายไปฮวบเลย ในขณะที่ตัวคุณภาพของรูปยังคงเท่าเดิม (คือแยกไม่ออกจริงๆ ว่าต่าง แต่เบาหวิวไปเลย)

แต่ชาว Windows หรือ Linux ก็มี alternative ให้ใช้อยู่บ้างๆ

รวมถึงถ้าเป็นไปได้ ตอนเอารูปมาใช้งาน ควรปรับ scale ให้พอดีกับขนาดที่จะโชว์จริงๆ เช่น ถ้าเราโชว์พื้นที่แค่ 320x180 ก็ควรจะโหลดรูปที่มี resolution ตามนี้เหลือใกล้เคียง ไม่ควรโหลดตัว scale ใหญ่ๆ แบบ 1920x1080 แล้วมาย่อขนาดเอา มันโหลดนาน แถมยังต้องนั่ง downscale ให้มันอีก

ถ้า GIF ใหญ่ ลองเปลี่ยนเป็น MP4 นะ

ในงาน Google I/O 2018 Addy เองก็แนะนำว่า animation ที่เป็น GIF ถ้าไฟล์ใหญ่ๆ ลองพิจารณาที่จะทำมันเป็นวิดิโอแบบ MP4 แทนจะช่วยลดขนาดได้

Demo ในงาน Google I/O เองก็ลดขนาดมันไปได้บานเลย จาก GIF 7MB เหลือ MP4 แค่ 1MB!

LazyLoad Image: โหลดรูป เมื่อจะเห็น

เว็บที่มีการ serve content ที่พ่วงรูปจำนวนมากๆ นั้นจะเจอปัญหานี้เยอะครับ TakeMeTour เองก็เช่นกัน ปัญหาคือเวลาเราแปะรูปในหน้าเว็บ รูปทุกรูปที่อยู่ใน HTML DOM ของเรามันจะโดนโหลดพรึ่บตูมเดียวหมดเลยทุกรูป ไม่ว่าจะเห็นไม่เห็นก็ตาม

ข้อเสียชัดๆ เลยคือ มันจะกินปริมาณ data มหาศาลในการโหลดหน้าเว็บครับ ทั้งๆ ที่บางทีไอ้รูปที่มันโหลดมาเนี่ย user ยังไม่ทันได้ดูด้วยซ้ำ

Addy เลยแนะนำว่า รูปอะไรที่มัน offscreen (พ้นจุดมองเห็น) ให้ยังไม่โหลด ไปโหลดตอนที่เลื่อนผ่านพอดี เทคนิคนี้เรียกว่า LazyLoad Image ครับ

ของ TakeMeTour เองก็ชัดมากครับ เพราะเดิมทีหน้า home เราเอง content ก็เยอะมากๆ และรูปก็เยอมากๆ เช่นกัน ทำให้หน้าแรกรวมๆ แล้วโหลดหนักมากประมาณ 4MB เลยทีเดียว!

แต่พอลองทำ LazyLoad แล้ว เราลดขนาดไปได้ครึ่งนึงเลยทีเดียว เหลือที่ 2MB โดยประมาณ

จริงๆ แนวคิด LazyLoad นี้ไม่ได้ apply แค่รูปอย่างเดียวนะ จริงๆ จะ apply ถึงระดับ component ที่แสดงได้เลย เช่น Airbnb เองก็มีการทำ infinite scroll ซึ่งก็นับเป็นการทำ LazyLoad แบบนึง

ซึ่งวิธีการทำนั้น ก็มีหลายแบบครับ มีตั้งแต่เพิ่งพา library ไปจนถึงเขียนเอง อย่างของผมก็ไปจบที่เขียนเอง เพราะ library ไม่ตอบโจทย์

อย่าสักแต่จะโหลดด้วย <script> อย่างเดียว

ถ้าทุกวันนี้ใครยังโหลด script ด้วยท่านี้

<script src="main.js"></script>
<script src="vendor.js"></script>
<script src="thirdparty-1.js"></script>
<script src="thirdparty-2.js"></script>
<script src="thirdparty-3.js"></script>

ซึ่งไม่ผิดอะไร แต่ว่ามันจะช้ามาก เพราะจริงๆ แล้วกลไกการทำงานของ JavaScript จะเป็น render blocking คือมันจะเสียเวลาทั้งโหลด script และ execute script และในเวลาเหล่านั้น งานการ render หน้าเว็บจะถูกหยุดไปเลย ทำให้เราจะเสียเวลาการโหลดนานมาก

แต่เดี๋ยวนี้ เรามีตัวช่วยเพื่อที่จะโหลด script ได้อย่างมีประสิทธิภาพมากขึ้น ด้วย keyword async defer

เพื่อให้เห็นภาพว่าทั้งสองต่างกันยังไง ดูรูปนี้ครับ

โดยคอนเซปหลักคือ หากใส่ async หรือ defer การโหลดตัว script จะไม่บล็อกการ render ทั้งคู่ แต่จุดต่างคือ ถ้าเป็น async หาก script โหลดเสร็จแล้ว จะ execute script ทันที ทำให้การ render จะโดนบล็อก แต่ถ้าเป็น defer จะรอให้การ render HTML เสร็จก่อนถึงค่อยสั่ง script

โดยมาก use case async จะเยอะกว่า defer เยอะ เพราะตัว script ที่จะ defer ได้นั้นต้องออกแบบมาเพื่องานนี้โดยเฉพาะ

ผลที่ได้จากการทำอย่างนี้คือ จะช่วยให้ First Paint ขึ้นมาเร็วขึ้น เพราะตัว JavaScript จะไม่บล็อกการ render ในช่วงแรก

บอกใบ้ Browser ว่าควรโหลดอะไรก่อนด้วย preload

ในเว็บไซต์นั้น แต่ละ resource ที่เราโหลดมา เราสามารถ “บอกใบ้” ไฟล์ที่จะถูกใช้ในเร็วๆ วันให้กับ browser เพื่อที่ตัว browser จะไปโหลดไฟล์มาก่อนครับ โดยใช้ keyword ต่างๆ เช่น

DNS Prefetch หากเราต้องมีการดึง resource จาก domain สักอย่างบ่อยๆ เช่น CloudFront CDN, Amazon S3 เราสามารถบอกให้ browser ไป prefetch DNS เพื่อ resolve DNS รอไว้ก่อนได้เลย โดยใช้ keyword rel="dns-prefetch"

<link rel="dns-prefetch" href="//example.com">

หรือ beyond ไปไกลกว่านั้น เราสามารถให้ browser connect ไปยัง domain นั้นรอทิ้งไว้ได้เลย โดยใช้ keyword rel="preconnect" แทน

<link rel="preconnect" href="http://example.com">

นอกจากนี้ยังมีอีก keyword ที่น่าสนใจคือ preload ครับ preload จะเป็นการบอกใบ้ว่า resource นี้จะถูกใช้ในอนาคตแน่ๆ ให้ไปโหลดเก็บไว้ก่อนเลย พอถึงเวลาที่ต้องรันในจุดนั้น ก็จะหยิบไปใช้ได้เลย

เช่น หากเราต้องใช้ style.css กับ main.js แน่ๆ เราก็ preload มันก่อนได้เลย แบบนี้

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">

แล้วพอตัว browser parse HTML เจอแท็กที่มีการเรียกใช้งาน style.css กับ main.js ตัว browser ก็จะหยิบไปใช้ได้เลย ไม่ต้องเสียเวลาโหลดตอนนั้น

<link rel="stylesheet" href="style.css">
<script src="main.js"></script>

สำหรับใครอยากอ่านเรื่องของ prefetch preload เพิ่มเติม แนะนำลิ้งด้านล่างเลยครับ

Code Splitting can save you

การทำ Code Splitting เป็นอีกแนวคิดนึงที่ช่วยลดขนาด JavaScript ได้ โดยปกติเวลาเราทำแอพด้วย SPA มักจะ build ออกมาได้ไฟล์สุดท้ายเป็น JavaScript ไฟล์เดียว

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

ทำให้แนวคิด Code Splitting จึงเกิดมา คอนเซปง่ายๆ คือแทนที่จะมี JavaScript สุดท้ายแค่ไฟล์เดียว เราก็แบ่งย่อยๆ ออกเป็นหลายๆ ไฟล์

ซ้าย: ไม่ทำ Code Splitting ทั้งหมดจะรวมเป็นก้อนเดียว / ขวา: ทำ Code Splitting จากก้อนเดียวแยกเป็น 6 ก้อน

ซึ่งก็จะสามารถแบ่งได้หลายแบบ แบบนิยมทำกันก็คือ Route-based คือแบ่งตาม route ที่ใช้ อะไรที่หน้านั้นใช้ก็จะมัดรวมเป็นก้อนเดียวกัน เวลาโหลดก็จะโหลดเฉพาะหน้าที่เราเข้ามาเท่านั้น หน้าอื่นๆ จะไปโหลดตอนจะใช้ทีหลังแทน

อีกแบบคือ Component-based ก็คืออิงตามว่า component ไหนมาด้วยกันก็กรุ๊ปๆ กัน

การทำ Code Splitting เอาจริงๆ ก็แอบปวดหัวนิดๆ แต่ framework เช่น Next.js ก็ทำให้เราแล้วเรียบร้อย (เป็น Route-based) ดังนั้นเราก็รอดในเรื่องนี้ไป

แต่อย่างใน Next.js เราก็ทำ Code Splitting ได้อีกเลเวลนึง คือการใช้ Dynamic import ช่วย โดยมันก็คือการทำ Code Splitting แบบ Component-based นั่นแหละ

หากอยากดูเพิ่มเติม สามารถตามไปได้ในบล็อกนี้เลยขรั่บ

โยน static resource ขึ้น CDN

อะไรที่เป็น static resource จ๋าๆ ก็จับมันขึ้น CDN ให้หมดครับ

CDN (Content Delivery Network) ให้นึกภาพง่ายๆ ว่า เราเอา resource ที่มีการใช้งานบ่อยๆ ไปวางตัวอยู่ใน cache server ทั่วทุกมุมโลก ทำให้ไม่ว่า user จะมาจากประเทศไหน ก็สามารถโหลด resource นั้นได้ไวเท่าๆ กัน

บริการ CDN ก็จะมีหลายเจ้าให้ใช้ครับ แต่เจ้ายอดนิยมก็คงจะเป็น AWS CloudFront นี่แหละครับ

โหลดฟอนต์ให้พอเหมาะ

อีกตัวนึงที่หน่วงการ render พอๆ กันคือการโหลดฟอนต์นี่แหละครับ คือจริงๆ ตัวฟอนต์นอกจากขนาดจะใหญ่แล้วเนี่ย ยัง block การ render อีกต่างหากครับ

และหลายคนชอบโหลดฟอนต์มันมาทุกขนาด ทุกรูปแบบ หนักโคตรเลยนะนั่น

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

มีแค่ไหน ใช้แค่นั้น

ต่อมาก็คือ เลือกท่าของการโหลดฟอนต์ ปกติเรามักจะใช้ @font-face ซึ่งมันเป็นอพไรที่โค้ดช้า ช้ามากๆ เลยต้องหาทางเลือกอื่นๆ เช่น ใช้ Web Font Loader

What we achieve so far

ฟ้องด้วยภาพ โดยใช้ PageSpeed Insights

ก่อน
หลัง

ส่วน Lighthouse นั้นน่าเสียดายที่ไม่ได้เก็บรูปทดสอบก่อนและหลังไว้ T-T แต่จากประสบการณ์คือการจะ optimize Lighthouse ให้เต็มร้อยนั้นเหนื่อยมากครับ และ approach ที่ดีที่สุดจริงๆ คือการขึ้นเว็บตั้งแต่แรก และคงให้ Lighthouse ได้คะแนน 100 เต็มเรื่อยๆ มากกว่าจะมานั่งปรับเว็บจากคะแนนน้อยมากๆ จนได้เต็มร้อย

แล้วทำไปเนี่ย เหนื่อยขนาดนี้มันได้อะไรขึ้นมา?

เอาจริงๆ งาน optimize เว็บถือว่าเหนื่อยและโหดหินเอาเรื่องครับ และบางทีเราไม่เห็นผลมันชัดเจนแต่แรกด้วยซ้ำ กว่าจะไปเห็นผลก็นู้น อีกสักพักเลย

แต่การทำงานนี้มีข้อดีหลายอย่างครับ หลักๆ คือเว็บโหลดเร็วขึ้น แน่นอนว่า user ก็จะ satisfy มากขึ้น ต่อมาคือ การที่จะทำให้เว็บโหลดไวขึ้น บางทีเราต้องมา revise code มาดูว่ามีอะไรที่เราใช้ไม่ใช้บ้าง มีอะไรที่ตัดออกไปได้ มีอะไรที่ปรับได้บ้าง ก็ทำให้เว็บเราโหลดไวขึ้นเยอะครับ

และอีกอย่างคือได้เรียนรู้อะไรเยอะแยะเลยครับ ทั้งหมดที่ผมเขียนมานี้ก็คือส่วนนึงที่ได้เรียนรู้มา และมันก็มองย้อนกลับไปถึง fundamental และรากฐานของ web technology และบางทีก็พ่วงเรื่อง network เช่น HTTP/2, CDN เป็นต้น

ท้ายสุดหวังว่าบล็อกนี้จะช่วยให้ทุกท่านได้ไอเดียหรืออยากกลับไป optimize เว็บไซต์ให้เร็วขึ้นนะครับ :)

แถม

Talk “Web performance made easy” จากงาน Google I/O ‘18

ช่วงโฆษณา

TakeMeTour สตาร์ทอัพการท่องเที่ยวสัญชาติไทยแท้ๆ กำลังเปิดรับสมัคร Developer เพิ่มเติมอยู่ ในตำแหน่งต่อไปนี้

  • Senior/Junior JavaScript Engineer (Front-end/Back-end/Full-stack)
  • UI/UX Designer

สำหรับ JavaScript Engineer นั้น Stack ที่เราใช้คร่าวๆ เป็นดังนี้

  • Front-End: React/Redux/Next.js/Expo
  • Back-End: Node.js/Express (with micro-service architecture)/Mongoose/Elastic Search/Redis
  • และอื่นๆ อีกมากมาย รอคอยให้มาได้เล่นกันเต็มไปหมด เช่น Kubernetes, Data Studio

สำหรับการทำงานและสวัสดิการของเรานั้นประกอบด้วย

  • เวลาเข้าออก Flexible เข้าออกกี่โมงก็ได้ เราเน้นที่ผลงาน ไม่เน้นที่เวลาในการทำงาน
  • การแต่งตัวสบายๆ ใส่ชุดอะไรมาทำงานก็ได้ ขอแค่ให้เหมาะสม
  • ออฟฟิศเดินทางสะดวก ติด BTS และ Airport Rail Link สถานีพญาไท
  • วันหยุด 30 วันต่อปี
  • มี Google Home Mini เหงาหงอยรอคนมาคุยด้วย (ได้เหรอ)
  • รวมถึงยังมีบอร์ดเกมฝุ่นเกาะรอคนมาเล่นด้วยอยู่
  • และยังมี PS4 มาให้เล่นเป็นช่วงๆ ด้วย (ช่วงนี้กระแส Detroit Become Human กำลังมาแรง อยากเล่นก็รีบเร่เข้ามา)

สำหรับผู้ที่สนใจสมัครตำแหน่ง JavaScript Engineer ให้ทำการ fork repo ด้านล่างไปทำ แล้วส่งอีเมล repo ที่ทำ และ resume เข้ามาที่ WantToWork@takemetour.com ได้เลยครับ

ส่วนตำแหน่งอื่นๆ ส่งอีเมลแนบ CV, Resume เข้ามาได้ที่ WantToWork@takemetour.com ได้เลยครับ

--

--

Tananan Tangthanachaikul
TakeMeTour Engineering

Senior Full-Stack Developer@TakeMeTour - A man who passionately craft software