सामग्री पर जाएँ
Blume
Esc
↑↓नेविगेट↵खोलें⌘Jप्रीव्यू
इस पेज पर

आइलैंड्स

किसी इंटरैक्टिव कंपोनेंट को 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) बिल्ड चेतावनी के साथ छोड़ दिए जाते हैं। जब दो आइलैंड्स एक ही नाम पर पहुँचते हैं — Counter.tsx और Counter.vue, या अलग-अलग सबफ़ोल्डरों में दो Counter.tsx फ़ाइलें — तो Blume फ़ाइल पाथ के क्रम में पहले वाले को रखता है और दूसरे को बिल्ड चेतावनी के साथ अनदेखा कर देता है।

किसी पेज से ब्राउज़र में कोड चलाने का एकमात्र तरीका आइलैंड ही है। MDX में किसी सादे HTML एलिमेंट पर लगा JavaScript इवेंट हैंडलर, जैसे <button onClick={() => open()}>, कभी नहीं चलता: पेज स्टैटिक HTML है, इसलिए फ़ंक्शन एट्रिब्यूट में टेक्स्ट के रूप में लिख दिया जाता है। Blume ऐसे हैंडलर के बारे में उसकी पंक्ति पर BLUME_MDX_EVENT_HANDLER के रूप में चेतावनी देता है। उस मार्कअप को एक आइलैंड में ले जाएँ और पेज में उस आइलैंड का उपयोग करें।

components.ts में आइलैंड्स रजिस्टर करना

यदि आप आइलैंड्स को अपने बाकी कंपोनेंट्स के साथ रखना चाहें — या उन्हें फ़ाइल से अलग नाम देना चाहें — तो उन्हें defineComponents के साथ एक client मोड वाली mdx एंट्री के रूप में रजिस्टर करें। आइलैंड बस इतना ही है: एक MDX कंपोनेंट जो हाइड्रेट होता है। प्रत्येक एंट्री हर MDX पेज में उपलब्ध होती है, और किसी islands/ फ़ाइल के समान नाम वाली एंट्री उस फ़ाइल की जगह ले लेती है।

import { defineComponents } from "blume";
import Counter from "./widgets/Counter.tsx";

export default defineComponents({
  mdx: {
    Counter: { component: Counter, client: "visible" }, // <Counter /> in any MDX page, hydrated
  },
});

कंपोनेंट को इंपोर्ट के ज़रिए या पाथ स्ट्रिंग के ज़रिए रेफ़र करें, और प्रति आइलैंड हाइड्रेशन मोड चुनें ("media" के साथ एक media क्वेरी भी देनी होती है):

export default defineComponents({
  mdx: {
    Chart: { component: "./widgets/Chart.tsx", client: "only" },
  },
});

फ़ोल्डर के विपरीत, यहाँ कोई डिफ़ॉल्ट नहीं है: client के बिना एक mdx एंट्री स्टैटिक HTML के रूप में रेंडर होती है, और यदि वह एंट्री React, Vue या Svelte कंपोनेंट है तो Blume चेतावनी देता है। Blume components.ts को स्टैटिक रूप से पढ़ता है, इसलिए एंट्री एक इंपोर्ट किया गया कंपोनेंट, एक पाथ स्ट्रिंग, या एक { component, client, media } ऑब्जेक्ट लिटरल होनी चाहिए — स्वीकृत फ़ॉर्म और अन्यथा मिलने वाली त्रुटि के लिए कस्टमाइज़ेशन देखें।

हाइड्रेशन

डिफ़ॉल्ट रूप से एक आइलैंड 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 चाहिए (चार्ट, एडिटर)
"media" (केवल components.ts) जब कोई CSS मीडिया क्वेरी मेल खाए ऐसा UI जो केवल कुछ आकारों पर चलता है, जैसे केवल-मोबाइल मेनू

"media" को अपने साथ क्वेरी की ज़रूरत होती है, इसलिए यह केवल components.ts एंट्री के लिए उपलब्ध है — { component: Menu, client: "media", media: "(max-width: 50em)" }। जो islands/ फ़ाइल इसे घोषित करती है, वह चेतावनी के साथ "visible" पर लौट आती है।

फ्रेमवर्क

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 } — कॉन्फ़िगर किए गए सर्च प्रोवाइडर से क्वेरी करें
useAssistant() { ask, messages, loading, reset } — असिस्टेंट एंडपॉइंट से स्ट्रीम करें

useBlume() और usePage() तब तक null लौटाते हैं जब तक आइलैंड माउंट नहीं हो जाता (ताकि सर्वर और क्लाइंट एक ही पहला फ़्रेम रेंडर करें) — इसके लिए गार्ड लगाएँ। स्नैपशॉट केवल उन पेजों पर उत्सर्जित होता है जो React भेजते हैं, इसलिए पूरी तरह स्टैटिक साइट को कोई कीमत नहीं चुकानी पड़ती।

PageLayout से बने कस्टम पेजों पर, clientData पास करें ताकि वहाँ के आइलैंड्स उसे पढ़ सकें:

<PageLayout
  clientData={{ config: data.config, navigation: data.navigation, page: { route: "/", title: "Home" } }}
  {/* …other props… */}
/>

अंतिम अपडेट

क्या यह पेज सहायक था?