สรุปเรื่อง Web Performance Optimization จาก BKK.js #8

Ayuth Mangmesap
Ayuth’s Story
6 min readFeb 24, 2020

--

ได้มีโอกาสไปฟังบรรยายในงาน BKK.js #8 จัดที่ WISESIGHT ซึ่งมี Speakers ทั้งหมด 4 ท่านซึ่งแต่ละคนก็พูดหัวข้อดังนี้

  1. มาในหัวข้อของ “การ Shared Code ระหว่าง Project และ JavaScript Framework”
  2. Teerasak Kroputaponchai มาในเรื่องของ Micro-frontend กับหัวข้อ “What I Talk About When I Talk About Mirco-Frontends”
  3. Henry Lim (English Session) มาในเรื่องดาร์กๆ กับ Dark Theme “EVERYTHING You Need To Know About Dark Theme”
  4. Jecelyn Yeen (English Session) กับประสบการณ์การทำเว็บไซต์ NG-MY 2019 กับหัวข้อ “How We Build NG-MY Website Performance, SEO, CICD”

โดยหัวข้อที่น่าสนใจที่สุดสำหรับผมคือหัวข้อ “How We Build NG-MY Website Performance, SEO, CICD”

ซึ่ง Jecelyn Yeen จะมาเล่าเกี่ยวกับการสร้าง NG-My Website และเทคนิคการ Optimize เว็บของเค้าเองได้น่าสนใจมากและสามารถนำไปใช้ได้จริงและใกล้ตัวผมมากที่สุด ผมเลยสรุปมาดังนี้

แอบบอกว่าจริง ๆ แล้วกะจะเขียนสรุปตั้งแต่ กรกฎาคม แต่ว่าดองไว้จนเกือบถึงปลายปีเลย (ตอนที่เขียนอยู่นี้ก็ปลายเดือนพฤศจิกายน 2562 ละ นานมากกก) (ตอนนี้ก็เดือนมกรา 2563 เข้าให้แล้ว … เอาล่ะไปดูเนื้อหากันเลย)

Section 1: Images

แทบทุกเว็บจะต้องมี Image แทบทั้งสิ้น ทีนี้ image จะต้องมีปัจจัยหลัก ๆ 4 ข้อดังนี้

  • Appropriate format
  • Appropriate compression
  • Appropriate display & size & density
  • Load only when necessary (lazy-loaded)

1.1 ไม่ควรใช้ .gif แต่ควรใช้ .mp4 แทน

Originally source from Jecelyn Yeen

ส่วนวิธีการ convert .gif ไปเป็น .mp4 สามารถใช้ ffmpeg ได้เช่น

ซึ่งผลลัพธ์ออกมาเป็นที่น่าตกใจทีเดียวเพราะลดขนาดภาพจาก

6.8M (.gif)→ 420K (.mp4)

6.8M (.gif)→ 420K (.mp4)

ทีนี้หลายคนอาจจะสงสัยว่าแล้วเว็บเช่น Facebook, Twitter ก็มี .gifเหมือนกัน

จริง ๆ แล้วผมพึ่งสังเกตจาก talk นี้เลยครับว่าเบื้อหลังมันคือ .mp4 ดี ๆ นี่เอง

The gif that shown on twitter or facebook or even giphy not a .gif actually it was mp4

1.2 ไฟล์ภาพควรใช้ webp แทน JPEG, PNG

WebP images นั้นมีขนาดเล็กกว่าไฟล์ JPEG, PNG อยู่ 25–35%

โดยส่วนมาก Browser Support เจ้าดัง ๆ ก็ Support กันหมดแล้ว

WebP image format — https://bit.ly/webp-support

ซึ่งวิธีการใช้งานจะใช้ tag <picture> ครอบและ ภาพไว้ด้านในดังด้านล่าง

Originally source from Jecelyn Yeen’s Slide

ถ้า .webp ไม่ support ใน browser ก็จะโหลดภาพ .jpg ปกติแทน

อันนี้ขอเสริมนิดหนึ่งว่าเว็บไซต์เช่นพวก ebay ก็นำ webp ไปใช้แล้วเหมือนกันนะ (จริง ๆ เห็นนานแล้วแหละแต่ตอนนั้นยังไม่รู้ว่าคืออะไร)

1.2 Image Compression

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

