2026 में स्क्रैच से एक कस्टम ब्लॉग बनाना एक सोची-समझी पसंद है। अधिकांश लेखक बस एक होस्टेड प्लेटफॉर्म चुनते हैं और आगे बढ़ जाते हैं। मैंने अपने टेक ब्लॉग को Astro के साथ फिर से बनाने का फैसला किया क्योंकि मैं स्टैक की हर परत का स्वामित्व चाहता था और उन पैटर्न्स को सीखना चाहता था जो वास्तव में एक स्टैटिक साइट को केवल अलग ही नहीं, बल्कि तेज़ भी बनाते हैं। इसका परिणाम एक द्विभाषी साइट है जो जापानी और अंग्रेजी सामग्री प्रदान करती है, डिफ़ॉल्ट रूप से ज़ीरो जावास्क्रिप्ट (zero JavaScript) भेजती है, और हर जटिलता को विज़िटर के ब्राउज़र के बजाय मेरी मशीन पर रखती है।

यहाँ वे पाँच पैटर्न्स दिए गए हैं जिन्होंने इसे सफल बनाया।

Zod के साथ Content Collections

Astro के Content Collections केवल Markdown फाइलों को फोल्डर्स में व्यवस्थित करने से कहीं अधिक करते हैं। वे आपकी सामग्री और आपके कोड के बीच एक अनुबंध (contract) लागू करते हैं। मैंने प्रत्येक लेख संग्रह (article collection) के साथ एक Zod स्कीमा जोड़ा, जिसका अर्थ है कि बिल्ड स्टेप एक भी पेज रेंडर होने से पहले frontmatter को वैलिडेट करता है।

स्कीमा में एक language फ़ील्ड की आवश्यकता होती है जो केवल दो मान स्वीकार करता है: ja या en| पाठक को कौन सी भाषा मिलेगी, इस बारे में कोई अस्पष्टता नहीं है। मैंने एक pair फ़ील्ड भी जोड़ा जो अनुवादों को एक साथ जोड़ता है। यदि मैं जापानी में Astro के बारे में एक पोस्ट प्रकाशित करता हूँ और बाद में उसका अंग्रेजी में अनुवाद करता हूँ, तो दोनों फ़ाइलें एक ही pair ID साझा करती हैं। इससे भाषा बदलने वाला स्विच (language switcher) बनाना बहुत आसान हो जाता है क्योंकि संबंध डेटा में स्पष्ट है, न कि फ़ाइल नामों से निकाला गया है।

तारीखें Markdown frontmatter से स्ट्रिंग्स के रूप में आती हैं, इसलिए स्कीमा उन्हें स्वचालित रूप से वास्तविक Date ऑब्जेक्ट्स में बदल देता है। इससे मेरे पेज टेम्पलेट्स के अंदर स्ट्रिंग-मैंगलिंग (string-mangling) लॉजिक खत्म हो जाता है। हालाँकि, सबसे महत्वपूर्ण लाभ इसका फेलियर मोड (failure mode) है। यदि किसी फ़ाइल में कोई आवश्यक फ़ील्ड गायब है या कोई अमान्य भाषा कोड उपयोग किया गया है, तो बिल्ड तुरंत एक स्पष्ट त्रुटि (error) के साथ क्रैश हो जाता है। मैं इसे डिप्लॉयमेंट के बाद टूटे हुए लेआउट या साइलेंट 404 खोजने के बजाय अपने टर्मिनल में ठीक कर लेता हूँ।

Article Conversion Pipeline

मैंने पहले दिन से ही हर पोस्ट इस नए फॉर्मेट में नहीं लिखी थी। वर्षों की सामग्री Zenn और Dev.to पर मौजूद थी, जिनमें से प्रत्येक प्लेटफॉर्म की अपनी खूबियाँ और प्रोप्रायटरी सिंटैक्स (proprietary syntax) थे। कॉपी-पेस्ट करने और हाथ से ठीक करने के बजाय, मैंने एक TypeScript स्क्रिप्ट लिखी जो लेखों के पूरे बैच को मानक Markdown में बदल देती है।

Zenn टिप्स और चेतावनियों के लिए कस्टम कॉलआउट सिंटैक्स का उपयोग करता है। मेरी स्क्रिप्ट उन्हें सिमेंटिक HTML aside टैग में बदल देती है ताकि वे साइट पर लगातार रेंडर हों। Dev.to एम्बेड और विशेष ब्लॉक्स के लिए Liquid टैग पर निर्भर करता है। पाइपलाइन उन्हें साधारण Markdown लिंक में अनुवादित करती है जो कहीं भी काम करते हैं।

