Islands ข้าม Frameworks
ขอบเขต micro-frontend ที่ถูกที่สุดที่คุณจะเคยวาดได้คือ Astro island island คือ component แบบโต้ตอบที่เบ็ดเสร็จในตัวเอง ที่ hydrate ด้วยตัวเอง ส่ง JavaScript ของตัวเอง และไม่รู้อะไรเลยเกี่ยวกับ component รอบข้าง เปลี่ยน “component” เป็น “team” แล้วคุณก็ได้ micro-frontend: region ที่แยกตัวออกมาซึ่งกลุ่มหนึ่งเป็นเจ้าของ และ shell เพียงแค่วางลงบนหน้าเพจ
ส่วนที่น่าทึ่งคือ Astro ปล่อยให้ islands มาจาก framework ต่างกันบนหน้าเพจเดียวกัน ได้ ทีม Catalog สามารถเขียน Vue ทีม Reviews สามารถเขียน Svelte และทีม Cart สามารถอยู่กับ React ต่อไป — ทั้งหมดถูกเรนเดอร์ลงในเอกสาร HTML แบบ static เดียวกัน
การเพิ่ม framework integrations
หัวข้อที่มีชื่อว่า “การเพิ่ม framework integrations”แต่ละ framework ที่คุณต้องการ host อยู่ห่างจาก astro add เพียงคำสั่งเดียว คำสั่งนี้จะติดตั้ง renderer และจัดการ config ให้คุณ:
npx astro add react vue svelteหลังจากนั้น การ import component .jsx, .vue, หรือ .svelte เข้าไปในไฟล์ .astro ก็ทำงานได้เลย คุณเลือกให้แต่ละตัวเข้าสู่ hydration ด้วย client:* directive — client:load, client:idle, หรือ client:visible — และ Astro จะส่งเฉพาะ runtime ของ island นั้น เฉพาะตอนที่จำเป็นเท่านั้น
flowchart TD Page["Astro page (static HTML shell)"] Page --> RI["React island — Cart\n(client:load)"] Page --> VI["Vue island — Catalog\n(client:visible)"] Page --> SI["Svelte island — Reviews\n(client:idle)"] RI -.->|isolated| VI VI -.->|isolated| SI
แต่ละ island คือขอบเขตของตัวเอง การ crash ภายใน Vue island ไม่ทำให้ React island ล้มตามไปด้วย แต่ละตัว hydrate อย่างเป็นอิสระและเป็นเจ้าของเฉพาะ subtree ของตัวเองเท่านั้น
React ใน tree vs islands บนหน้าเพจ
หัวข้อที่มีชื่อว่า “React ใน tree vs islands บนหน้าเพจ”ใน React SPA ทุก region ที่โต้ตอบได้อยู่ภายใน component tree เดียวและ bundle เดียว ใน Astro นั้น หน้าเพจ คือ shell และแต่ละ region คือ island ที่ shell วางลงไป — โดยอาจมาจาก framework ที่ต่างกัน
// React SPA: one tree, one bundle.// Every region is a React component,// all hydrated together at startup.
export default function StorePage() { return ( <Shell> <Cart /> {/* React */} <Catalog /> {/* React */} <Reviews /> {/* React */} </Shell> );}---// Astro page: the shell is static HTML.// Each region is an island — and each may// be a different framework owned by a// different team.import Cart from '../islands/Cart.jsx'; // Reactimport Catalog from '../islands/Catalog.vue'; // Vueimport Reviews from '../islands/Reviews.svelte'; // Svelte---<main> <Cart client:load /> <Catalog client:visible /> <Reviews client:idle /></main>ลองเลย: React island และ Vue island เคียงข้างกัน
หัวข้อที่มีชื่อว่า “ลองเลย: React island และ Vue island เคียงข้างกัน”playground ด้านล่างเป็นหน้า Astro ที่สมบูรณ์และรันได้จริง หน้านี้ host React counter และ Vue counter ในเอกสารเดียวกัน — สอง framework, สอง islands ที่เป็นอิสระต่อกัน, หนึ่ง static shell เปิดใน StackBlitz แล้วดูแต่ละ island hydrate และเก็บ state ของตัวเอง
---
// src/pages/index.astro
// Each island below could be owned by a
// different team. The page is the shell.
import ReactCounter from '../components/ReactCounter.jsx';
import VueCounter from '../components/VueCounter.vue';
---
<html lang="en">
<head><title>MFE islands demo</title></head>
<body>
<h1>One page, two frameworks</h1>
<section>
<h2>Cart team (React)</h2>
<ReactCounter client:load />
</section>
<section>
<h2>Catalog team (Vue)</h2>
<VueCounter client:visible />
</section>
<p>Each counter keeps its own state, isolated.</p>
</body>
</html>หากต้องการรันจริงๆ คุณจะต้อง npx astro add react vue จากนั้นเพิ่ม src/components/ReactCounter.jsx (React component ปกติที่ใช้ useState) และ src/components/VueCounter.vue (Vue component ปกติที่ใช้ ref) component ทั้งสองไม่รับรู้ถึงกันและกัน — การแยกตัวนั้นแหละคือประเด็นทั้งหมด
islands คือทางเข้าสู่ micro-frontends ที่นุ่มนวลที่สุด: ไม่มี infrastructure เพิ่มเติม, ไม่มี remote loading, ไม่มี Module Federation — เป็นเพียง component จากทีม (และ framework) ต่างๆ ที่ประกอบกันโดย Astro shell ที่รวดเร็ว บทเรียนถัดไปจะขยายเรื่องนี้ขึ้นไปสู่ระดับ package ทั้งก้อนและ server fragment ที่ถูกเลื่อน (deferred)