Island คืออะไร?
ในแอป React หรือ Next.js browser ได้รับ JavaScript bundle ขนาดใหญ่หนึ่งก้อน React บูต เดิน component tree ทั้งหมด และแนบ event listeners ทุกที่ — แม้แต่กับ component ที่ไม่มีการโต้ตอบใดๆ นี่คือ full-app hydration
Island Architecture ที่คิดค้นโดย Jason Miller และทำให้เป็นที่นิยมโดย Astro พลิกค่าเริ่มต้น: เพจเป็น HTML ที่ไม่ทำงาน มีเฉพาะ component ที่ต้องการ interactivity เท่านั้นที่ถูก hydrate และ hydrate อย่างอิสระ — เหมือนเกาะในทะเลของ markup แบบ static
ค่าใช้จ่ายของ hydration ใน React vs Astro
หัวข้อที่มีชื่อว่า “ค่าใช้จ่ายของ hydration ใน React vs Astro”// Next.js page — the WHOLE tree hydrates.// Even <Header> and <Footer> download JS.export default function BlogPost({ post }) { return ( <> <Header /> {/* JS downloaded + hydrated */} <article>{post.content}</article> {/* JS downloaded + hydrated */} <LikeButton postId={post.id} /> {/* JS downloaded + hydrated */} <RelatedPosts posts={post.related} />{/* JS downloaded + hydrated */} <Footer /> {/* JS downloaded + hydrated */} </> );}// Total JS budget: EVERYTHING---// Astro page — only <LikeButton> needs JS.import Header from '../components/Header.astro';import LikeButton from '../components/LikeButton.jsx';import RelatedPosts from '../components/RelatedPosts.astro';import Footer from '../components/Footer.astro';const { post } = Astro.props;---<Header /> <!-- 0 KB JS --><article>{post.content}</article> <!-- 0 KB JS --><LikeButton client:visible postId={post.id} /> <!-- hydrated --><RelatedPosts posts={post.related} /> <!-- 0 KB JS --><Footer /> <!-- 0 KB JS -->{/* Total JS budget: ONE component */}ในหน้าเพจที่มีเนื้อหาเป็นหลัก เช่น บล็อก, landing page, หรือเว็บ docs — ส่วนใหญ่ของ component เป็นแค่การแสดงผล ไม่ตอบสนองต่อการคลิก การ hydrate เหล่านั้นสิ้นเปลือง CPU และทำให้ Time to Interactive ช้าลง
ประสิทธิภาพที่ได้รับ
หัวข้อที่มีชื่อว่า “ประสิทธิภาพที่ได้รับ”Astro วัดสิ่งนี้อย่างแม่นยำ เพจที่มี island LikeButton เดียวจะดาวน์โหลดเฉพาะ JavaScript สำหรับปุ่มนั้นและ React runtime ของตัวเอง — ไม่มีอื่นนอกจากนั้น Next.js เทียบเท่าส่ง React บวก component ทุกตัวบนเพจ
ผลลัพธ์จริงในเว็บที่มีเนื้อหาหนาแน่น:
- ลด JavaScript ที่ส่งได้ 90%+
- Largest Contentful Paint เร็วขึ้น — HTML มาถึงพร้อม parse แล้ว ไม่มี hydration blocking การ render
- Time to Interactive ต่ำลง — มีเพียง island เดียวที่ต้องบูท
”Partial hydration” หมายความว่าอะไร
หัวข้อที่มีชื่อว่า “”Partial hydration” หมายความว่าอะไร”รูปแบบนี้เรียกว่า partial hydration เพราะมีเพียง บางส่วน ของเพจที่ถูก hydrate แต่ละ island:
- Render เป็น HTML บน server/build (เหมือน
.astrocomponent ทั่วไป) - ส่ง JS bundle ของตัวเองไปยัง browser
- Hydrate อย่างอิสระ — islands ไม่แชร์ React root
จุดสุดท้ายสำคัญมาก: islands ถูกแยกออกจากกัน ไม่มี React tree เดียวที่เชื่อมต่อกัน ซึ่งหมายความว่าไม่มีการแชร์ React context ข้าม islands โดยค่าเริ่มต้น คุณจะได้เรียนรู้วิธีจัดการกับนั้นใน เมื่อใดควรใช้ Island
// React: ONE root, one reconciler, shared contextimport ReactDOM from 'react-dom/client';ReactDOM.createRoot(document.getElementById('root')) .render(<App />);// Every component inside <App> is part of this tree.// React.createContext() works across the whole tree.---// Astro: MULTIPLE roots, one per island// Astro mounts each island independently:// ReactDOM.createRoot(islandEl).render(<Counter />)// ReactDOM.createRoot(likeEl).render(<LikeButton />)// Each island has its own React root.// React.createContext() does NOT cross island boundaries.import Counter from '../components/Counter.jsx';import LikeButton from '../components/LikeButton.jsx';---<Counter client:load /><LikeButton client:visible postId={42} />