कुछ पोस्ट में ऐसे एसाइड्स (asides) होते हैं जो केवल मूल प्लेटफॉर्म के लिए होते हैं, जैसे Medium पेवॉल के बारे में डिस्क्लेमर या Zenn-विशिष्ट इमेज पाथ। मैं उन्हें HTML कमेंट्स में लपेट देता हूँ ताकि कन्वर्टर माइग्रेशन के दौरान उन्हें हटा सके। स्क्रिप्ट फ़ाइलों को लाइन दर लाइन प्रोसेस करती है, लेकिन यह कोड की सीमाओं का सम्मान करती है। जब यह एक fenced code block का पता लगाती है, तो यह ट्रांसफ़ॉर्मेशन नियमों को पूरी तरह से छोड़ देती है। सिंटैक्स सैंपल को खराब करना एक टेक ब्लॉग के पूरे उद्देश्य को कमजोर कर देगा, इसलिए लाइन-दर-लाइन पार्सर कोड ब्लॉक्स को अछूत ज़ोन (untouchable zones) के रूप में मानता है।

अब एक कमांड चलाने से बिना किसी लिंक या कॉलआउट को तोड़े वर्षों का लेखन फिर से प्रकाशित हो जाता है।

Build-Time OGP Image Generation

सोशल शेयरिंग इमेज आमतौर पर बाद के विचार (afterthought) होती हैं। या तो आप उन्हें मैन्युअल रूप से डिज़ाइन करते हैं या एक भारी रनटाइम सर्विस इंस्टॉल करते हैं जो मांग पर कार्ड जेनरेट करती है। मुझे दोनों ही नहीं चाहिए थे। इस साइट पर प्रत्येक Open Graph इमेज बिल्ड के दौरान बनाई जाती है ताकि विज़िटर्स को एक स्टैटिक PNG की ओर इशारा करने वाले एक हल्के img टैग के अलावा और कुछ न मिले।

मैं Satori का उपयोग करता हूँ, जो JSX मार्कअप लेता है और उसे SVG में रेंडर करता है। आउटपुट स्पष्ट, अनुमानित और टेम्पलेट बनाने में आसान है। असली ऑप्टिमाइज़ेशन फ़ॉन्ट हैंडलिंग से आया। एक पूरा जापानी वेब फ़ॉन्ट आसानी से पांच मेगाबाइट से ऊपर जा सकता है। उसे बिल्ड के दौरान लोड करना, ब्राउज़र से उसे लाने के लिए कहना तो दूर की बात है, बेतुका होगा।

इसके बजाय, मैं Google Fonts subsetting का उपयोग करता हूँ। स्क्रिप्ट किसी दिए गए पोस्ट के शीर्षक टेक्स्ट का निरीक्षण करती है और केवल उस स्ट्रिंग को रेंडर करने के लिए आवश्यक सटीक ग्लिफ़ सेट (glyph set) का अनुरोध करती है। यदि कोई हेडलाइन चालीस अद्वितीय जापानी वर्णों का उपयोग करती है, तो केवल वे चालीस वर्ण ही नेटवर्क पर यात्रा करते हैं। बिल्ड तेज़ रहता है, और रेंडर की गई इमेज में कभी भी टूटे हुए टोफू ब्लॉक्स (tofu blocks) नहीं दिखते क्योंकि सबसेट सटीक है। रनटाइम की किसी भी अनिश्चितता के लिए कुछ भी नहीं छोड़ा गया है।

Tailwind Tokens के माध्यम से Dark Mode

मैंने हर एलिमेंट को dark: यूटिलिटी क्लासेस से सजाने से इनकार कर दिया। वह दृष्टिकोण खराब तरीके से स्केल करता है और आपके मार्कअप को शोर (noise) से भर देता है। मैंने स्वयं कलर टोकन को फिर से परिभाषित किया ताकि सक्रिय थीम के आधार पर एक ही क्लास नाम अलग-अलग मानों (values) को हल करे।

