आइलैंड्स
किसी इंटरैक्टिव कंपोनेंट को islands/ में रखें और उसे किसी भी MDX पेज में इस्तेमाल करें — स्वचालित रूप से हाइड्रेट, हर पेज पर इंपोर्ट किए बिना।
Blume आपके डॉक्स को डिफ़ॉल्ट रूप से शून्य JavaScript के साथ स्टैटिक HTML के रूप में रेंडर करता है। जब आपको कुछ इंटरैक्टिव चाहिए — एक लाइव डेमो, एक चार्ट, एक प्लेग्राउंड — तो आप एक आइलैंड जोड़ते हैं: एक फ्रेमवर्क कंपोनेंट जो JS केवल अपने लिए भेजता है, और केवल उन पेजों पर जो उसका उपयोग करते हैं।
islands/ परिपाटी
अपने प्रोजेक्ट के रूट में एक islands/ फ़ोल्डर में कोई कंपोनेंट रखें। इसका फ़ाइल नाम एक ऐसा कंपोनेंट बन जाता है जिसे आप किसी भी .mdx पेज में, बिना इंपोर्ट किए, इस्तेमाल कर सकते हैं:
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Clicked {count}</button>;
}
Here's a live counter: <Counter />
फ़ाइल नाम ही कंपोनेंट का नाम है, इसलिए यह एक PascalCase आइडेंटिफ़ायर होना चाहिए — केवल अक्षर, अंक और अंडरस्कोर (Counter.tsx → <Counter />)। लोअरकेस फ़ाइल नाम, डैश/डॉट/स्पेस वाले नाम (जैसे Time-Picker.tsx), और ऐसे दो आइलैंड्स जो एक ही नाम पर पहुँचते हैं, बिल्ड चेतावनी के साथ छोड़ दिए जाते हैं।
components.ts में आइलैंड्स रजिस्टर करना
यदि आप आइलैंड्स को अपने बाकी कंपोनेंट्स के साथ रखना चाहें — या उन्हें फ़ाइल से अलग नाम देना चाहें — तो उन्हें defineComponents के साथ रजिस्टर करें। islands समूह बिल्कुल islands/ फ़ोल्डर जैसा ही है: प्रत्येक एंट्री हर MDX पेज में उपलब्ध होती है और हाइड्रेट होती है (डिफ़ॉल्ट client: "visible" के साथ)।
import { defineComponents } from "blume";
import Counter from "./widgets/Counter.tsx";
export default defineComponents({
islands: {
Counter, // <Counter /> in any MDX page, hydrated
},
});
कंपोनेंट को इंपोर्ट के ज़रिए या पाथ स्ट्रिंग के ज़रिए रेफ़र करें, और डिस्क्रिप्टर फ़ॉर्म के साथ प्रति आइलैंड एक हाइड्रेशन मोड सेट करें:
export default defineComponents({
islands: {
Chart: { component: "./widgets/Chart.tsx", client: "only" },
},
});
हाइड्रेशन
डिफ़ॉल्ट रूप से एक आइलैंड client:visible का उपयोग करता है: यह तब हाइड्रेट होता है जब पाठक इसे स्क्रॉल करके दृश्य में लाता है, इसलिए आइलैंड्स से भरा पेज भी तुरंत लोड होता है। आइलैंड फ़ाइल में export const client के साथ किसी दूसरी रणनीति को चुनें:
// Skip server rendering entirely — for components that touch the DOM/window.
export const client = "only";
export default function Chart() {
/* ... */
}
client मान |
हाइड्रेट होता है | इसके लिए उपयोग करें |
|---|---|---|
"visible" (डिफ़ॉल्ट) |
जब स्क्रॉल करके दृश्य में आए | अधिकांश आइलैंड्स |
"load" |
पेज लोड होते ही तुरंत | ऊपरी हिस्से का, तुरंत चाहिए वाला UI |
"idle" |
जब मुख्य थ्रेड निष्क्रिय हो | गैर-अत्यावश्यक इंटरैक्टिविटी |
"only" |
केवल क्लाइंट, कभी सर्वर-रेंडर नहीं | ऐसी लाइब्रेरीज़ जिन्हें window/document चाहिए (चार्ट, एडिटर) |
फ्रेमवर्क
React बिना किसी सेटअप के काम करता है — जैसे ही आपके प्रोजेक्ट में कोई .tsx/.jsx आइलैंड होता है, Blume इसे अपने आप चालू कर देता है।
जब भी React सक्षम होता है, React Compiler डिफ़ॉल्ट रूप से चालू रहता है, इसलिए आपके आइलैंड्स स्वतः-मेमोआइज़्ड होते हैं — हाथ से लिखे useMemo/useCallback की ज़रूरत नहीं। यह Blume के साथ ही आता है; इंस्टॉल करने को कुछ नहीं है। blume.config.ts में इससे बाहर निकलें:
export default defineConfig({
react: { compiler: false },
});
Vue और Svelte भी समर्थित हैं; संबंधित Astro इंटीग्रेशन इंस्टॉल करें और जब Blume को कोई .vue या .svelte आइलैंड दिखता है, तो वह रेंडरर को जोड़ देता है:
# Vue
npm install @astrojs/vue vue
# Svelte
npm install @astrojs/svelte svelte
<script setup>
import { ref } from "vue";
const on = ref(false);
</script>
<template>
<button @click="on = !on">{{ on ? "On" : "Off" }}</button>
</template>
MDX में आपके द्वारा पास किए गए प्रॉप्स (<Counter start={5} />) कंपोनेंट को फ़ॉरवर्ड कर दिए जाते हैं, और चिल्ड्रन (<Counter>label</Counter>) डिफ़ॉल्ट स्लॉट के रूप में पहुँचते हैं।
हुक्स
आइलैंड्स अपने आप हाइड्रेट होते हैं, इसलिए प्रोजेक्ट डेटा को पिरोने के लिए कोई React कॉन्टेक्स्ट नहीं होता। इसके बजाय, blume/hooks एक छोटा स्नैपशॉट पढ़ता है जिसे लेआउट पेज में सीरियलाइज़ करता है — कोई प्रॉप ड्रिलिंग नहीं:
import { useBlume, usePage } from "blume/hooks";
export default function PageInfo() {
const blume = useBlume();
const page = usePage();
if (!(blume && page)) {
return null;
}
return (
<p>
You're reading <strong>{page.title}</strong> on {blume.config.title}.
</p>
);
}
| हुक | क्या लौटाता है |
|---|---|
useBlume() |
साइट के लिए { config, navigation }, या माउंट से पहले null |
usePage() |
मौजूदा पेज के लिए { route, title }, या माउंट से पहले null |
useSearch() |
{ search, results, loading } — कॉन्फ़िगर किए गए सर्च प्रोवाइडर से क्वेरी करें |
useAskAI() |
{ ask, messages, loading, reset } — Ask AI एंडपॉइंट से स्ट्रीम करें |
useBlume() और usePage() तब तक null लौटाते हैं जब तक आइलैंड माउंट नहीं हो जाता (ताकि सर्वर और क्लाइंट एक ही पहला फ़्रेम रेंडर करें) — इसके लिए गार्ड लगाएँ। स्नैपशॉट केवल उन पेजों पर उत्सर्जित होता है जो React भेजते हैं, इसलिए पूरी तरह स्टैटिक साइट को कोई कीमत नहीं चुकानी पड़ती।
PageLayout से बने कस्टम पेजों पर, clientData पास करें ताकि वहाँ के आइलैंड्स उसे पढ़ सकें:
<PageLayout
clientData={{ config: data.config, navigation: data.navigation, page: { route: "/", title: "Home" } }}
{/* …other props… */}
/>