Client Directives
เปลี่ยน component ให้เป็น island
หัวข้อที่มีชื่อว่า “เปลี่ยน component ให้เป็น island”framework component ที่ import เข้ามาในไฟล์ .astro จะ render เป็น static HTML — ไม่มี interactivity — จนกว่าเราจะเพิ่ม client directive ให้ directive บอก Astro สองอย่าง: hydrate component นี้บน client และ เมื่อไหร่ ให้ทำ
---import Counter from '../components/Counter.jsx';---<Counter /> <!-- static HTML, no JS ships --><Counter client:load /> <!-- an island: hydrates immediately -->คำว่า “เมื่อไหร่” คือหัวใจทั้งหมด hydrate เร็วขึ้นทำให้ component interactive เร็วขึ้น แต่แลกด้วย JavaScript ที่โหลดล่วงหน้าและเวลาบน main thread ส่วน hydrate ช้าลงทำให้หน้าเบา แต่ interactivity มาช้า directive แต่ละตัวคือจุดที่ต่างกันบนเส้น trade-off นี้
directive ทั้งห้าตัว
หัวข้อที่มีชื่อว่า “directive ทั้งห้าตัว”client:load— hydrate ทันที ตั้งแต่หน้าโหลด ใช้กับ control ที่อยู่เหนือ fold และต้องทำงานได้ทันทีที่หน้าใช้งานได้: search ที่ header, toggle สำคัญ ๆ เป็นตัวที่ขยันที่สุดและแพงที่สุดclient:idle— hydrate ตอน browser idle (ผ่านrequestIdleCallback) หลังงานหลักของการโหลดเสร็จแล้ว เหมาะกับ interactivity ที่สำคัญแต่ไม่ต้องมาทันที — รอจังหวะที่ browser ว่างก่อนclient:visible— hydrate ตอน component scroll เข้ามาในจอ (ผ่านIntersectionObserver) เป็น default ที่ดีที่สุดสำหรับอะไรก็ตามที่อยู่ใต้ fold: widget comment, ฟอร์ม newsletter ที่ footer, carousel ที่อยู่ลึกลงไปในหน้า JavaScript ของตัวเองจะไม่ถูกโหลดเลยถ้า user ไม่ scroll ไปถึงclient:media— hydrate เฉพาะตอน CSS media query match เช่นclient:media="(max-width: 50em)"ใช้กับ interactivity ที่มีเฉพาะบาง breakpoint — เมนู hamburger ที่มีเฉพาะบน mobile ซึ่งไม่มีความหมายบน desktopclient:only="react"— ข้าม server rendering ทั้งหมด และ render บน client เท่านั้น เราต้องระบุชื่อ framework ("react","vue","svelte", …) เพราะ Astro จะไม่ render component นั้นบน server เพื่อตรวจว่าเป็น framework อะไร ใช้กับ component ที่ render บน server ไม่ได้เลย — พวกที่แตะwindow,localStorageหรือ library ที่ใช้ได้แค่บน browser ตั้งแต่ render ครั้งแรก
flowchart LR start["page loads"] --> load["client:load — hydrate now"] load --> idle["client:idle — when browser is idle"] idle --> visible["client:visible — when scrolled into view"] visible --> media["client:media — when a breakpoint matches"] only["client:only — skip server render, client only"]
เลือกตัวที่ถูก
หัวข้อที่มีชื่อว่า “เลือกตัวที่ถูก”เส้นทางตัดสินใจง่าย ๆ ครอบคลุมเกือบทุกเคส:
- ต้องทำงานได้ทันทีที่หน้าโหลด อยู่เหนือ fold ไหม? →
client:load - อยู่ใต้ fold หรือไม่ต้องใช้ทันที? →
client:visible(default ที่เบาและปลอดภัยที่สุด) - สำคัญแต่รอจังหวะว่างได้? →
client:idle - เกี่ยวเฉพาะบางขนาดหน้าจอ? →
client:media - render บน server ไม่ได้เลย? →
client:only="react"
สัญชาตญาณที่จะคว้า client:load มาใส่ทุกอย่างคือสิ่งที่ island มีไว้ป้องกันพอดี ส่ง JavaScript ให้น้อยที่สุดเท่าที่ให้ interactivity ที่ต้องการ และปล่อยให้ island ส่วนใหญ่ของคุณเป็น client:visible