२०२६ मध्ये शून्यातून स्वतःचा कस्टम ब्लॉग तयार करणे हा एक जाणीवपूर्वक घेतलेला निर्णय आहे. बहुतेक लेखक फक्त एखादे होस्टेड प्लॅटफॉर्म निवडतात आणि पुढे जातात. मी माझा टेक ब्लॉग Astro वापरून पुन्हा तयार करण्याचे ठरवले कारण मला स्टॅकच्या प्रत्येक थरावरील नियंत्रण हवे होते आणि अशा पॅटर्नबद्दल शिकायचे होते जे केवळ वेगळे नसून स्टॅटिक साइटला खरोखर वेगवान बनवतात. याचा परिणाम म्हणजे एक द्विभाषिक साइट आहे जी जपानी आणि इंग्रजी मजकूर प्रदान करते, बाय डिफॉल्ट शून्य JavaScript पाठवते आणि प्रत्येक गुंतागुंत व्हिजिटरच्या ब्राउझरऐवजी माझ्या मशीनवर ठेवते.
येथे पाच पॅटर्न आहेत ज्यांनी हे शक्य केले.
Zod सह Content Collections
Astro चे Content Collections केवळ Markdown फाइल्स फोल्डर्समध्ये आयोजित करण्यापेक्षा अधिक काम करतात. ते तुमच्या मजकूर (content) आणि तुमच्या कोडमध्ये एक करार (contract) लागू करतात. मी प्रत्येक आर्टिकल कलेक्शनला Zod schema जोडला आहे, ज्याचा अर्थ असा की एकही पेज रेंडर होण्यापूर्वी बिल्ड स्टेप फ्रंटमॅटरची (frontmatter) पडताळणी करते.
या schema मध्ये language फील्ड आवश्यक आहे जे केवळ दोन व्हॅल्यूज स्वीकारते: ja किंवा en. वाचक कोणत्या भाषेत मजकूर वाचणार आहे याबाबत कोणतीही संदिग्धता राहत नाही. मी pair नावाचे एक फील्ड देखील जोडले आहे जे भाषांतरांना एकमेकांशी जोडते. जर मी जपानी भाषेत Astro बद्दलचा पोस्ट प्रकाशित केला आणि नंतर त्याचे इंग्रजीमध्ये भाषांतर केले, तर दोन्ही फाइल्स एकाच pair ID शेअर करतात. यामुळे लँग्वेज स्विचर (language switcher) तयार करणे अत्यंत सोपे होते कारण संबंध डेटा मध्ये स्पष्ट असतो, फाईल नावावरून काढलेला निष्कर्ष नसतो.
तारखा Markdown frontmatter मधून स्ट्रिंग (strings) म्हणून येतात, त्यामुळे schema त्यांना आपोआप खऱ्या Date ऑब्जेक्ट्समध्ये रूपांतरित करते. यामुळे माझ्या पेज टेम्पलेट्समधील स्ट्रिंग-मॅंगलिंग (string-mangling) लॉजिकची गरज उरत नाही. तथापि, सर्वात महत्त्वाचा फायदा म्हणजे 'फेल्युअर मोड' (failure mode). जर एखादी फाईल आवश्यक फील्ड विसरली असेल किंवा अवैध भाषा कोड वापरत असेल, तर बिल्ड लगेच स्पष्ट त्रुटीसह (error) थांबते. डेप्लॉयमेंटनंतर तुटलेले लेआउट किंवा 'सायलेंट 404' शोधण्याऐवजी मी ते माझ्या टर्मिनलमध्येच दुरुस्त करू शकतो.
आर्टिकल कन्व्हर्जन पाईपलाईन (Article Conversion Pipeline)
मी पहिल्या दिवसापासून प्रत्येक पोस्ट या नवीन फॉरमॅटमध्ये लिहिली नाही. अनेक वर्षांचा मजकूर Zenn आणि Dev.to वर होता, ज्या प्रत्येक प्लॅटफॉर्मची स्वतःची वैशिष्ट्ये आणि खास सिंटॅक्स (syntax) होते. कॉपी-पेस्ट करून हाताने दुरुस्त करण्याऐवजी, मी एक TypeScript स्क्रिप्ट लिहिली जी लेखांचे संपूर्ण बॅचेस प्रमाणित Markdown मध्ये रूपांतरित करते.
Zenn टिप्स आणि वॉर्निंगसाठी कस्टम कॉलआउट सिंटॅक्स वापरते. माझी स्क्रिप्ट त्यामध्ये aside HTML टॅग्स वापरते जेणेकरून ते संपूर्ण साइटवर सुसंगत दिसतील. Dev.to एम्बेड्स आणि विशेष ब्लॉक्ससाठी Liquid टॅग्सवर अवलंबून आहे. ही पाईपलाईन त्यांचे साध्या Markdown लिंक्समध्ये रूपांतर करते जे कुठेही काम करतात.
काही पोस्टमध्ये मूळ प्लॅटफॉर्मसाठीच असलेले काही भाग असतात, जसे की Medium पेवॉलबद्दल डिस्क्लेमर किंवा Zenn-विशिष्ट इमेज पाथ. मी ते HTML कमेंट्समध्ये गुंडाळतो जेणेकरून मायग्रेशन दरम्यान कन्व्हर्टर ते काढून टाकू शकेल. स्क्रिप्ट फाईल्स ओळ दर ओळ (line by line) प्रोसेस करते, परंतु ती कोडच्या सीमांचा आदर करते. जेव्हा ती एखादा 'fenced code block' शोधते, तेव्हा ती ट्रान्सफॉर्मेशनचे नियम पूर्णपणे वगळते. तांत्रिक ब्लॉगचा उद्देशच धोक्यात येईल जर सिंटॅक्स सॅम्पल खराब झाले, म्हणून लाइन-बाय-लाइन पार्सर कोड ब्लॉक्सना 'अस्पर्शनीय क्षेत्र' (untouchable zones) म्हणून मानतो.
आता एक कमांड चालवल्यास एकही लिंक किंवा कॉलआउट न मोडता अनेक वर्षांचे लेखन पुन्हा प्रकाशित होते.
बिल्ड-टाइम OGP इमेज जनरेशन
सोशल शेअरिंग इमेजेसकडे सहसा दुर्लक्ष केले जाते. एकतर तुम्ही त्या मॅन्युअली डिझाइन करता किंवा कार्ड्स तयार करण्यासाठी एखादी जड रनटाइम सर्व्हिस इन्स्टॉल करता. मला या दोन्ही गोष्टी नको होत्या. या साइटवरील प्रत्येक Open Graph इमेज बिल्ड दरम्यान तयार केली जाते जेणेकरून व्हिजिटर्सना केवळ स्टॅटिक PNG कडे निर्देश करणारा एक हलका img टॅग मिळेल.
मी Satori वापरतो, जे JSX मार्कअप घेते आणि त्याचे SVG मध्ये रूपांतर करते. आउटपुट स्पष्ट, अंदाजित आणि टेम्प्लेटिंगसाठी सोपे असते. खरी ऑप्टिमायझेशन फॉन्ट हाताळणीतून आली. एक पूर्ण जपानी वेब फॉन्ट सहज पाच मेगाबाइटपेक्षा जास्त असू शकतो. तो बिल्ड दरम्यान लोड करणे, ब्राउझरला तो फेच करायला सांगणे, हे अवास्तव ठरेल.
त्याऐवजी, मी Google Fonts subsetting वापरतो. स्क्रिप्ट एखाद्या पोस्टसाठी शीर्षक मजकूर तपासते आणि तो स्ट्रिंग रेंडर करण्यासाठी आवश्यक असलेल्या नेमक्या ग्लिफ सेटची (glyph set) मागणी करते. जर हेडलाईनमध्ये चाळीस अद्वितीय जपानी अक्षरे असतील, तर केवळ ती चाळीस अक्षरेच ट्रान्सफर केली जातात. बिल्ड वेगवान राहते आणि रेंडर केलेली इमेज कधीही तुटलेले 'टोफू ब्लॉक्स' (tofu blocks) दाखवत नाही कारण सबसेट अचूक असतो. रनटाइमच्या योगायोगावर काहीही सोडले जात नाही.
Tailwind Tokens द्वारे डार्क मोड
मी प्रत्येक एलिमेंटला dark: युटिलिटी क्लासेसने सजवण्यास नकार दिला. हा दृष्टिकोन मोठ्या प्रमाणावर वापरताना कठीण जातो आणि तुमच्या मार्कअपमध्ये अनावश्यक गोंधळ निर्माण करतो. मी स्वतः कलर टोकन्स पुन्हा परिभाषित केले जेणेकरून सक्रिय थीमवर अवलंबून एकच क्लास नेम वेगवेगळ्या व्हॅल्यूज रिझॉल्व्ह करेल.
मी प्रत्येक सरफेस आणि टेक्स्ट कलरसाठी CSS custom properties वापरतो. लाईट मोडमध्ये, --color-white हे #ffffff ला मॅप होते. डार्क मोडमध्ये, तोच व्हेरिएबल नेम जवळजवळ काळ्या रंगाच्या व्हॅल्यूकडे निर्देश करतो. माझे HTML या गोष्टीपासून पूर्णपणे स्वतंत्र राहते. दिवसाची वेळ काहीही असो, एखादे कार्ड bg-ui-surface आणि text-ui-primary वापरू शकते. थीम स्विच केल्यावर रूटवर (root) व्हेरिएबल डेफिनिशन्स बदलतात आणि संपूर्ण इंटरफेस त्वरित प्रतिसाद देतो.
या पद्धतीमधील एक धोका म्हणजे स्टाईलशीट्स लोड होण्यापूर्वी लाईट कंटेंटचा फ्लॅश दिसणे. मी हे डॉक्युमेंट head मध्ये एका लहान इनलाइन स्क्रिप्टद्वारे सोडवले आहे. ही स्क्रिप्ट पहिल्या पेंट (first paint) पूर्वी चालते, localStorage आणि सिस्टम प्रेफरन्स तपासते आणि लगेच योग्य डेटा ॲट्रिब्युट सेट करते. ही स्क्रिप्ट रेंडरिंगला फक्त काही मिलीसेकंद थांबवते, त्यामुळे डार्क मोड सुरू होण्यापूर्वी व्हिजिटरला कोणताही त्रासदायक पांढरा प्रकाश दिसत नाही.
Island Architecture आणि Zero-JS
Astro चा मुख्य आधार असा आहे की पेजची सुरुवात स्टॅटिक HTML म्हणून झाली पाहिजे. जेव्हा एखाद्या इंटरअॅक्शनची खरोखर गरज असते, तेव्हाच JavaScript वापरले जाते. मी हे गांभीर्याने घेतले.
मी ग्लोबल मेनू आणि थीम टॉगलसाठी React टाळले. या दोन्ही गोष्टी एका सिंगल मॉड्यूलमध्ये असलेल्या थोड्या प्रमाणात vanilla JavaScript द्वारे हाताळल्या जातात. यामध्ये कोणताही hydration overhead, no virtual DOM diffing किंवा डाउनलोड करण्यासाठी कोणताही framework runtime नाही.
मी वापरत असलेली एकमेव जड लायब्ररी म्हणजे मजकुरातून डायग्राम रेंडर करण्यासाठी Mermaid.js. ती ग्लोबलरी इंपोर्ट करण्याऐवजी, मी तिला Intersection Observer मध्ये गुंडाळले आहे. ऑब्झर्व्हर डायग्राम कंटेनर्सवर लक्ष ठेवतो. जेव्हा वापरकर्ता एखाद्या डायग्रामच्या काही शेकडो पिक्सेलच्या आत स्क्रोल करतो, तेव्हा स्क्रिप्ट डायनॅमिकली Mermaid मॉड्यूल इंजेक्ट करते आणि डायग्राम रेंडर करते. जर पोस्टमध्ये कोणतेही डायग्राम नसतील, तर ती लायब्ररी नेटवर्कला स्पर्शही करत नाही. सुरुवातीचा पेज लोड हलका राहतो आणि वाचक प्रत्यक्षात जे पाहतो, त्यासाठीच ब्राउझर रिसोर्सेस खर्च करतो.
Build-First मानसिकता
प्रत्येक पॅटर्नमधून जाणारा धागा सरळ आहे: जर तुम्ही बिल्ड दरम्यान काम करू शकत असाल, तर ते तिथेच करा. साइट डिप्लॉय करण्यापूर्वी Zod वापरून तुमचा डेटा व्हॅलिडेट करा. रिक्वेस्ट टाइमऐवजी आधीच प्रोप्रायटरी प्लॅटफॉर्म सिंटॅक्स कन्व्हर्ट करा. सर्व्हर सुरू करण्याऐवजी सोशल इमेजेस स्टॅटिक फाइल्समध्ये रेंडर करा. प्रत्येक क्लायंटला लॉजिक पाठवण्याऐवजी टोकन्सद्वारे थीम कलर्स रिझॉल्व्ह करा. वापरकर्त्याला खरोखर गरज असेल तोपर्यंत जड JavaScript ला पुढे ढकला.
गुंतागुंत बिल्ड स्टेपमध्ये हलवल्यामुळे रनटाइम प्रेडिक्टेबल, पेलोड लहान आणि मेंटेनन्सचा भार व्यवस्थापित करण्यायोग्य राहतो. साइट कोणत्याही एका ट्रिकमुळे नाही, तर व्हिजिटरच्या ब्राउझरमध्ये कमीत कमी गोष्टी घडत असल्यामुळे वेगवान राहते. 2026 मध्ये स्टॅटिक आर्किटेक्चर निवडण्याचे खरे फळ हेच आहे.
