• 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 की समीक्षा करके पूछना चाहिए: “यह क्यों ज़रूरी है?”
  • सफाई सब मिलकर कर सकते हैं

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.