JavaScript Gom Jabbar
(frantic.im)- 10 साल के अनुभव वाला JavaScript डेवलपर
package.jsonपढ़ने के दृश्य को दर्द की परीक्षा बनाकर दिखाता है कि एक config file में ecosystem की जमा हुई complexity कितनी भरी होती है main,browser,type: moduleजैसे fields Isomorphic JavaScript, browser bundle, और CommonJS से ESM transition की पुरानी migration चोटों की याद दिलाते हैंscripts,dependencies,devDependenciesमें lint variants,watchman, gulp,left-pad, moment.js,resolutionsजैसे पुराने tools और package management समस्याएँ उलझी हुई हैंeslint,postcss,jestऔर build/test tools सख्त rules, platform-specific install errors, और ESM/TypeScript configuration की कठिनाई के जरिए development environment maintenance cost बढ़ाते हैं- Node
enginesदेखते हुए भी Bun या Deno पर न जाने की वजह यह यकीन है कि दर्द खत्म नहीं होगा, बल्कि और बढ़ेगा; डेवलपर file बंद करता है और फिलहाल बच निकलता है
package.json पढ़ने की परीक्षा
- कहानी उस स्थिति से शुरू होती है जहाँ 10 साल से JavaScript इस्तेमाल कर रहा डेवलपर अपने कंप्यूटर के सामने
package.jsonfile खोलकर उसे अंत तक पढ़ने को मजबूर है - यह file कोई साधारण config file नहीं है, बल्कि JavaScript ecosystem में झेली गई यादों और दर्द को एक साथ वापस बुलाने वाली चीज है
versionअभी भी1.0तक नहीं पहुँचा है, और SemVer बहुत पहले से अनदेखा करना सीख ली गई एक अप्रिय याद बनकर रह गया हैnameदिखाता है कि 7 साल पहले किसी ने एक package name कब्जा कर लिया और फिर update नहीं किया, इसलिए मनचाहा नाम इस्तेमाल नहीं किया जा सकता
modules और bundling की पुरानी चोटें
mainऔरbrowserfields साथ मौजूद हैं, जिससे Isomorphic JavaScript के निशान दिखते हैं- browser bundle में
fsmodule कोrequireकरने की याद, और उसे चलाने के लिए किए गए hacks, अप्रिय अनुभव बनकर रह गए हैं type: moduleका संबंधrequireसेimportकी ओर migration से है- CommonJS और ESM modules को एक-दूसरे में import करने की कोशिश का अनुभव बड़ा दर्द बनकर रह गया है
scripts और dependencies की अव्यवस्था
scriptsगर्म और दर्दनाक अव्यवस्था का केंद्र हैlint,lintall,lintfast,lintdiffजैसे variants हैं- parallel execution, अस्पष्ट arguments, और JSON-format arguments की double escaping सामने आती है
- yarn और pnpm पर जाने के बाद भी कुछ subcommands अब भी npm को call करते हैं
- कुछ scripts अभी भी
watchmanइस्तेमाल करते हैं- यह याद रखना पड़ता है कि symlink support न होने के कारण इसे इस्तेमाल नहीं करना चाहिए
- संबंधित issue 2015 से खुला है
- gulp-based scripts भी बचे हुए हैं; उन्हें किसी modern चीज से बदलना चाहते हैं, लेकिन कोई भी replacement की हिम्मत नहीं करता
package list से लौटता trauma
dependenciesमें बहुत सारे packages हैं, और हर package अपनी-अपनी trauma memory को फिर से जगा देता हैleft-padएक छोटा package है, लेकिन “पूरे internet को तोड़ देने वाला” legendary package बनकर रह गया है- dependency list में बदलाव करते ही कुछ packages console में donation requests या breaking change warnings लंबी-लंबी print करते हैं
- डेवलपर बस यही उम्मीद करने की स्थिति में आ जाता है कि कोई malicious package secrets चोरी न करे या computer को खराब न कर दे
- moment.js एक अच्छे API वाली library के रूप में याद है, लेकिन internet ने उसे बहुत mutable, बहुत बड़ा, और treeshaking support न करने वाला माना; अब date-fns पर migration करना है
- package versions आज के standards से काफी पीछे हैं और upgrade की जरूरत है, लेकिन पुराने upgrade अनुभवों के कारण बड़े दर्द की आशंका है
resolutionspackage upgrades से बचने के लिए चुना गया एक और दर्द बनकर रह गया है
development tools से बनी एक और complexity
devDependenciesदेखते हुए वह दौर याद करना मुश्किल है जब सिर्फ non-dev dependency की जरूरत होती थीeslintconfiguration इतना सख्त हो गया है कि छोटी गलती पर भी लाल underline आ जाती है, और CI lint issues को दुनिया के अंत जैसा मानता है- यह team के junior engineers को गलत तरह की सुरक्षा-भावना देता है
- कौन-से rules enable किए जाएँ, इस पर कई बार बहस हुई है
- codebase भर में मौजूद
eslint-ignoreकी संख्या जितना ही दर्द बढ़ता है
postcssसीधे इस्तेमाल नहीं होता, लेकिन dependency की dependency के लिए जरूरी package के रूप में मौजूद है- हर बार नए platform पर
npm installचलाने की कोशिश में अस्पष्ट C++ compile errors पैदा करता है
- हर बार नए platform पर
jestएक fast test runner के रूप में शुरू हुआ था, लेकिन अब बड़ा और भारी हो गया है, और कुछ Babel packages पर निर्भर है- application का बाकी हिस्सा esbuild और swc के combination से transpile होता है
- ESM और TypeScript के लिए इसे सही ढंग से configure करना “PhD science project” जितना कठिन है
- codebase में TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser जैसे कई tools और parsers शामिल हैं
enginesमेंnodespecified है, और माना जाता है कि Bun या Deno पर जाने से भी दर्द रुकेगा नहीं, बल्कि और खराब होगा- आखिरी closing brace तक पढ़ने के बाद वह tab बंद करता है, साँस सँभालता है, और हाथों व दिमाग के सलामत रहते फिलहाल बच निकलता है
1 टिप्पणियां
Hacker News की राय
काफ़ी मज़ेदार। मैंने लगभग 18 साल JavaScript लिखा और लगभग 3 साल पहले छोड़ दिया, लेकिन इस सूची की ज़्यादातर चिंताएँ पिछले 10 सालों की चीज़ें हैं
ख़ास तौर पर यह ध्यान खींचता है कि इसमें polyfill नहीं है, जो 2013 में लिखा जाता तो ज़रूर होता। 2013 के JavaScript दुःस्वप्नों में से और क्या अब लगभग ग़ायब हो चुका है? बेशक उसकी जगह यह मज़ेदार सूची आ गई है
मेरा पसंदीदा हिस्सा वह था जहाँ कोडबेस में काम करने वाले टूल और parser गिनते-गिनते TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser याद आते हैं, और दर्द इतना बढ़ जाता है कि यह भी जानना नहीं चाहते कि कुछ और छूट तो नहीं गया
undefined,with, private fields की नकल के लिए closures, बदले हुए prototypes, default global variables, कॉल की जगह के हिसाब से बदलने वालाthis, comparison के समय automatic type coercion…हाँ, JavaScript के 10 से ज़्यादा साल ऐसे ही गुज़रे
SomeFunction.prototypeको बदलकर बनाए गए fake classes थेउसे तुरंत चलने वाले anonymous function में लपेटकर object के रूप में लौटाते थे, ताकि
SomeFunctionको class की तरह दिखाया जा सके औरnew SomeFunction()याSomeFunction.actualFunction()कॉल किया जा सके। arrow functions नहीं थे, इसलिए event को scope में बाँधने के लिएFunction.prototypeतक बदल देते थे और.apply()इस्तेमाल करते थे, या हर event callback में अंतहीन.bind(this)नरक में फँस जाते थेआज भी मुझे एक ऐसी company के test assignment लिखने का दुर्भाग्य झेलना पड़ा जो अभी भी Promise या declaration files के बिना pure JavaScript इस्तेमाल करती है, और ऐसा लगा जैसे 2012 में पहली बार Node से मिला था। JavaScript इस्तेमाल करने की शर्त को मैंने JSDoc से किसी तरह संभाला, लेकिन यह मेरी याद से कहीं ज़्यादा बुरा था
जब भी नया JavaScript, या सही कहें तो TypeScript project, शुरू करता हूँ तो हमेशा वही प्रक्रिया दोहरानी पड़ती है
आमतौर पर frontend होता है, इसलिए React चुनता हूँ, हालांकि Svelte भी आज़माना चाहता हूँ। bundler पहले create-react-app या Webpack wrapper हुआ करता था, लेकिन अब कम configuration और सभी बड़े frameworks के support की वजह से Vite सबसे अच्छा विकल्प है
TypeScript compiler install और configure करता हूँ, अक्सर किसी template से copy-paste करके। target latest stable JavaScript और ESM modules पर रखता हूँ, eslint और prettier को साथ में configure करता हूँ, और TypeScript व React जैसे plugins भी जोड़ता हूँ। commit से पहले Prettier और eslint चलाने वाला hook भी डालता हूँ
IDE extensions भी install करता हूँ और
.devcontainerया recommended extensions की list भी बना देता हूँ। मुझे styling से ख़ास मतलब नहीं, code consistency और mistakes पकड़ना ज़्यादा ज़रूरी है, इसलिए eslint के लिए आमतौर पर तैयार config इस्तेमाल करता हूँउसके बाद jest या vitest जैसे unit test setup करता हूँ, और फिर TypeScript से जुड़ी settings और eslint rules फिर साथ आते हैं। CSS framework के लिए tailwind पसंद है, इसलिए styled-components और twin.macro भी install करता हूँ ताकि React के साथ अच्छे से फिट हो, और Google Fonts plugin या font library भी जोड़ता हूँ
इस सब में लगभग एक दिन निकल जाता है, तब जाकर programming शुरू कर पाता हूँ। इतना सारा काम क्यों है? Vite + TypeScript + React/Vue/Svelte + eslint/prettier + tailwind/bootstrap + jest/vitest का combo इस्तेमाल करने वाले इतने लोग हैं, फिर भी 90% use cases के लिए तैयार zero-config library क्यों नहीं है?
toolchain को किसी तरह चालू कर भी लूँ तो कभी महसूस नहीं हुआ कि यह मेरे control में है, और लगता था कि हल्का-सा झटका लगे तो सब गिर जाएगा और मैं उसे ठीक भी नहीं कर पाऊँगा
हाल में मैंने तय किया कि इस JavaScript stack का ज़्यादातर हिस्सा उस काम के लिए रुकावट है जो मैं करना चाहता हूँ, इसलिए पहले की तरह Flask और Jinja2 आधारित server-side rendered app बना लिया। यह modern या चमकदार नहीं है, और CSS भी नहीं है इसलिए अभी काफ़ी बदसूरत है, लेकिन मुझे pure modern CSS अपनाने की सलाह मिली। फिर भी यह चौंकाने वाला है कि उस stack में features कितनी जल्दी बना सकता हूँ
package.jsonमें सिर्फ़ नाम बदलता हूँ। हाँ, मैं ज़्यादातर backend ही करता हूँ, लेकिन क्या frontend के लिए भी ऐसा personal template नहीं बनाया जा सकता?npm createयह काम नहीं करता?npm create vueचलाने पर ज़्यादातर setup पहले से किया हुआ एक काफ़ी अच्छा और काम करने वाला Vue configuration मिल जाता है। मैं मानता हूँ कि boilerplate और इधर-उधर की चीज़ें बहुत हैं, लेकिन आजकल जो apps हम web पर बनाते हैं वे पहले से कहीं बड़े हो गए हैं। सिर्फ़ ESModules के सहारे बिना tools के JavaScript इस्तेमाल कर सकते हैं, लेकिन आमतौर पर ऐसा नहीं करते क्योंकि वे tools सच में कुछ काम के होते हैं। यह सबसे साफ़ तरीका नहीं है, लेकिन किसी न किसी तरह काम करता हैनया project शुरू करते समय उसे clone करके बस कुछ जगह नाम बदलो, और काम शुरू करने के लिए तैयार हो जाओ
लोग इसे JavaScript कहते हैं, लेकिन असल में इसका मतलब “Node ecosystem का कबाड़” होता है
शुरुआत से ही
package.jsonफ़ाइल खोलकर पढ़ने को कहा जाता है, और आगे भी बात उसी दिशा में चलती रहती है। जिन चीज़ों का ज़िक्र है, उनमें JavaScript खुद से जुड़ी चीज़ें लगभग नहीं हैंयह सही है कि JavaScript और NodeJS एक ही चीज़ नहीं हैं, लेकिन ज़्यादातर लोगों ने समझ लिया होगा कि लेखक का मतलब क्या था। और ज़्यादा सटीक लिखा जाता तो अच्छा होता, लेकिन इसे पूरी तरह ग़लत कहना भी मुश्किल है
package.jsonइस्तेमाल करने वाले bundler के JavaScript सच में एक बार लिखकर देखो। जब तक ECMA आधिकारिक spec में package manager या bundler नहीं डालता,package.jsonव्यावहारिक रूप से JavaScript का हिस्सा हैइसका मज़ाकिया लहजा अच्छा है। त्वचा और नसों के सिरे कई परतों तक जल जाने के बाद, दर्द के ऐसे बिंदुओं को फिर से याद करना फ़ायदेमंद होता है
उल्टा कहें तो, किसी उत्साही junior डेवलपर को नई MacBook देकर गहरे पानी में फेंक दो, तो भी वह एक दिन के भीतर productive हो सकता है। उसे containers, .NET, nginx, या अक्सर इस्तेमाल होने वाले 100 command-line tools जानने की ज़रूरत नहीं, और समस्या आए तो बस search कर सकता है
यह जानते हुए भी कि अगर सीधे हाथ लगाने दिया जाए तो कुछ दिनों में पूरा जहाज़ बना सकता है, उसे दिए गए घटिया tools के साथ बोतल के अंदर जहाज़ ठीक करने जैसा काम करना पड़ता है, और अनावश्यक जटिलता की परतों से लड़ना पड़ता है। सिर्फ JavaScript, HTML, CSS से कोई personal project तेज़ी से आगे बढ़ाने के बाद जब modern frontend के काम में झोंक दिया जाता है, तो बिल्कुल ऐसा ही लगता है
उसे बनाने में कई महीने लगते हैं, और यह कि समस्या का एक हिस्सा framework की भरमार है, और वह अगले ही दिन पुराना पड़ जाएगा — यह उन्हें भोलेपन में समझ नहीं आता
“मैंने निर्देशों के मुताबिक किया, फिर उसने कहा कि grunt installed नहीं है। अब मैं बूढ़ा आदमी हूँ, इसलिए मुझे ठीक से पता नहीं था कि grunt क्या है, और मेरी grunt file में भी कुछ गड़बड़ थी। तो मैंने थोड़ा search किया और पता लगाया कि grunt क्या है। Grunt है… सच कहूँ तो अभी भी मुझे ठीक से नहीं पता।”
--Joe Armstrong, https://www.youtube.com/watch?v=lKXe3HUG2l4
कुछ दिन पहले मैंने
gem install wayback_machine_downloaderचलाया। Ruby नाम की भाषा मुझे कभी इतनी पसंद नहीं आई कि उसके ecosystem में उतर जाऊँ, लेकिन बाहर से देखने पर उसका ecosystem हैरान करने वाली हद तक स्थिर बना रहा है। gem अभी भी इस्तेमाल होने वाला tool है, और Rails भी अभी भी मौजूद हैमैं उस नए प्रोजेक्ट का इंतज़ार कर रहा हूँ जिसमें complex frontend की ज़रूरत हो और JavaScript की 0~30 लाइनों से आगे जाना पड़े। तब शायद आजकल के सबसे लोकप्रिय विशाल framework की बजाय HTMX के साथ मैं ज़्यादा खुश रहूँगा
यह JavaScript के बारे में नहीं, npm के बारे में पोस्ट है
ऐसी बकवास की वजह से मैं npm से नफ़रत करता हूँ और जितना हो सके उससे बचता हूँ। निजी तौर पर मैं Deno इस्तेमाल करता हूँ, और काम पर monorepo-आधारित bazel-जैसी किसी चीज़ का इस्तेमाल करता हूँ जो npm की ज़रूरत ही ख़त्म कर देती है
लेकिन मुझे JavaScript/TypeScript प्रोग्रामिंग के लिए अच्छी भाषाएँ लगती हैं, और मैं कुछ भी बनाऊँ, सबसे पहले इन्हीं को चुनता हूँ। जब लोग कहते हैं “JavaScript बेकार है”, लेकिन असल में उनका मतलब होता है कि npm के साथ React app build करना बेकार है, तो दुख होता है। modern JavaScript/TypeScript coding सच में बहुत मज़ेदार है
ऐसा लगता है कि JavaScript और उसके ecosystem ने हम सबको इतना PTSD दे दिया है कि हम इस पोस्ट की comedy का मज़ा ही नहीं ले पा रहे
एक मज़ेदार पोस्ट पर “गंभीर” बहस कुछ ज़्यादा ही हो रही है। चाहो तो इसे खुलकर dissect करो, लेकिन यह याद रखना अच्छा होगा कि असली मंशा humor है
सच कहूँ तो, मेरा पहला ecosystem Node था, और बाद में जो चीज़ें सीखीं, उनमें भी हर एक के अपने पागलपन भरे मसले थे
Haskell को कई मशीनों पर इस्तेमाल करना बहुत मुश्किल था, 2019 में उसे MacOS पर install करना भी दर्दनाक था, और ecosystem management भी कठिन था। macros और extensions काफ़ी उलझाऊ हैं, और भाषा की backward compatibility भी अच्छी नहीं है। इसके उलट, 2010 का JavaScript आम तौर पर 2023 में भी वैसे ही चलने की उम्मीद की जा सकती है
Docker image या codespace/gitpod जैसे environment को ठीक से बनाना भी मुश्किल है, और GitHub की दी हुई default image भी बहुत अच्छी नहीं है और समस्याएँ रखती है
C ज़्यादातर platforms पर आम तौर पर ठीक है, लेकिन भाषा खुद ईमानदारी से कहें तो जटिल है और पूरे system के बारे में बहुत व्यापक ज्ञान माँगती है। नतीजा यह होता है कि ऐसा कम portable code बनना आसान है जो सामान्य programming के ज़्यादातर उपयोगों के लिए उपयुक्त नहीं होता
और भी कह सकता हूँ, लेकिन जिसने कई भाषाएँ इस्तेमाल की हैं, वह जानता है कि हर ecosystem में कई कमियाँ हैं और हम सब लगातार किसी न किसी रूप में पीड़ित रहते हैं। PHP में मैंने कभी कुछ दिनों के भीतर project setup पूरा नहीं किया, और Elm कम तकलीफ़देह है, लेकिन उसकी अपनी समस्याएँ हैं — benevolent dictator वाली स्थिति और development speed
मैं एक polyglot developer हूँ, जिसे कई programming paradigms और languages के साथ-साथ frontend और backend दोनों में काम करना सहज लगता है
जब भी
package.jsonको 20 लाइनों से लंबा देखता हूँ, तो लगभग हर बार मेरी प्रतिक्रिया बिल्कुल ऐसी ही होती हैpackage.json200 लाइनों से भी लंबा हैज़ोर से ऐसे बोल रहा हूँ मानो किसी शैतान को दूर भगाने की कोशिश कर रहा हो। “डरना नहीं चाहिए। डर मन को मार देता है। डर वह छोटी मौत है जो पूर्ण विनाश लाती है। मैं अपने डर का सामना करूँगा। मैं उसे अपने ऊपर से गुज़र जाने दूँगा। और जब वह गुज़र जाएगा, तो मैं मन की आँख से उसका रास्ता देखूँगा। जहाँ डर गुज़र चुका होगा, वहाँ कुछ भी नहीं होगा। केवल मैं बचूँगा।”
रो रहा हूँ
पुराने ज़माने का JavaScript developer इस लेख को पढ़ते हुए PTSD और flashbacks से जूझ रहा है
डरना नहीं चाहिए। डर मन को मार देता है। डर वह छोटी मौत है जो पूर्ण विनाश लाती है
मैं अपने डर का सामना करूँगा। मैं उसे अपने ऊपर से गुज़र जाने दूँगा। और जब वह गुज़र जाएगा, तो मैं मन की आँख से उसका रास्ता देखूँगा
जहाँ डर गुज़र चुका होगा, वहाँ कुछ भी नहीं होगा। केवल मैं बचूँगा
लेख पूरा पढ़कर एहसास होता है कि मैं बच गया, लेकिन तब तक मैं पसीने से लथपथ हो चुका हूँ