การ Compression นั้นมีด้วยกัน 2 รูปแบบคือ

  1. Lossless Compression คือการ compress โดยที่ไม่ลดคุณภาพของไฟล์ลงแต่การ compress ชนิดนี้จะไม่ช่วยลดขนาดของไฟล์ลงมากเท่าไรนัก
  2. Lossy Compression คือการ compress โดยที่ลดคุณภาพของไฟล์ลงอย่างมากเพื่อแลกกับขนาดที่เล็กลงอย่างมากเช่นกัน

หากใครเคยดาวน์โหลดเพลงมาฟังครับ มันจะมีไฟล์เพลงอยู่สองประเภทก็คือ Lossless กับ Lossy นี่แหละครับ ถ้า Lossless ก็จะเป็นพวกไฟล์นามสกุล .flac ซึ่งไฟล์จะมีขนาดใหญ่มาก (จากที่เคยดาวน์โหลดประมาณ ~10 MB ต่อเพลง) ซึ่งต่างกับ Lossy ที่จะเป็นพวกนามสกุล .mp3 ซึ่งขนาดไฟล์จะประมาณ (~1–2 MB ต่อเพลง)

พอจะเห็นความต่างของขนาดไหมครับ ถ้าเราเก็บ lossless ไฟล์เดียวอาจจะเก็บ lossy ได้ 5 ไฟล์ ดังนั้นถ้าไม่ซีเรียสเรื่องคุณภาพอะไรมากก็เก็บเป็น lossless จะดีกว่าครับ ประหยัดพื้นที่เครื่องด้วย

การบีบอัดแบบ Lossy นั้นจะช่วยลดขนาดของไฟล์รูปภาพเยอะกว่าก็จริงแต่นั่นก็หมายความว่าเราต้องแลกด้วยคุณภาพที่เสียไปด้วยครับ ตัวอย่างเช่น ภาพดอกไม้ด้านล่าง

Originally source from Jecelyn Yeen’s Slide

สรุปว่า Lossy Compression ถ้าเราตั้งค่า quality ไว้สัก 80–85 เปอร์เซ็นต์จะส่งผลกระทบต่อรูปภาพน้อยที่สุดและจะช่วยลดขนาดของรูปภาพลงไปถึง 30–40%

ซึ่งบางภาพแล้วถ้าเราเอาเป็นพื้นหลังเราก็ไม่จำเป็นต้องใช้ภาพระดับ Full HD หรือโครตจะคมชัดให้เสียดาย bandwidth หรือ data plan ของเรา เมื่อภาพมีขนาดน้อยลงเว็บเราก็จะโหลดไวขึ้นด้วย

เครื่องมือที่จะช่วย compress จะมีรายชื่อดังนี้

Originally source from Jecelyn Yeen’s Slide

Update 12 Jan 2019 พอดีเห็นในไลฟ์ทำเว็บ​(นาทีที่ 49.54) JavaScript Bangkok 1.0.0 ของพี่ Thai Pangsakulyanont ได้เครื่องมือมาใหม่ชื่อ ImageOptim และอีกตัวหนึ่งจำไม่ได้มันเป็น command line

โดยเค้านำภาพธรรมดาที่เป็น .png ที่มีภาพความละเอียดสูงมาย่อให้เป็น .jpg และใช้ ImageOptim ทำ Lossy Compression ให้มีขนาดเล็กลงไปอีกซึ่งแต่เดิมไฟล์ภาพ 1.3 MB ย่อให้เหลือ 119 KB ซึ่งลดลงเกือบ 11 เท่าเลยทีเดียว!

1.3 Responsive Image

Originally source from Jecelyn Yeen’s Slide

รูปภาพที่เราดาวน์โหลดมานั้นล้วนมี cost ทั้งนั้น ถ้าเราดาวน์โหลดรูปภาพของ Desktop มาแต่เราใช้บน Mobile มันก็สิ้นเปลืองโดยใช่เหตุ โดยรูปภาพบน Desktop อาจใหญ่กว่าบนมือถือประมาณ 2–3 เท่า

รูปภาพที่มีขนาดมากเกินยังทำให้ cost ต่าง ๆ ไม่ว่าจะเป็น

  1. Transmission cost
  2. Decoding cost
  3. Resizing cost

ทางที่จะ Optimize ในส่วนนี้ได้ก็คือ เราต้องมีรูปภาพขนาดต่างกัน 3–5 ขนาดเพื่อแสดงผลได้ดีที่สุดในแต่ละหน้าจอ

Squoosh (resize, compress, format)

เค้าแนะนำเว็บตัวหนึ่งที่มีชื่อว่า Squoosh! โดยเป็น Open Source จาก GoogleChromeLabs เอาไว้ compress พวกภาพโดยสามารถเลือก option ต่าง ๆ ได้

