3 पॉइंट द्वारा GN⁺ 2023-09-11 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Static site को host करना आसान और तेज़ होता है, और maintenance भी कम चाहिए; इसलिए अगर साइट सरल है तो अलग builder सीखे बिना Makefile की कुछ पंक्तियों से ही काम चल सकता है
  • मुख्य संरचना यह है कि source में मौजूद file layout को बनाए रखते हुए HTML में header.html जोड़ा जाए, और बाकी files को जैसा है वैसा copy करके build में रखा जाए
  • make build में find source -type f और patsubst से input और output files को match किया जाता है, और .html तथा अन्य files पर अलग-अलग make rules लागू होते हैं
  • current page highlight करना, Markdown conversion, local server, change detection पर rebuild, और GitHub Pages deployment जैसी चीज़ें ज़रूरत पड़ने पर additional targets के रूप में जोड़ी जा सकती हैं
  • Dependencies कम होने और बदलने की जगह साफ़ दिखने की वजह से, छोटे requirements वाली sites में generic generator की तुलना में खुद बनाया गया build flow ज़्यादा तेज़ हो सकता है

सिर्फ Makefile से बनने वाली basic static site

  • Static site generator का output host करना आसान होता है, तेज़ चलता है, और maintenance का बोझ बहुत कम होता है
  • अगर साइट सरल है, तो existing site builder को सीखने और उसके हिसाब से ढलने के बजाय खुद script लिखना ज़्यादा तेज़ और संतोषजनक हो सकता है
  • अगर यह auto-updating timestamp या RSS feed के बिना एक साधारण site है, तो blog scripts से भी ज़्यादा सरल setup काफ़ी है
  • बुनियादी आवश्यकताएँ

    • सभी input files source directory में रखी जाती हैं, और output में भी वही directory structure बनाए रखा जाता है
    • सभी HTML files की शुरुआत में header.html जोड़ा जाता है
    • HTML के अलावा बाकी files को बिना बदलाव build directory में copy किया जाता है
  • Makefile rules

    • build target की dependency ऐसी होती है कि source के नीचे मौजूद सभी files, build के नीचे corresponding output files से map हो जाएँ
    • इसका अपना कोई काम नहीं होता, लेकिन यह entry point की तरह काम करता है ताकि हर file पर सही rule लागू हो
    • build/%.html rule, source/%.html, header.html, Makefile पर depend करता है
    • mkdir -p $(dir $@) से output directory बनाई जाती है, और cat header.html $< > $@ से header और input HTML को जोड़कर output बनाया जाता है
    • build/% rule, HTML के अलावा बाकी files को cp $< $@ से जैसा है वैसा copy करता है
    • सिर्फ इस header.html और इन rules से make build चलाने पर ऐसा build directory बन जाता है जिसे local में खोला जा सकता है या web server पर upload किया जा सकता है

