10 पॉइंट द्वारा GN⁺ 2026-03-23 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • npm ecosystem में dependency tree का बLOAT एक बड़ी समस्या के रूप में देखा जाता है, और इसके पीछे पुराने runtime support, atomic package structure, और पुराने ponyfill का उपयोग मुख्य कारण हैं
  • पुराने engine compatibility और cross-realm safety के कारण बनाए रखे गए छोटे utility packages आधुनिक environment में भी अनावश्यक रूप से बचे हुए हैं
  • Atomic architecture का लक्ष्य reusability बढ़ाना था, लेकिन व्यवहार में यह duplication, security, और maintenance cost बढ़ाने वाली अक्षम संरचना बन गई है
  • जिन features को सभी engines पहले से support करते हैं, उनके लिए बने पुराने ponyfill packages हटाए नहीं गए, जिससे अनावश्यक downloads और management burden पैदा होता है
  • Community, e18e, knip, और module-replacements जैसे tools के जरिए अनावश्यक dependencies हटाने और native features पर शिफ्ट करने की दिशा में काम कर रही है

JavaScript dependency बLOAT के तीन स्तंभ

  • e18e community के बढ़ने के साथ performance-केंद्रित contributions बढ़ रहे हैं, और अनावश्यक या unmaintained packages को हटाने की cleanup activity चल रही है
  • npm ecosystem में dependency tree का बLOAT (dependency bloat) एक मुख्य समस्या है, और पुराने runtime support, atomic package structure, तथा पुराने ponyfill का उपयोग इसके प्रमुख कारण माने जाते हैं

1. पुराना runtime support (safety और realm सहित)

  • npm tree में is-string, hasown जैसे कई छोटे utility packages मौजूद हैं, और ये मुख्यतः नीचे दिए गए तीन कारणों से बने हुए हैं
    • बहुत पुराने engines (जैसे ES3, IE6/7, शुरुआती Node.js) का support
    • global namespace modification से सुरक्षा

      • cross-realm values को handle करना
  • पुराने engines का support

    • ES3 environment में Array.prototype.forEach, Object.keys, Object.defineProperty जैसी ES5 features मौजूद नहीं थीं
    • ऐसे environment में direct implementation या polyfill का उपयोग करना पड़ता है
    • सबसे अच्छा समाधान upgrade है, लेकिन कुछ users अब भी पुराने versions पर टिके हुए हैं
  • global namespace modification से सुरक्षा

    • Node अंदरूनी रूप से primordials की अवधारणा का उपयोग करता है, जिसमें global objects को शुरुआत में wrap करके modification से सुरक्षित रखा जाता है
    • उदाहरण के लिए, अगर Map को redefine कर दिया जाए तो Node खुद टूट सकता है, इसलिए Node original reference को बनाए रखता है
    • कुछ package maintainers यही तरीका सामान्य packages में भी अपनाते हैं और math-intrinsics जैसे safety-केंद्रित packages का उपयोग करते हैं
  • Cross-realm values

    • iframe के बीच object pass करने पर instanceof check fail हो सकता है
    • उदाहरण: window.RegExp !== iframeWindow.RegExp
    • chai जैसे test frameworks realm के बीच type check के लिए Object.prototype.toString.call(val) तरीका इस्तेमाल करते हैं
    • is-string जैसे packages ऐसी cross-realm compatibility के लिए मौजूद हैं
  • समस्या

    • ज़्यादातर developers modern Node या evergreen browsers का उपयोग करते हैं, इसलिए ऐसी compatibility की ज़रूरत नहीं होती
    • लेकिन ये packages सामान्य dependency tree के “hot path” में शामिल हो जाते हैं, इसलिए सबको इसकी cost चुकानी पड़ती है