ซึ่งความสามารถมันสามารถทำได้ทั้ง

  • Resize
  • Compress
  • Format

ภาพแมวด้านล่างคือตัวอย่างครับ ผมลากภาพแมวเข้าไปและเค้าจะมี options ให้เลือกด้านข้างเช่นพวก compression methods, width, height และสามารถเลือก

ภาพแมวที่เปิดด้วย Squoosh โดยด้านซ้ายคือขนาดปกติ ด้านขวาคือขนาดที่ set quality เป็น 0

หรือเราสามารถทำ automate ด้วย npm packages เหล่านี้ได้

  • imagemin
  • sharp
  • jimp

สรุปเรื่อง Performant Images จะมี key 4 ตัวด้วยกัน คือ

  • Appropriate format
  • Appropriate compression
  • Appropriate display & size & density
  • Load only when necessary (lazy-loaded)

1.4 Lazy-Loading Images

นี่ก็เป็นอีกเทคนิคหนึ่งที่สามารถทำได้เลยเช่นกัน พูดง่าย ๆ คือแทนที่เราจะดาวน์โหลด image มาทั้งหน้า เราก็แค่ดาวน์โหลดภาพแค่บนหน้าจอที่ user เห็นเท่านั้นเอง ลองดูเดโมได้ที่นี่ https://mathiasbynens.be/demo/img-loading-lazy

ทีนี้การทำ lazy-loading ถ้าใน chrome เวอร์ชัน 76 ขึ้นไปจะมี native lazy-loading มาให้เราเพียงแค่เราใส่ loading

การ lazy-loading สามารถทำได้ทั้ง image, iframe ครับ ทั้งนี้หาก browser ไม่ support native lazy-loading เราสามารถใส่สคริปต์ด้านล่างลงไปแทนได้

Source from https://web.dev/native-lazy-loading/

1.4 ใช้ Image CDN

Source from https://www.cloudflare.com/learning/cdn/what-is-a-cdn/

CDN (Content Delivery Network) คือกลุ่มของเซิฟเวอร์ที่ตั้งอยู่ที่ต่าง ๆ ที่เอาไว้ให้บริการพวกไฟล์ HTML, javascript files, stylesheets, images และ videos ต่าง ๆ แทนที่ client จะ request ไปหาเครื่อง server ของเราโดยตรง(สีเหลือง) ถ้าเจ้าพวก server ที่อยู่ตามประเทศต่าง ๆ มีไฟล์ที่ client ร้องขออยู่ก็จะตอบกลับไปเลย

จินตนาการว่าเราอยู่ประเทศไทยถ้าเราต้องการดู NAKED DIRECTOR ใน Netflix แทนที่เราจะวิ่งไปเอาไฟล์ video ที่อยู่ที่อเมริกาเราก็วิ่งไปเอาจากเซิฟเวอร์ที่อยู่ใกล้ที่สุดแทนเช่นสิงค์โปรเป็นต้น รูปภาพและพวก static files ก็ทำเช่นเดียวกัน

Originally source from Jecelyn Yeen’s Slide

ในหัวข้อนี้ไม่มีอะไรมากครับ เอาภาพของเราขึ้น CDN แล้วเรียกเอาครับ เช่น เราต้องการภาพ cat.jpg ที่มีความกว้าง 300 ความยาว 200 และ quality 50

ซึ่งพวก Popular Image CDN ได้แก่ Akami Image Manager, Cloudinary, Imgix, Thumbor (self-hosted)

ส่วนตัวผมใช้ Cloudflare อยู่ครับไม่ต้องติดตั้งอะไรมากให้ตัว DNS ชี้ไปที่ IP ของเค้าและเรา manage พวก Settings ต่าง ๆ ผ่าน web interface เค้าอีกทีหนึ่ง แต่ด้วยความง่ายนี้เองเราต้องเป็นเจ้าของ domain หรือได้รับสิทธิ์จากเจ้าของให้ทำนะครับ

Section 2: Web Fonts

https://www.gstatic.com/images/icons/material/apps/fonts/1x/opengraph_color_1200dp.png

Flash of Invisible Text (FOIT)

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

browser จะไม่แสดตัวอักษรจนกว่าจะถึงระยะเวลาที่กำหนด มันเลยทำให้ User Experience ไม่ค่อยดีนัก

โดย browser แต่ละตัวจะมีระยะเวลาดังนี้

  • Edge 3 seconds
  • Chrome 3 seconds
  • Firefox 3 seconds
  • Safari ∞ seconds …