विस्तार के उदाहरण और helper targets

  • current page दिखाना

    • Navigation में current page को highlight करने से visitor एक नज़र में समझ सकता है कि वह साइट में कहाँ है
    • उदाहरण में navigation link को ढूँढकर उसमें current class जोड़ी जाती है
    • sed -E 's|(href="$(subst source,,$<))|class="current" \\1|' header.html | cat - $< > $@
    • असल replacement तरीका इस्तेमाल किए जा रहे markup structure के अनुसार बदलना चाहिए
  • Markdown से HTML बनाना

    • अगर आप सीधे HTML नहीं लिखना चाहते, या existing content Markdown format में है, तो Markdown-to-HTML converter को pipe में जोड़ा जा सकता है
    • उदाहरण में smu का उपयोग किया गया है
    • smu $< | cat header.html - > $@
    • Basic rule अब भी यह मानता है कि build/foo.html, source/foo.html से बनता है
    • Markdown files के लिए भी .html suffix बनाए रखना होगा, या input के रूप में .md files खोजने के लिए rule बदलना होगा
  • local preview

    • कुछ sites में browser में local files सीधे खोलने पर preview सही नहीं दिखता, और इसका आम कारण relative links की जगह absolute links का इस्तेमाल होना है
    • Python कई systems में पहले से installed होता है, और इस काम के लिए उपयुक्त web server भी साथ लाता है
    • serve target: python -m http.server -d build
  • बदलाव पर automatic rebuild

    • साइट पर काम करते समय हर बार manually फिर से build करना झंझट भरा होता है
    • entr का उपयोग करने पर source, header.html, Makefile में बदलाव होने पर make build अपने-आप चलाया जा सकता है
    • watch target: find source header.html Makefile | entr make build
    • अगर dependency से बचना हो, तो inotifywait का भी उपयोग किया जा सकता है
  • GitHub Pages deployment

    • अगर आपका repository GitHub पर है, तो generated HTML को GitHub Pages पर host करना स्वाभाविक विकल्प है
    • git की details से बचे रहते हुए deployment command को सही तरह सेट करना थोड़ा पेचीदा हो सकता है, लेकिन git worktree से यह किया जा सकता है
    • यह तरीका Sangsoo Nam की post पर आधारित है
    • gh-pages branch को public_html worktree के रूप में जोड़ा जाता है
    • build/* को public_html में copy किया जाता है
    • git add --all, git commit -m "Deploy to github pages", git push origin gh-pages चलाए जाते हैं
    • अंत में git worktree remove public_html से worktree हटा दी जाती है
  • वास्तविक उदाहरण

    • इस approach से बनी page karlb/astridbartel.de में देखी जा सकती है
    • पूरा static site generator Makefile की छह पंक्तियों से शुरू किया जा सकता है, और बिना किसी अजीब dependency या maintenance बोझ के ज़रूरत के हिसाब से तेज़ी से बदला जा सकता है

1 टिप्पणियां

 
GN⁺ 2023-09-11
Hacker News की रायें
  • मैंने पहले अपनी निजी वेबसाइट(https://pablo.rauzy.name/) एक साधारण Makefile से generate की थी
    बाद में इसमें news और RSS feeds, research papers और lecture materials की automatic listing, tags से filter की जा सकने वाली book list जैसी सुविधाएँ जोड़ीं। आज भी यह Makefile ही है, लेकिन Makefile खुद उल्टा थोड़ा सरल हो गया है; इसकी जगह HTML को line-by-line संभालने के लिए बेहतरीन xml2 और 2xml utilities इस्तेमाल करने वाली Bash scripts call करता है। मुख्य रूप से grep और sed जैसी core utilities का इस्तेमाल करता है
    इसके साथ कुछ git hooks भी लगाए हैं जो जरूरत पड़ने पर अपने-आप make call करते हैं, खासकर जिस remote server पर वेबसाइट host होती है, वहाँ repository में push करने पर public version फिर से build हो जाता है
    कई सालों से बहुत अच्छी तरह चल रहा है, और git history 2009 तक जाती है। शुरुआती commits देखकर पता चला कि वे beccad7 (FIRST_VERSION) Initial commit, d1cc6d7 adding link to Google Reader shared items, 6ccfd0c fix typo, d337959 adding link to Identi.ca account थे, और सचमुच 15 साल बीत चुके हैं
  • इस तरीके की समस्या यह है कि source/ से file delete करने पर भी वह build/ से delete नहीं होती
    मेरे projects में पूरा site फिर से build करना भी पर्याप्त तेज है, इसलिए मैंने rebuild से पहले पूरे build folder को delete करने का रास्ता चुना
    https://github.com/jez/jez.github.io/blob/source/Makefile#L1...
    इससे build system इस्तेमाल करने की बड़ी वजह, यानी incremental builds, काफी हद तक निष्प्रभावी हो जाती है, लेकिन फिर भी अगर आपको पता है कि कौन-सा page फिर से generate करना है, तो उस file को सीधे make कर सकते हैं
    Makefile में इस pattern के लिए कोई common workaround हो तो जानना चाहूँगा
    • पता नहीं यह common pattern है या नहीं, लेकिन मेरा solution हर बार “unexpected” files को delete करने वाला command चलाना था
      GNU Make के shell function से files list कीं, और filter-out function से “expected” outputs को filter कर दिया। यह देखने में भद्दा hack है, लेकिन shell function के जरिए variable expansion के हिस्से के रूप में command चलवाकर यह सुनिश्चित किया कि वह हर बार चले
      Makefile link: https://github.com/jaredkrinke/make-blog/blob/main/Makefile
    • File deletion और renaming कई version control/build systems में आम समस्या है
      make clean जैसे nuclear option के अलावा, deletion और renaming के लिए specific Make targets रखे जा सकते हैं। उदाहरण के लिए make rm sourcefile या make mv sourcefile newsourcefile को source और generated target, दोनों के delete/rename को साथ में handle करने जैसा बनाया जा सकता है
      असल में काफी बड़े blogs या online projects में भी make clean / make all cycle आम तौर पर काफी तेज होती है, और templates या site design elements ठीक करते समय अक्सर जरूरत पड़ती है। अगर rebuild time चिंता करने लायक scale का हो, तो शायद source को database में manage करके client access पर dynamically generate करने वाला असली CMS इस्तेमाल करना सही हो सकता है
    • make clean से काम नहीं चलेगा?
    • कुछ इस तरह हो सकता है
      rm/%.html:
      @rm -f source/%.html build/%.html
      इसे $ make rm/page.html से चलाएँ
    • General-purpose build system Shake में इसी मकसद के लिए prune feature है
      http://neilmitchell.blogspot.com/2015/04/cleaning-stale-file...
      लेकिन make में भी चलने वाला सबसे अच्छा समाधान मुझे यह लगता है कि final .tar.gz archive बनाने के लिए make dist target रखा जाए। Rules सही लिखे हों तो पुराने files उसमें शामिल नहीं होंगे। बड़े projects में यह slow हो सकता है, लेकिन development के दौरान वैसे भी इसका इस्तेमाल करने की जरूरत नहीं, सिर्फ release के समय करना होगा। Incremental build अब भी possible है, और सिर्फ आखिरी .tar.gz को scratch से बनाना होगा
  • इस article में बताए गए Karl के blog.sh shell script काम से मुझे सीधे inspiration मिली
    उसे लेकर modify करके मैंने अपना minimal static site generator barf बनाया। Karl ने अपना शानदार काम public न किया होता तो यह मौजूद नहीं होता
    [0]: https://github.com/karlb/karl.berlin/blob/master/blog.sh
    [1]: https://barf.bt.ht
    • लगता है हमारी पसंद मिलती है। मेरे वाले को मैं shite कहता हूँ, और इसी से अपनी site बनाता हूँ। नाम software quality की ओर इशारा करता है :)
      सबसे अच्छी बात यह है कि अब तक कुछ भी upgrade करने की जरूरत नहीं पड़ी, और आगे भी शायद नहीं पड़ेगी। दूसरी सबसे अच्छी बात यह है कि JavaScript के बिना hot reload मिलता है
      [1] https://github.com/adityaathalye/shite
      [2] https://evalapply.org
  • m4 को थोड़ा मिलाने से उसी bare-bones approach को बनाए रखते हुए थोड़ी और flexibility मिल सकती है

लगभग 20 साल पहले मैंने इसी तरीके से बनी एक छोटी वेबसाइट maintain की थी। लेकिन personal websites को छोड़ दें तो आजकल यह मॉडल कितना फिट बैठेगा, पता नहीं। क्योंकि यह तरीका मूल रूप से Web 1.0 वाली भूमिकाएँ थोप देता है। योगदान देने वाले हर user को HTML में निपुण होना पड़ेगा, या फिर किसी को “webmaster” जैसा झंझट वाला काम अपने ऊपर लेना पड़ेगा
[1] https://en.wikipedia.org/wiki/M4_(computer_language)

  • “थोड़ा-सा m4” जैसी कोई चीज़ नहीं होती
    एक clean project शुरू करते हैं और कसम खाते हैं कि इस बार m4 को हाथ नहीं लगाएंगे। फिर repetitive code कम करने के लिए एक छोटा-सा m4 call डाल देते हैं
    एक साल बाद वेबसाइट से “cat” शब्द चुपचाप गायब क्यों हो रहा है, यह खोजते हुए macro expansion की 5 परतें खंगालते हैं, और अंत में पता चलता है कि एक junior developer ने manual से copy करने के बजाय खुद for loop implement किया और quotes खराब कर दिए
    तत्काल समस्या हल करने के बाद लगता है कि DSL debugging बहुत कठिन है, इसलिए वह M4 macro file उठा लाते हैं जिसे हर project में copy करते रहे हैं। इसके बाद output में comments जोड़कर stack trace generation script चलाने वाले macro-generating macro से define के सभी use बदलने में पूरा दिन निकल जाता है
    अगले project में पक्का नियम बनाएंगे। m4 banned! हाँ, शायद उस एक जगह को exception रखा जा सकता है
  • m4 या perl जैसे general text substitution पर निर्भर रहने के बजाय, HTML और XML का आधार और common superset SGML इस्तेमाल करने की सलाह दूँगा
    SGML आसान type-checked text macros, यानी entity expansion, built-in देता है, और type-aware parameterized macro expansion भी संभव है। यहाँ type से मतलब markup element के general content type से है, यानी कौन से child elements और किस order में allowed हैं; साथ ही attributes, CDATA, RCDATA जैसे contexts में expand या escape करने पर भी विचार होता है
    संभावित रूप से malicious user comments को सही तरह expand/escape करते हुए, उदाहरण के लिए inline-level markup allow करना और script elements block करना—ऐसे user rules को ठीक से केवल SGML ही expand कर सकता है। Markdown या wiki syntax को HTML में expand करना, external/syndication HTML content लाना, RSS और navigation के लिए outline बनाना वगैरह भी संभव है। command line पर काफी complex static site preparation tasks के लिए यह अच्छी तरह फिट बैठता है
    [1]: https://sgmljs.net/docs/producing-html-tutorial/producing-ht...
    [2]: https://sgmljs.net/docs/sgmlproc-manual.html
  • m4 या sed find-and-replace की जगह envsubst आज़माना अच्छा रहेगा
    यह Bash-style variable references, जैसे $TITLE, को environment variable values से replace करने वाला program है
    export CURRENT="..."
    cat page.html | envsubt
  • “थोड़ा-सा m4”, प्लीज़ बिल्कुल नहीं
    m4 एक esoteric programming language के तौर पर भी खास नहीं है
  • एक बार किया है, फिर कभी नहीं
    सिर्फ यह तथ्य कि वह sendmail में चलता था, किसी चीज़ को justify करने के लिए काफी नहीं है
  • HN पर मिलने वाले लगभग हर developer blog में RSS feed होती है, यह बात अच्छी लगती है
    यहाँ जब भी कोई दिलचस्प post पढ़ता हूँ, feed subscribe कर लेता हूँ। चाहे Wordpress site हो, Bear Blog हो, Micro.blog हो, Havenweb blog हो, या किसी की खुद बनाई site की feed हो—मैं उसे Hey Homepage के Really Social Sites module में जोड़ देता हूँ
    आखिरकार मैं इस blog list को public करना चाहता हूँ, जैसे Kagi अपनी Small Web initiative में करता है। लेकिन quality जोड़नी हो तो curation ही key है, और curation के बारे में सोचते-सोचते किसी online magazine जैसी चीज़ शुरू करना स्वाभाविक लगने लगता है
    • एक developer के तौर पर मुझे अपना blog रखने की इच्छा नहीं है—क्या मैं अजीब हूँ, यह समझने की कोशिश कर रहा हूँ
      लोग दूसरों के साथ share करने लायक, अच्छे अर्थ वाला “entitlement” कहाँ से पाते हैं? मुझे समझ नहीं आता कि वे क्यों मान लेते हैं कि दूसरे लोग इस बात में interested होंगे कि मैं किस पर काम कर रहा हूँ। कभी-कभी यह competition जैसा लगता है। जैसे “blog पर likes या exposure पाने के लिए सबसे cool चीज़ बनानी होगी”
      collaboration बेशक अच्छी चीज़ है, और सब कुछ public होगा तभी संभव है। बस “यह cool लग रहा है इसलिए कर रहा हूँ” और “reaction पाने के लिए इसे दूसरों के साथ share करने की कोशिश कर रहा हूँ” के बीच की line समझ नहीं आती
    • Bear Blog जैसा https://prose.sh भी है
  • एक दोस्त ने कभी बताया था कि वह make से scientific papers generate करता है
    उसने कहा था कि सिर्फ एक test file बदलने पर भी एक ही command से tests run करने और graphs generate करने सहित पूरा paper दोबारा generate किया जा सकता है
  • idea neat है, लेकिन अगर आप पहले से GitHub पर push कर रहे हैं, तो सिर्फ source upload करने पर भी GitHub Markdown को hosted page के रूप में publish कर सकता है
    https://pages.github.com/
    • तब आप simple hosting से भी ज्यादा GitHub पर dependent हो जाते हैं। शुरुआत से ही site generation local पर चला सकें, ऐसा रखना बेहतर है
  • code पसंद आया
    मेरा version JavaScript के बिना hot reload चाहता था, इसलिए थोड़ा over-engineered हो गया, और यह एक मजेदार yak shaving था
    basic idea वही है। templates के लिए heredoc इस्तेमाल करता हूँ, plain text को HTML में बदलने वाला compiler use करता हूँ, मेरे case में pandoc है। index generation के लिए intermediate CSV का इस्तेमाल करता हूँ, और front matter निकालने की एक उपयोगी sed trick भी है। classic और अच्छा
    [1] https://github.com/karlb/karl.berlin/blob/master/blog.sh
    [2] https://github.com/adityaathalye/shite
    [3] मेरा तरीका: https://github.com/adityaathalye/shite/blob/master/bin/templ...
    • उसका GEMINI approach काफी मजेदार लगा। regex से formatting का ज्यादातर हिस्सा हटा देता है

हालांकि इसमें थोड़ी सीमा है। मैं लेखों को namespace के हिसाब से व्यवस्थित करता हूं और URL में तारीख डालता हूं, लेकिन make इसे सीधे अच्छी तरह handle नहीं कर पाता

  • इस तरह की scripts को देखकर ठीक-ठीक समझ आता है कि हम खुद बनाने के बजाय esbuild या vite जैसी चीजें क्यों इस्तेमाल करते हैं
  • make का फायदा यह है कि धीमे compiler से build होने वाले बड़े programs में छोटे बदलाव होने पर यह incremental rebuild को काफी तेज बना देता है
    जिस काम के full rebuild में 40 मिनट लगते, वह लगभग 3 सेकंड में खत्म हो सकता है
    अगर कोई static site common header और कुछ सौ HTML files को cat करने भर से 1 सेकंड से कम में शुरू से generate हो जाती है, तो script के बजाय make इस्तेमाल करने का कोई फायदा नहीं है। dependency bug की वजह से अधूरा build होने का जोखिम ही पैदा होता है
    • अगर file dependencies वाकई महत्वपूर्ण नहीं हैं, तो build target को .phony के रूप में mark कर सकते हैं
      फिर भी make build और make push जैसा distinction रखा जा सकता है
  • वाह, यह लगभग बिल्कुल वही है जो मैं अपनी site पर करने वाला था
    दूसरे छोटे project में मैंने temporary bundler के रूप में एक बहुत छोटी shell script इस्तेमाल की थी। तरीका CSS और JS को HTML के अंदर insert करने का था, और लक्ष्य यह था कि unbuilt files को भी local पर serve किया जा सके