मैं हर सरफेस और टेक्स्ट कलर के लिए CSS custom properties का उपयोग करता हूँ। लाइट मोड में, --color-white #ffffff से मैप होता है। डार्क मोड में, वही वेरिएबल नाम एक लगभग काले (near-black) मान की ओर इशारा करता है। मेरा HTML पूरी तरह से तटस्थ (agnostic) रहता है। एक कार्ड दिन के समय की परवाह किए बिना bg-ui-surface और text-ui-primary का उपयोग कर सकता है। थीम स्विच रूट पर वेरिएबल डेफिनिशन को बदल देता है, और पूरा इंटरफ़ेस तुरंत प्रतिक्रिया देता है।

इस दृष्टिकोण के साथ एक जोखिम stylesheets लोड होने से पहले लाइट कंटेंट का फ्लैश (झलक) दिखना है। मैंने इसे डॉक्यूमेंट head में एक छोटे से inline script के साथ हल किया है। यह पहले पेंट (first paint) से पहले चलता है, localStorage और सिस्टम प्रेफरेंस की जांच करता है, और तुरंत सही data attribute सेट कर देता है। क्योंकि स्क्रिप्ट रेंडर को केवल कुछ मिलीसेकंड के लिए रोकती है, इसलिए विज़िटर को डार्क मोड शुरू होने से पहले कभी भी कोई परेशान करने वाला सफेद चमक (white burst) नहीं दिखता।

Island Architecture और Zero-JS

Astro का मूल सिद्धांत यह है कि एक पेज को static HTML के रूप में शुरू होना चाहिए। JavaScript तभी आता है जब किसी इंटरैक्शन की वास्तव में आवश्यकता होती है। मैंने इसे गंभीरता से लिया।

मैंने ग्लोबल मेनू और थीम टॉगल के लिए React का उपयोग करने से परहेज किया। दोनों को vanilla JavaScript की एक छोटी मात्रा के साथ संभाला जाता है जो एक ही मॉड्यूल में रहती है। इसमें कोई hydration overhead, कोई virtual DOM diffing, और डाउनलोड करने के लिए कोई framework runtime नहीं है।

एकमात्र भारी लाइब्रेरी जिसका मैं उपयोग करता हूँ, वह टेक्स्ट से डायग्राम रेंडर करने के लिए Mermaid.js है। इसे ग्लोबली इम्पोर्ट करने के बजाय, मैंने इसे एक Intersection Observer के अंदर रैप (wrap) कर दिया है। ऑब्जर्वर डायग्राम कंटेनर्स पर नज़र रखता है। जब कोई यूजर किसी एक के कुछ सौ पिक्सेल के भीतर स्क्रॉल करता है, तो स्क्रिप्ट डायनामिक रूप से Mermaid मॉड्यूल को इंजेक्ट करती है और डायग्राम रेंडर करती है। यदि किसी पोस्ट में कोई डायग्राम नहीं है, तो वह लाइब्रेरी कभी नेटवर्क को टच नहीं करती। शुरुआती पेज लोड हल्का रहता है, और ब्राउज़र केवल उसी के लिए संसाधन खर्च करता है जो पाठक वास्तव में देखता है।

Build-First माइंडसेट

हर पैटर्न में चलने वाला सूत्र सीधा है: यदि आप बिल्ड के दौरान काम कर सकते हैं, तो उसे वहीं करें। साइट डिप्लॉय होने से पहले Zod के साथ अपने डेटा को वैलिडेट करें। रिक्वेस्ट टाइम के बजाय समय से पहले ही प्रोप्रायटरी प्लेटफॉर्म सिंटैक्स को कन्वर्ट करें। सर्वर चलाने के बजाय सोशल इमेज को स्टैटिक फाइलों में रेंडर करें। हर क्लाइंट को लॉजिक भेजने के बजाय टोकन के माध्यम से थीम रंगों को हल करें। भारी JavaScript को तब तक टाल दें जब तक उपयोगकर्ता को वास्तव में इसकी आवश्यकता न हो।

जटिलता को बिल्ड स्टेप की ओर धकेलने से रनटाइम प्रेडिक्टेबल, पेलोड छोटा और मेंटेनेंस का बोझ प्रबंधनीय रहता है। साइट किसी एक ट्रिक की वजह से तेज़ नहीं रहती, बल्कि इसलिए रहती है क्योंकि विज़िटर के ब्राउज़र के अंदर बहुत कम चीज़ें हो रही होती हैं। 2026 में एक स्टैटिक आर्किटेक्चर चुनने का असली लाभ यही है।