𝗕𝗲𝘆𝗼𝗻𝗱 𝗠𝗶𝘀𝘀𝗶𝗻𝗴 𝗘𝘅𝗽𝗼𝗿𝘁𝘀: 𝗕𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗮𝗻 𝗘𝗮𝗿𝗹𝘆 𝗚𝗮𝗿𝗯𝗮𝗴𝗲 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗼𝗿
I tried to use a standard plugin to fix missing links in Webpack documentation. It failed.
Integrating a plugin into a large codebase is not a simple task. It became an architectural challenge. I had to manage Abstract Syntax Tree (AST) manipulation, memory use, and recursive loops.
The Problem with Standard Plugins
I ran three experiments to find a solution.
Experiment 1: The plugin recovered 135 types. However, it put them in an internal module. Our tool created a separate folder for them. We had to sort them manually. The documentation was also structurally wrong.
Experiment 2: I turned on a setting to hide external types. This worked for some things. It reduced the payload to 60 Webpack types. But TypeDoc ignored nested dependencies. It left many types hidden while they still used memory.
Experiment 3: I tried to map types back to their original modules. This caused a recursive loop. The plugin kept extracting nested interfaces until it created 630 types. The documentation was full of noise. It ruined the user experience.
The Solution: Early Garbage Collection
I needed the types in their correct modules without the extra noise. I stopped trying to fix the output and started fixing the process.
I used a hook called EVENT_RESOLVE_END. This let me intercept the AST right after resolution. I did this before TypeDoc assigned categories or used heavy memory.
My logic followed three steps:
- Find the internal module in the AST.
- Check every node using a custom utility.
- Delete the noise. I used project.removeReflection to delete 300 unneeded nodes immediately. This let Node.js free the memory.
- Move the important types. I merged the remaining 300 types into the root scope.
The result: I saved 240 vital types. They are now visible and correctly routed. I avoided the recursive noise of the third experiment.
Lessons Learned
• Handle ASTs early. Removing unneeded nodes prevents memory waste later. • Use hooks instead of hacks. Understanding the compiler lifecycle allows for clean work. • Feedback improves architecture. Maintainer reviews helped me build a better system. • More data is not better. Good engineering means finding the balance between data and usability.
"Missing Exports"-ന് അപ്പുറം: Webpack-ന്റെ TypeDoc AST-യ്ക്കായി ഒരു ആദ്യഘട്ട ഗാർബേജ് കളക്ടർ നിർമ്മിക്കുന്നു
വലിയ തോതിലുള്ള TypeScript ആപ്ലിക്കേഷനുകൾ വികസിപ്പിക്കുമ്പോൾ, ഉപയോഗിക്കാത്ത എക്സ്പോർട്ടുകൾ (unused exports) കൈകാര്യം ചെയ്യുന്നത് ഒരു പ്രധാന വെല്ലുവിളിയായി മാറുന്നു. ഇവ ഡോക്യുമെന്റേഷനിൽ ഉൾപ്പെടുന്നത് ഡോക്യുമെന്റേഷന്റെ ഗുണനിലവാരത്തെ ബാധിക്കുകയും ഡെവലപ്പർമാരെ ആശയക്കുഴപ്പത്തിലാക്കുകയും ചെയ്യുന്നു.
സാധാരണയായി, നമ്മൾ "Missing Exports" എന്ന പ്രശ്നത്തെക്കുറിച്ചാണ് സംസാരിക്കാറുള്ളത്—അതായത്, ഒരു ഫംഗ്ഷനോ ക്ലാസ്സോ നിർമ്മിച്ചെങ്കിലും അത് എക്സ്പോർട്ട് ചെയ്യാൻ മറന്നുപോയി എന്ന്. എന്നാൽ ഇതിനേക്കാൾ വലിയൊരു പ്രശ്നം, അനാവശ്യമായ എക്സ്പോർട്ടുകൾ ഡോക്യുമെന്റേഷനിൽ നിറഞ്ഞുനിൽക്കുന്നതാണ്.
പ്രശ്നം: TypeDoc-ന്റെ സ്വഭാവം
TypeDoc പോലുള്ള ടൂളുകൾ കോഡ് വിശകലനം ചെയ്യുമ്പോൾ, അവ കോഡിലെ എല്ലാ എക്സ്പോർട്ടുകളും ഡോക്യുമെന്റ് ചെയ്യാൻ ശ്രമിക്കുന്നു. TypeDoc-ന് ഒരു എക്സ്പോർട്ട് ഉപയോഗിക്കപ്പെടുന്നുണ്ടോ ഇല്ലയോ എന്ന് തിരിച്ചറിയാനുള്ള കഴിവില്ല. ഇത് ഫലമായി, പ്രോജക്റ്റിലെ "Dead Code" പോലും ഡോക്യുമെന്റേഷന്റെ ഭാഗമായി മാറുന്നു.
ഇത് രണ്ട് രീതിയിൽ ദോഷകരമാണ്:
- അമിതമായ വിവരങ്ങൾ: ഡോക്യുമെന്റേഷൻ വായിക്കുന്നവർക്ക് പ്രസക്തമല്ലാത്ത വിവരങ്ങൾ കാണേണ്ടി വരുന്നു.
- അവ്യക്തത: ഒരു എക്സ്പോർട്ട് ഉപയോഗിക്കാമോ ഇല്ലയോ എന്ന കാര്യത്തിൽ ഡെവലപ്പർമാർക്ക് സംശയം ഉണ്ടാകുന്നു.
പരിഹാരം: ഒരു ആദ്യഘട്ട ഗാർബേജ് കളക്ടർ (Early Garbage Collector)
ഈ പ്രശ്നം പരിഹരിക്കാൻ, TypeDoc AST (Abstract Syntax Tree) പ്രോസസ്സ് ചെയ്യുന്നതിന് മുമ്പ് തന്നെ ഉപയോഗിക്കാത്ത എക്സ്പോർട്ടുകൾ നീക്കം ചെയ്യുന്ന ഒരു ടൂൾ നിർമ്മിക്കുക എന്നതാണ് എന്റെ ലക്ഷ്യം. ഇതിനെ നമുക്ക് ഒരു "ഗാർബേജ് കളക്ടർ" എന്ന് വിളിക്കാം.
ഈ ടൂൾ Webpack-ന്റെ മൊഡ്യൂൾ ഗ്രാഫ് (Module Graph) ഉപയോഗിച്ചാണ് പ്രവർത്തിക്കുന്നത്. Webpack-ന് കോഡിലെ എല്ലാ ഡിപെൻഡൻസികളും കൃത്യമായി അറിയാം. ഏതെല്ലാം ഫയലുകൾ തമ്മിൽ ബന്ധപ്പെട്ടിരിക്കുന്നു എന്നും, ഏതെല്ലാം എക്സ്പോർട്ടുകളാണ് ഇംപോർട്ട് ചെയ്തിട്ടുള്ളതെന്നും Webpack-ന് അറിയാം.
പ്രവർത്തന രീതി
ഈ ഗാർബേജ് കളക്ടർ പ്രധാനമായും മൂന്ന് ഘട്ടങ്ങളിലൂടെയാണ് പ്രവർത്തിക്കുന്നത്:
- Dependency Analysis: Webpack-ന്റെ
compilation.moduleGraphഉപയോഗിച്ച് പ്രോജക്റ്റിലെ എല്ലാ ഇംപോർട്ടുകളും വിശകലനം ചെയ്യുന്നു. ഇതിലൂടെ ഏതൊക്കെ എക്സ്പോർട്ടുകളാണ് യഥാർത്ഥത്തിൽ ഉപയോഗിക്കപ്പെടുന്നത് എന്ന് നമ്മൾ കണ്ടെത്തുന്നു. - AST Transformation: കോഡിന്റെ AST നിർമ്മിക്കുന്നു.
- Pruning (കീറിക്കളയൽ): ഡിപെൻഡൻസി ഗ്രാഫിൽ ഇല്ലാത്ത (അതായത് ഉപയോഗിക്കാത്ത) എക്സ്പോർട്ടുകളെ AST-യിൽ നിന്ന് നീക്കം ചെയ്യുന്നു.
ഇത് ചെയ്യുന്നതിലൂടെ, TypeDoc-ന് ലഭിക്കുന്ന AST കൂടുതൽ ശുദ്ധവും (clean) പ്രസക്തവുമാകുന്നു.
നടപ്പിലാക്കൽ (Implementation)
Webpack പ്ലഗിൻ ആയിട്ടാണ് ഇത് പ്രവർത്തിക്കുന്നത്. താഴെ പറയുന്ന രീതിയിൽ നമുക്ക് ഇത് നടപ്പിലാക്കാം:
// ഒരു ലളിതമായ ഉദാഹരണം
compiler.hooks.compilation.tap('EarlyGarbageCollector', (compilation) => {
const moduleGraph = compilation.moduleGraph;
for (const module of moduleGraph.getModules()) {
// ഓരോ മൊഡ്യൂളും പരിശോധിക്കുക
// ഉപയോഗിക്കാത്ത എക്സ്പോർട്ടുകൾ കണ്ടെത്തുക
// AST-യിൽ നിന്ന് അവ നീക്കം ചെയ്യുക
}
});
ഈ പ്രക്രിയ നടക്കുന്നത് Webpack ബിൽഡ് ചെയ്യുന്ന സമയത്താണ്. അതിനാൽ, TypeDoc റൺ ചെയ്യുന്നതിന് മുമ്പ് തന്നെ അനാവശ്യമായ എക്സ്പോർട്ടുകൾ നീക്കം ചെയ്യപ്പെടുന്നു എന്ന് നമുക്ക് ഉറപ്പാക്കാം.
ഉപസംഹാരം
"Missing Exports" എന്നതിലുപരി, "Unnecessary Exports" എന്ന പ്രശ്നമാണ് പലപ്പോഴും വലിയ പ്രോജക്റ്റുകളിൽ ഉണ്ടാകുന്നത്. ഒരു ആദ്യഘട്ട ഗാർബേജ് കളക്ടർ ഉപയോഗിക്കുന്നതിലൂടെ, ഡോക്യുമെന്റേഷൻ കൂടുതൽ കൃത്യവും ഉപയോഗപ്രദവുമാക്കാൻ സാധിക്കും. ഇത് ഡെവലപ്പർമാരുടെ ഉൽപ്പാദനക്ഷമത വർദ്ധിപ്പിക്കുകയും ഡോക്യുമെന്റേഷൻ കൈകാര്യം ചെയ്യുന്നത് എളുപ്പമാക്കുകയും ചെയ്യുന്നു.