सामग्री स्रोत
लोकल फ़ाइलों, किसी रिमोट रिपॉज़िटरी, किसी CMS, या किसी भी कस्टम बैकएंड से डॉक्स लाएँ — और कई स्रोतों को एक ऐसी स्टैटिक-फ़र्स्ट साइट में मिलाएँ जो बिल्ड टाइम पर पढ़ी जाती है।
डिफ़ॉल्ट रूप से Blume .md/.mdx फ़ाइलों का एक फ़ोल्डर पढ़ता है। कंटेंट स्रोत आपको कहीं और से पेज लाने देते हैं — किसी रिमोट रिपॉज़िटरी, किसी CMS, या किसी भी कस्टम बैकएंड से — और कई स्रोतों को एक ही साइट में मिलाने देते हैं। स्रोत बिल्ड टाइम पर पढ़े जाते हैं; Blume स्टैटिक-फ़र्स्ट ही रहता है।
डिफ़ॉल्ट
बिना किसी कॉन्फ़िगरेशन के, Blume आपके कंटेंट रूट (डिफ़ॉल्ट रूप से docs) को एक फ़ाइलसिस्टम स्रोत के रूप में स्कैन करता है। टॉप-लेवल content.root, content.include और content.exclude विकल्प उसी एकल स्रोत के लिए शॉर्टहैंड हैं — न कुछ इंपोर्ट करना है, न कुछ बदलना है।
import { defineConfig } from "blume";
export default defineConfig({
content: { root: "docs" },
});
एडैप्टर
content.sources की हर एंट्री एक एडैप्टर है: blume/sources से इंपोर्ट की गई एक फ़ैक्टरी, जो एक सादा डिस्क्रिप्टर लौटाती है जिसे Blume बिल्ड टाइम पर पढ़ता है। स्रोतों को जोड़ने के लिए एक sources ऐरे जोड़ें। जब sources मौजूद होता है, तो यह निहित डिफ़ॉल्ट की जगह ले लेता है, इसलिए अपने लोकल डॉक्स के लिए एक filesystem() एंट्री शामिल करें — और root, include या exclude को उसके अंदर ले जाएँ। शॉर्टहैंड और sources को एक साथ इस्तेमाल नहीं किया जा सकता; Blume बताता है कि किस फ़ील्ड को ले जाना है।
import { defineConfig } from "blume";
import { filesystem, mdxRemote } from "blume/sources";
export default defineConfig({
content: {
sources: [
// Local docs at the site root
filesystem({ root: "docs" }),
// Remote MDX from a GitHub repo, mounted under /sdk
mdxRemote({
prefix: "sdk",
github: { owner: "acme", repo: "sdk", ref: "main", path: "docs" },
}),
],
},
});
filesystem() के अलावा, हर बिल्ट-इन एडैप्टर का अपना पेज है, और custom() किसी भी अन्य बैकएंड को जोड़ता है:
| एडैप्टर | क्या पढ़ता है | रनटाइम डिपेंडेंसी | एनवायरनमेंट वेरिएबल |
|---|---|---|---|
obsidian() |
कोई Obsidian वॉल्ट, उसी जगह | — | — |
mdxRemote() |
किसी GitHub रिपॉज़िटरी या किसी रॉ URL से .md/.mdx |
— | GITHUB_TOKEN (प्राइवेट रिपॉज़िटरी) |
githubReleases() |
किसी रिपॉज़िटरी की रिलीज़, चेंजलॉग एंट्रियों के रूप में | — | GITHUB_TOKEN (प्राइवेट रिपॉज़िटरी) |
sanity() |
किसी Sanity डेटासेट पर एक GROQ क्वेरी | @sanity/client |
SANITY_TOKEN (प्राइवेट डेटासेट) |
notion() |
कोई Notion डेटाबेस | @notionhq/client |
NOTION_TOKEN |
contentful() |
कोई एक Contentful कंटेंट टाइप | — | CONTENTFUL_ACCESS_TOKEN |
payload() |
कोई Payload कलेक्शन | — | PAYLOAD_API_KEY |
strapi() |
कोई Strapi कंटेंट टाइप | — | STRAPI_API_TOKEN |
custom() |
कोई भी ContentSource जिसे आप लागू करते हैं |
— | — |
विकल्प ऑब्जेक्ट लेने वाला हर एडैप्टर दो साझा विकल्प स्वीकार करता है:
prefixस्रोत के रूट को/<prefix>/…के अंतर्गत नेमस्पेस करता है, और यही डायग्नोस्टिक्स में स्रोत का नाम तथा उसकी कैश डायरेक्टरी भी बन जाता है। अगर दो स्रोत एक ही रूट पर पहुँचते हैं, तो Blume एकBLUME_DUPLICATE_ROUTEबिल्ड एरर रिपोर्ट करता है — हर स्रोत को एक अलगprefixदें।pollInterval(सेकंड में) डेव में किसी रिमोट स्रोत को उस अंतराल पर फिर से फ़ेच करवाता है, और तभी रीलोड करता है जब कंटेंट वास्तव में बदलता है। एक बार फ़ेच करके सेशन के लिए फ़्रीज़ करने के लिए इसे अनसेट छोड़ दें। लोकल स्रोत (filesystem(),obsidian()) इसके बजाय फ़ाइलसिस्टम पर नज़र रखते हैं और इसे अनदेखा करते हैं।
किसी एडैप्टर का डिस्क्रिप्टर यह भी घोषित करता है कि उसे किस SDK की ज़रूरत है और वह कौन-से एनवायरनमेंट वेरिएबल पढ़ता है, इसलिए जेनरेट किया गया प्रोजेक्ट उस पैकेज को घोषित करता है, कोई वेरिएबल अनसेट होने पर blume dev, blume build और blume doctor चेतावनी देते हैं, और blume doctor कॉन्फ़िगर किए गए स्रोतों की सूची दिखाता है। यह चेतावनी किसी भी स्रोत के फ़ेच होने से पहले प्रिंट होती है, ताकि बाद में फ़ेच विफल होने पर यह खो न जाए। notion() और contentful() अपने टोकन के बिना कुछ भी नहीं पढ़ सकते, इसलिए टोकन अनसेट होने पर वे अपने पहले अनुरोध से पहले ही BLUME_MISSING_SECRET एरर के साथ रुक जाते हैं, और जिस स्रोत का SDK इंस्टॉल नहीं है, वह भी इसी तरह BLUME_SOURCE_SDK_MISSING के साथ रुक जाता है; दोनों ही स्थितियों में, कैश किया गया स्नैपशॉट मौजूद होने पर स्रोत इसके बजाय वही स्नैपशॉट परोसता है। कॉन्फ़िग लोड होते समय विकल्पों की पुष्टि की जाती है: कोई छूटा हुआ आवश्यक विकल्प, कोई अज्ञात कुंजी, या 1.x का बचा हुआ कोई { type: "…" } ऑब्जेक्ट एक ऐसे संदेश के साथ विफल होता है जो सुधार बताता है।
एकल filesystem() स्रोत जेनरेट किए गए डॉक्स कलेक्शन को अपनी ही डायरेक्टरी पर रूट करता है। कई फ़ाइलसिस्टम स्रोतों को एक ही रूट डायरेक्टरी साझा करनी चाहिए और उसे include ग्लॉब से विभाजित करना चाहिए — कहीं और रूट किया गया दूसरा स्रोत BLUME_ENTRY_ID_MISMATCH के रूप में रिपोर्ट किया जाता है, ताकि उसके पेज चुपचाप 404 न हों।
कैशिंग और ऑफ़लाइन बिल्ड
हर रिमोट स्रोत .blume/cache/<source>/ के अंतर्गत एक स्नैपशॉट रखता है। अगर कोई फ़ेच विफल हो जाता है — कोई नेटवर्क गड़बड़ी या CMS आउटेज — तो Blume बिल्ड को विफल करने के बजाय चेतावनी के साथ आखिरी ज्ञात-अच्छा स्नैपशॉट परोसता है। प्रीव्यू और प्रकाशित कंटेंट को अलग-अलग स्नैपशॉट मिलते हैं, और स्रोत विकल्पों के हर सेट को भी, इसलिए कोई बिल्ड कभी भी --preview के तहत फ़ेच किए गए ड्राफ़्ट पर वापस नहीं जाता, और किसी स्रोत की query या fields संपादित करने पर वह नए सिरे से फ़ेच होता है। custom() स्रोत इसका अपवाद है: उसका स्नैपशॉट केवल प्रीव्यू मोड के अनुसार अलग रखा जाता है, इसलिए उसके विकल्प संपादित करने के बाद blume sync चलाएँ। कैश .blume/ के अंदर रहता है और फिर से जेनरेट होता है, कभी कमिट नहीं किया जाता।
डेव में, किसी रिमोट स्रोत का स्नैपशॉट मौजूद होने पर उसे उसी स्नैपशॉट से परोसा जाता है, इसलिए डेव सर्वर को पुनः आरंभ करने से वह फिर से फ़ेच नहीं होता। नवीनतम कंटेंट खींचने के लिए blume sync चलाएँ (चल रहा डेव सर्वर हॉट-रीलोड करता है), या पहले स्नैपशॉट हटाने के लिए blume sync --force चलाएँ। लोकल फ़ाइलसिस्टम स्रोत हमेशा की तरह हॉट-रीलोड होते हैं। इसके बजाय किसी रिमोट स्रोत में बदलावों के लिए पोल करने के लिए, उस पर साझा pollInterval विकल्प (सेकंड में) सेट करें — डेव सर्वर उस अंतराल पर फिर से फ़ेच करता है और तभी रीलोड करता है जब कंटेंट वास्तव में बदलता है। काम करते समय API पर बार-बार अनुरोध भेजने से बचने के लिए इसे अनसेट छोड़ दें।
प्रीव्यू और सिंक
दो फ़्लैग यह नियंत्रित करते हैं कि रिमोट कंटेंट कैसे फ़ेच किया जाता है और क्या-क्या शामिल होता है:
--preview—blume devयाblume buildपर यह ड्राफ़्ट रेंडर करता है और अप्रकाशित CMS कंटेंट खींचता है — Sanity अपनेpreviewDraftsपरिप्रेक्ष्य पर स्विच कर जाता है, Contentful Preview API के ज़रिए पढ़ता है, और Payload तथा Strapi ड्राफ़्ट का अनुरोध करते हैं। Notion हमेशा हर पेज पढ़ता है और जिन पेजों काStatusप्रकाशित नहीं है, उन्हें ड्राफ़्ट के रूप में स्टेज करता है, इसलिएblume devउन्हें फ़्लैग के साथ या उसके बिना दिखाता है, औरblume build --previewउन्हें रेंडर करता है। इस फ़्लैग के बिना प्रोडक्शन बिल्ड हमेशा की तरह ड्राफ़्ट को बाहर रखते हैं, इसलिए प्रीव्यू बिल्ड अप्रकाशित काम को शिप होने से पहले समीक्षा करने का एक सुरक्षित तरीका है।blume syncहर रिमोट स्रोत को फिर से फ़ेच करता है और रनटाइम को दोबारा जेनरेट करता है। डेव कैश-फ़र्स्ट है — कोई रिमोट स्रोत एक बार फ़ेच किया जाता है और पुनः आरंभ पर.blume/cacheसे परोसा जाता है (तेज़ और ऑफ़लाइन-सहिष्णु), इसलिएblume syncवह तरीका है जिससे आप डेव सर्वर को पुनः आरंभ किए बिना नवीनतम CMS कंटेंट खींचते हैं (चल रहा सर्वर हॉट-रीलोड करता है)। पहले कैश हटाने के लिए--forceजोड़ें, या अपने आप रीफ़्रेश करने के लिए किसी स्रोत परpollIntervalसेट करें।
blume dev --preview # author workflow: see drafts live
blume build --preview # render a full preview build
blume sync # refresh remote content now
blume sync --force # ...ignoring any cached snapshot
रेंडरिंग और एस्केपिंग
एक स्रोत अपने नेटिव आकार (Portable Text, Notion ब्लॉक, रिमोट HTML) को Markdown/MDX टेक्स्ट में नॉर्मलाइज़ कर देता है, इसलिए पेज चाहे कहीं से भी आए, वही कंपोनेंट और मार्कडाउन फ़ीचर लागू होते हैं। बिल्ट-इन एडैप्टर रिच टेक्स्ट को उतारते समय उसे एस्केप करते हैं, इसलिए किसी लेखक ने CMS में जो टाइप किया — कोई {, कोई <b>, import से शुरू होने वाला कोई पैराग्राफ़, या © — वह वैसा ही रेंडर होता है जैसा लिखा गया है। लिंक केवल http(s), mailto:, tel: और सापेक्ष लक्ष्य बनाए रखते हैं; कोई भी अन्य स्कीम (javascript:, data:) लिंक के टेक्स्ट के रूप में रेंडर होती है, और कोई स्रोत जो SVG इमेज डाउनलोड करता है, उन्हें सैंडबॉक्स करके परोसा जाता है। githubReleases() के रिलीज़ नोट्स और mdxRemote() की फ़ाइलों को आपका अपना कंटेंट माना जाता है: उनका रॉ HTML वैसा ही रेंडर होता है जैसा लिखा गया है, इसलिए उन्हें केवल उन्हीं रिपॉज़िटरी की ओर इंगित करें जिन पर आप भरोसा करते हैं।