อาการนี้ส่งผลกระทบต่อ 2 / 5 mobile sites

ตัวอย่างอาการ FOIT

https://youtu.be/vTf9HRTWKtM?t=278

Flash of Unstyled Text (FOUT)

https://upload.wikimedia.org/wikipedia/commons/b/b0/Wikipedia_FOUC.png

FOUT คือการที่ browser จะแสดงผลหน้าเว็บเพจด้วย default styles ก่อนที่จะดาวน์โหลด styles ของเว็บเราและ re-render หน้านั้นด้วย styles ที่ดาวน์โหลดมา

ตัวอย่างเช่น

https://upload.wikimedia.org/wikipedia/commons/9/93/Fouc-example.gif

เราสามารถใช้วิธีนี้แก้ปัญหา FOIT ได้ (เพราะว่า FOIT จะไม่แสดง font ยังดาวน์โหลดไม่เสร็จ แต่วิธีนี้จะแก้ปัญหาโดยการให้แสดงผลด้วย default font ของ system ไปก่อนและเมื่อดาวน์โหลดเสร็จก็ค่อยเปลี่ยน font เป็นตัวที่เสร็จ)

สามารถทำได้ดังนี้คือ

ซึ่งช่วยให้

  • 0.5s improvement in “Visually Complete” on 3G
  • 20% Improvement in mobile page load times (this & other techniques)

ข่าวดีสำหรับคนทีใช้ Google Fonts เราสามารถเติม &display=swap ได้เลยเช่น

Optimizing your font request

ถ้าเราใช้ font ที่มีตัวอักษรแค่ 10 เราก็ไม่ต้องการ font ของทุกตัวอักษร

ถ้าเป็น Google Fonts สามารถทำได้โดยการใส่

อ่านต่อได้ที่

Font import

Originally source from Jecelyn Yeen’s Slide

import โดยใช้ @import จะช่วยลดเรื่องของ render-blocking

Icon Fonts

ถ้าเราใช้แค่ 10 icons เราจะ load อีก 100 icons มาทำไม?

เราสามารถแก้ปัญหานี้โดยใช้ SVG หรือ inline แทนก็ได้

ลองไปดูพวก icomoon, icomoon-cli, fonticons ครับ

Section 3: JavaScript

To be continued.

References

Jeremy Wagner, ‘Replace Animated GIFs with Video’, Web Fundamentals [web blog], https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video, (accessed 15 Nov 2019).

Image Compression

What Is Image Compression?, KeyCDN [website], 21 November 2018, https://www.keycdn.com/support/what-is-image-compression, (accessed 27 November 2019).

Lossless compression, Wikipedia [website], 13 November 2019, https://en.wikipedia.org/wiki/Lossless_compression, (accessed 27 November 2019).

Lossy compression, Wikipedia [website], 13 November 2019, https://en.wikipedia.org/wiki/Lossless_compression, (accessed 27 November 2019).

Responsive Images

What Img Srcset Does In HTML5: A Quick & Simple Guide Read more [website], https://html.com/attributes/img-srcset/, (accessed 19 Jan 2019).

Lazy-loading Image

Automatically lazy-loading offscreen images & iframes for Lite mode users, Chromium Blog [website], 24 October 2019, https://blog.chromium.org/2019/10/automatically-lazy-loading-offscreen.html, (accessed 8 December 2019).

Native lazy-loading for the web, web.dev [website], 6 August 2019, https://web.dev/native-lazy-loading/, (accessed 8 December 2019).

CDN

What Is a CDN? How Does a CDN work?, Cloudflare [website], https://www.cloudflare.com/learning/cdn/what-is-a-cdn/, (accessed 14 Jan 2019).

Font

How to Fix Flash of Invisible Text (FOIT) in WordPress [website], https://wpspeedmatters.com/fix-foit-font-in-wordpress/, (accessed 19 Jan 2019).

Get Started with the Google Fonts API [website], https://developers.google.com/fonts/docs/getting_started#optimizing_your_font_requests, (accessed 19 Jan 2019)

font-display [website], https://css-tricks.com/almanac/properties/f/font-display/, (accessed 19 Jan 2019)

Responsive Images 101, Part 3: Srcset Display Density [website], https://cloudfour.com/thinks/responsive-images-101-part-3-srcset-display-density/, (accessed 19 Jan 2019)

Flash of unstyled content [website], https://en.wikipedia.org/wiki/Flash_of_unstyled_content, (accessed 24 Feb 2019)

font-display [website], https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display, (accessed 24 Feb 2019)

Slides

--

--