2. Atomic architecture

  • कुछ developers का मानना है कि packages को जितना संभव हो छोटी units में बाँटना चाहिए ताकि reusable building blocks बनाए जा सकें
  • नतीजतन shebang-regex, arrify, slash, path-key, onetime, is-wsl जैसे बेहद सूक्ष्म रूप से विभाजित packages बड़ी संख्या में मौजूद हैं
  • उदाहरण: shebang-regex में सिर्फ एक line की regex है (/^#!(.*)/)
  • समस्या

    • ज़्यादातर atomic packages reuse नहीं होते या उनका सिर्फ एक consumer होता है
    • उदाहरण:
      • shebang-regex → सिर्फ shebang-command उपयोग करता है
      • cli-boxes → सिर्फ boxen, ink उपयोग करते हैं
      • onetime → सिर्फ restore-cursor उपयोग करता है
    • ऐसे मामलों में यह inline code जैसा ही है, लेकिन npm requests, extraction, bandwidth जैसी अतिरिक्त cost पैदा होती है
  • duplication की समस्या

    • उदाहरण: nuxt@4.4.2 dependency tree में is-docker, is-stream, is-wsl, path-key आदि 2-2 versions में duplicate मौजूद हैं
    • अगर इन्हें inline code से बदला जाए तो version conflicts या resolution cost खत्म हो जाती है, इसलिए duplication cost लगभग शून्य हो सकती है
  • supply chain risk का विस्तार

    • packages की संख्या जितनी अधिक होगी, security और maintenance risk उतना बढ़ेगा
    • वास्तव में, एक maintainer के कई छोटे packages manage करने के दौरान उसका account hack हो गया और सैकड़ों packages एक साथ compromise हो गए थे
    • साधारण code (Array.isArray(val) ? val : [val]) को अलग package बनाने की बजाय inline handle किया जा सकता है
  • निष्कर्ष

    • Atomic architecture, अपने इरादे के विपरीत, अक्षम और जोखिमपूर्ण संरचना में बदल गई है
    • अधिकांश users के लिए किसी वास्तविक लाभ के बिना पूरा ecosystem इसकी cost उठाता है

3. पुराने Ponyfill

  • Polyfill वह code है जो engine द्वारा unsupported feature को environment में जोड़ता है, जबकि Ponyfill environment को बदले बिना सीधे import करके इस्तेमाल की जाने वाली alternative implementation है
  • उदाहरण: @fastly/performance-observer-polyfill polyfill और ponyfill दोनों उपलब्ध कराता है
  • समस्या

    • Ponyfill पहले उपयोगी थे, लेकिन target feature सभी engines में support होने के बाद भी हटाए नहीं गए
    • उदाहरण:
      • globalthis (2019 से support, साप्ताहिक 4.9 करोड़ downloads)
      • indexof (2010 से support, साप्ताहिक 23 लाख downloads)
      • object.entries (2017 से support, साप्ताहिक 3.5 करोड़ downloads)
    • ऐसे packages ज़्यादातर सिर्फ इसलिए बचे हैं क्योंकि उन्हें हटाया नहीं गया
    • जब सभी LTS engines किसी feature को support करने लगें, तो ponyfill हटा दिए जाने चाहिए

बLOAT कम करने के उपाय

  • dependency tree की गहरी nesting के कारण cleanup मुश्किल है, लेकिन community collaboration से सुधार संभव है
  • हर developer को खुद से पूछना चाहिए, “क्या यह package सच में ज़रूरी है?” और अगर नहीं, तो issue उठाना या alternative package ढूँढना चाहिए
  • module-replacements project ऐसे packages की सूची देता है जिन्हें native features से बदला जा सकता है
  • knip का उपयोग

    • knip unused dependencies और dead code detect करने का tool है
    • यह सीधा समाधान नहीं है, लेकिन cleanup शुरू करने के लिए उपयोगी है
  • e18e CLI का उपयोग

    • @e18e/cli analyze command से replace की जा सकने वाली dependencies detect की जा सकती हैं
    • उदाहरण: chalkpicocolors में automatic migration
    • आगे चलकर environment के आधार पर Node के styleText जैसे native features recommend करने की योजना है
  • npmgraph का उपयोग

    • npmgraph.js.org dependency tree visualization tool है
    • उदाहरण: eslint@10.1.0 tree में find-up branch अलग-थलग पड़ी है
    • साधारण file lookup के लिए 6 packages की ज़रूरत नहीं होनी चाहिए, इसलिए empathic जैसे छोटे alternatives इस्तेमाल किए जा सकते हैं
  • module replacements project

    • Community replace किए जा सकने वाले packages और native features की mapping dataset को maintain करती है
    • codemods project के जरिए automatic migration भी support किया जाता है

निष्कर्ष

  • मौजूदा बLOAT ऐसी संरचना है जिसमें पुरानी compatibility और अजीब architecture बनाए रखने वाले कुछ users के कारण पूरी community cost चुकाती है
  • पहले यह अपरिहार्य था, लेकिन आज जब modern engines और APIs काफ़ी विकसित हो चुके हैं, यह अनावश्यक बोझ बन चुका है
  • आगे चलकर इन कुछ users को अलग stack maintain करना चाहिए, और बाकी ecosystem को हल्के और modern codebase की ओर बढ़ना चाहिए
  • e18e और npmx जैसे projects documentation और tooling के माध्यम से इसे support कर रहे हैं, और हर developer को अपनी dependencies की समीक्षा करके पूछना चाहिए: “यह क्यों ज़रूरी है?”
  • सफाई सब मिलकर कर सकते हैं

2 टिप्पणियां

 
click 2026-03-23

जब मैं भी लाइब्रेरी बनाता हूँ, तो अभी CJS build देता हूँ
लेकिन 2026 में भी जिन लाइब्रेरीज़ में ESM examples तक नहीं हैं और सब कुछ require-based है, उनका थोड़ा update हो जाना अच्छा होगा।

 
GN⁺ 2026-03-23
Hacker News की राय
  • मुझे लगता है कि आजकल dependency-free JavaScript के साथ development करना सबसे अच्छा रास्ता है
    JS/CSS standard libraries भी शानदार हैं, और static analysis (TypeScript का JSDoc check), ES modules, web components वगैरह भी काफ़ी शक्तिशाली हैं
    लोग कहते हैं कि यह तरीका scalability या maintenance के लिए नुकसानदेह है, लेकिन मेरे अनुभव में इससे उल्टा ज़्यादा सरल और आसानी से बदली जा सकने वाली structure बनाए रखना संभव हुआ

    • मैं भी कई सालों से इस approach पर प्रयोग कर रहा हूँ, और plainvanillaweb.com नाम की एक tutorial site भी बनाई है
      framework या build tools जो ज़्यादातर काम करते हैं, उन्हें browser की built-in features और vanilla patterns से बदला जा सकता है
      लेकिन यह तरीका अभी भी काफ़ी अनजान इलाक़ा है, इसलिए समस्या यह है कि ज़्यादातर tutorial ecosystem बड़े frameworks के इर्द-गिर्द घूमता है
      वास्तव में React code को पूरी तरह vanilla में ले जाने पर भी modularity बनी रहती है और code की लंबाई लगभग 1.5 गुना ही बढ़ती है, लेकिन dependencies न होने की वजह से performance और बेहतर हो जाती है
      बेशक dependencies बुरी चीज़ नहीं हैं। बस बहुत से developers इस fixed mindset में फँसे हैं कि “इन्हें ज़रूर इस्तेमाल करना ही होगा”
    • साधारण marketing page के लिए यह संभव है, लेकिन अगर app में बहुत features हों तो कई बार dependencies ज़रूरी हो जाती हैं
      उदाहरण के लिए, मैं ऐसे site बनाता हूँ जिनमें map features बहुत होते हैं, इसलिए mapbox/maplibre/openlayers जैसी ऐसी libraries इस्तेमाल करनी पड़ती हैं जिनका कोई असली विकल्प नहीं है
    • मैंने 2022 में इसी तरीके से एक project किया था, और CVE या version migration से जुड़ी कोई समस्या बिल्कुल नहीं आई
      client को भी migration cost पर एक पैसा खर्च नहीं करना पड़ा
    • component rendering आसान है, लेकिन framework का असली core model की reactive updates देना है
      इस लेख की तरह, यह जानने की जिज्ञासा है कि model updates को कैसे handle किया जाता है
    • लगभग 20 साल से JS के साथ काम कर रहा हूँ, और आख़िरकार मैं इस तरीके पर आकर रुका हूँ कि बस minimum dependencies रखो और बाकी चीज़ें ख़ुद बनाओ
      उल्टा large codebase को कम लोगों के साथ maintain करना और आसान हो गया है
      आजकल के tools की वजह से पहले की तुलना में ख़ुद implementation करना बहुत आसान हो गया है, और यह agentic engineering के साथ भी अच्छी तरह फिट बैठता है
  • लेख अच्छी तरह लिखा गया है, भावनात्मक हुए बिना समस्या को साफ़-साफ़ समझाता है
    मुझे लगता है कि JS के पास ठीक-ठाक standard library न होना इस स्थिति की एक वजह है

    • आजकल JS standard library काफ़ी बड़ी हो चुकी है, तो जानना चाहूँगा कि आपको अभी कौन-सी functionality की कमी लगती है
    • मुझे तो उल्टा तीखे लेख (rant) पसंद हैं। इससे लोगों की भावनाएँ ही नहीं, उनके पीछे की वजह भी समझने में मदद मिलती है
  • लेख अच्छा है, लेकिन मुझे लगता है कि समस्या की जड़ अनावश्यक जोड़ (=bloat) ही है
    मैं Saint-Exupéry की इस बात को उद्धृत करना चाहूँगा: “पूर्णता तब नहीं आती जब जोड़ने के लिए कुछ न बचे, बल्कि तब आती है जब हटाने के लिए कुछ न बचे”
    ज़्यादातर software इस सवाल से नहीं लिखे जाते कि “इसे और elegant कैसे बनाएँ?”, बल्कि इस तरह लिखे जाते हैं कि “इसमें और आसानी से क्या जोड़ा जा सकता है?”
    जवाब हमेशा npm i more-stuff होता है

    • यह Kurt Vonnegut के writing rule की याद दिलाता है: “हर sentence या तो character को उजागर करे या action को आगे बढ़ाए”
      Demosthenes और Cicero के contrast की तरह, वही code अच्छा है जिसमें कुछ भी और हटाया न जा सके
    • हर software में कुछ न कुछ अनावश्यक हिस्सा होता है, लेकिन npm packages और webapps में यह ख़ास तौर पर ज़्यादा है
      JS को अतीत और भविष्य दोनों तरह के browser compatibility का ध्यान रखना पड़ता है, और UI-centric language होने की वजह से accessibility, internationalization, mobile support वगैरह से आकार बढ़ता जाता है
  • कई मामलों में यह छिपे हुए technical debt की समस्या लगती है
    compile target को ESx तक न बढ़ाना, और packages या implementation को update न करना इसका कारण है
    ES5 को सभी browsers में supported हुए अब 13 साल हो चुके हैं (caniuse.com/es5)

    • असल में कुछ लोग पुराने JS engines को support करना चाहते हैं, और कुछ लोग ढेर सारे mini packages बनाते हैं
      दोनों ही अपनी हरकतों को एक feature मानते हैं, और कई popular packages maintain करते हैं
      इसलिए बदलाव मुश्किल है। कभी-कभी community आलोचना करती है, लेकिन उनके पास भी अपनी-अपनी दलीलें होती हैं
    • ES6 से नीचे की compatibility बनाए रखने की ज़िद अजीब लगती है
      Babel से पुराने version में transpile करने पर code फूल जाता है और धीमा हो जाता है, और फिर भी पुराने browsers में CSS या JS feature limitations की वजह से वह ठीक से चलता नहीं
      यहाँ तक कि polyfill ने भी कभी-कभी समस्याएँ पैदा की हैं (ऐसा exponent operator polyfill जो BigInt को handle नहीं कर पाया)
    • सिर्फ़ पुराने browsers ही नहीं, अजीब browsers को support करना भी ज़रूरी होता है
      consoles, TVs, पुराने Android, iPod touch, Facebook in-app browser जैसी कई environments मौजूद हैं
      इसलिए मैं सिर्फ़ एक external module रखता हूँ, और बाकी सब transpiler configuration से संभालता हूँ
    • web में “अभी deploy करो, बाद में ठीक कर लेंगे” वाली culture बहुत मज़बूत है, इसलिए पुरानी dependencies लंबे समय तक बनी रहती हैं
    • Angular के design decisions की तरह, कभी-कभी अतीत की architecture आज की inefficiency पैदा करती है
      पहले async tracking के लिए setTimeout वगैरह को override किया जाता था, लेकिन अब signals से इसे काफ़ी सरल तरीके से handle किया जा सकता है
  • मुझे लगता है कुछ package authors download count बढ़ाने के लिए dependency tree को जानबूझकर टुकड़ों में बाँटते हैं
    7 lines वाले package का होना ही बेतुका है। lockfile metadata code से बड़ा होता है
    पहले create-react-app की dependencies में 5% एक ही author के mini packages थे
    has-symbols, is-string, ljharb जैसे उदाहरण हैं

    • जिज्ञासा है कि यह सिर्फ़ ego का मामला है या इसमें सच में कोई फ़ायदा भी है
      जैसे Anthropic, npm download count ज़्यादा रखने वाले open source maintainers को free Claude देता है
    • immich.app/cursed-knowledge वाले लेख की तरह, कुछ लोग “backward compatibility” के नाम पर 50 packages जोड़ देते हैं
    • security के नज़रिए से भी यह गंभीर है। ऐसे हर micro-package से attack surface बढ़ता है
      download count की दौड़ उल्टा जोखिम बढ़ाती है
    • पहले एक मामले में किसी ने organization में घुसकर अपनी package को dependency में जोड़ दिया था ताकि resume के लिए star count बढ़ा सके
    • यह एक cultural issue भी है। JS community में 7-line code को सीधे copy-paste करना “reinventing the wheel” कहकर आलोचना की जाती है
      लेकिन दूसरी cultures में इसे उल्टा अच्छी बात माना जाता है
  • JS ecosystem की आलोचना करने से पहले 30 years of br tags पढ़ना अच्छा रहेगा
    इससे JS और tools की evolution process समझने में मदद मिलती है
    सिर्फ़ यह कहना कि “JS developers ही समस्या हैं” engineering mindset की कमी दिखाता है

    • खराब वास्तविकता को समझने की कोशिश अच्छी बात है, लेकिन हद से ज़्यादा स्वीकार करना defeatism है
      हमें हमेशा बेहतर theory और practice के बारे में सोचना चाहिए
      software की दुनिया बहुत तेज़ी से बदलती है, इसलिए ख़ुद अपनी “fake funeral” करके पुरानी practices छोड़ने की ज़रूरत है
    • मुझे यह लेख developers को दोष देने के बजाय मौजूदा हालत की तार्किक आलोचना करता हुआ लगा
  • मैं 9 साल पुराने Node.js codebase को maintain कर रहा हूँ, और उसमें सिर्फ़ 8 dependencies हैं, वह भी सभी बिना transitive dependencies के
    Node की built-in features को प्राथमिकता देता हूँ, और ज़रूरत के हिस्से ही ख़ुद implement करता हूँ
    अब यह पहले से कहीं ज़्यादा stable है और stress भी कम है
    Deno की standard library भी शानदार है, इसलिए runtime की default features के साथ कुछ ही packages में काफ़ी app बनाया जा सकता है
    JS अगर सावधानी से इस्तेमाल किया जाए तो काफ़ी अच्छी भाषा है

  • is-string जैसे package का cross-realm safety वाला दावा समझ में आता है, लेकिन असल में ऐसी situations बहुत कम होती हैं
    npm ने publish करना बहुत आसान बना दिया, और “module को तोड़कर publish करो” वाली philosophy ज़रूरत से ज़्यादा फैल गई — यही समस्या है
    consumer dependency tree का audit नहीं करते, बस install कर लेते हैं, इसलिए optional cost default cost बन जाती है
    ponyfill की समस्या automation से हल की जा सकती है
    उदाहरण के लिए, ऐसा Renovate-style bot मददगार हो सकता है जो Node LTS versions में पहले से supported features को auto-detect करके हटा दे

  • हमारी internal PWA का सिर्फ़ एक ही principle है:
    Chrome के latest version में upgrade करो। फिर भी समस्या हो तो उसके बाद देखेंगे”

    • अगर internal use के लिए है, तो यह सही approach है। company अगर supported browser तय कर दे तो management आसान हो जाता है
      Safari कम memory इस्तेमाल करता है, यह समझ में आता है, लेकिन policy के स्तर पर standardize करना ज़्यादा efficient है
    • चीज़ों को simple रखना आख़िरकार सबसे बड़ा फ़ायदा देता है
  • “ES3 (IE6/7 स्तर) तक support करना चाहिए” जैसी बात सच में समझना मुश्किल है
    security के लिहाज़ से तो banking sites को भी ऐसे पुराने browsers ब्लॉक कर देने चाहिए

    • ऐसे teams अक्सर वही होती हैं जिन्होंने 2015 के आसपास सेट किया हुआ build tooling आज तक नहीं बदला
      Webpack, Babel, polyfill stack को upgrade करना बड़ा काम है, इसलिए वे उसे वैसे ही छोड़ देते हैं
      यह “अगर टूटा नहीं है तो ठीक मत करो” वाली culture है
    • सच में एक ख़ास व्यक्ति है जो ऐसी पुरानी compatibility की वकालत करता है, और वही कई low-level packages maintain भी करता है
    • संदर्भ के लिए, मैंने यह भी सुना है कि Deutsche Bahn अब भी Windows 3.1 इस्तेमाल करती है