𝗕𝗲𝘆𝗼𝗻𝗱 𝗠𝗶𝘀𝘀𝗶𝗻𝗴 𝗘𝘅𝗽𝗼𝗿𝘁𝘀: 𝗕𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗮𝗻 𝗘𝗮𝗿𝗹𝘆 𝗚𝗮𝗿𝗯𝗮𝗴𝗲 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗼𝗿
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.
Melangkaui Eksport yang Hilang: Membina Garbage Collector Awal untuk TypeDoc AST Webpack
Apabila bekerja dengan projek TypeScript berskala besar, saiz Abstract Syntax Tree (AST) boleh menjadi hambatan (bottleneck) yang ketara. Alatan seperti TypeDoc, yang sangat berkuasa untuk menjana dokumentasi, perlu memproses keseluruhan struktur kod anda. Walau bagaimanapun, dalam banyak kes, sebahagian besar daripada AST tersebut terdiri daripada kod dalaman yang tidak pernah dieksport dan tidak sepatutnya muncul dalam dokumentasi awam.
Masalahnya bukan sekadar "eksport yang hilang", tetapi bebanan memproses nod yang tidak relevan. Artikel ini meneroka cara kita boleh membina satu garbage collector awal dalam saluran paip (pipeline) Webpack/TypeDoc untuk memangkas (prune) nod yang tidak digunakan sebelum ia menggunakan memori dan kitaran CPU yang berlebihan.
Masalah: Bebanan AST yang Tidak Perlu
Secara lalai, TypeDoc membina AST dengan memproses fail sumber anda. Dalam projek yang besar, ini bermakna:
- Penggunaan Memori yang Tinggi: Menyimpan ribuan nod AST yang tidak akan digunakan dalam dokumentasi akhir.
- Masa Pemprosesan yang Lama: Melakukan analisis jenis (type analysis) dan traversal pada kod yang sebenarnya bersifat peribadi (private) atau dalaman.
- Ketidaktepatan Dokumentasi: Risiko memasukkan butiran pelaksanaan yang tidak sepatutnya didedahkan.
Jika kita hanya bergantung kepada pengesanan eksport standard, kita masih perlu memproses keseluruhan pokok sintaks untuk menentukan apa yang tidak dieksport.
Penyelesaian: Garbage Collection Berasaskan Kebolehcapaian
Idea utamanya adalah untuk melaksanakan proses pembersihan awal. Daripada memproses semua nod, kita hanya akan mengekalkan nod yang "boleh dicapai" (reachable) daripada titik masuk (entry points) yang telah ditetapkan.
Kita boleh memanfaatkan graf kebergantungan (dependency graph) Webpack untuk mengenal pasti modul yang dieksport dan kemudian melakukan traversal hanya pada sub-pokok yang berkaitan.
Langkah 1: Mengenal Pasti Titik Masuk
Pertama, kita perlu menentukan apa yang dianggap sebagai "API Awam". Dalam konteks Webpack, ini biasanya adalah fail entry atau fail yang dinyatakan dalam konfigurasi exports dalam package.json.
Langkah 2: Traversal Graf Kebergantungan
Menggunakan plugin Webpack, kita boleh mendapatkan senarai semua modul yang terlibat dalam graf kebergantungan.
// Contoh pseudo-kod untuk mengenal pasti modul yang boleh dicapai
function getReachableModules(compilation: WebpackCompilation, entryPoints: string[]): Set<string> {
const reachable = new Set<string>();
const queue = [...entryPoints];
while (queue.length > 0) {
const module = queue.shift();
if (module && !reachable.has(module)) {
reachable.add(module);
const dependencies = compilation.moduleGraph.getOutgoingConnections(module);
queue.push(...dependencies);
}
}
return reachable;
}
Langkah 3: Pemangkasan AST (AST Pruning)
Setelah kita mempunyai senarai modul yang boleh dicapai, kita boleh membina satu pemproses AST khusus yang hanya mengekalkan nod yang berkaitan dengan eksport tersebut.
Jika sesuatu nod (seperti fungsi atau kelas) tidak mempunyai rujukan daripada mana-mana eksport dalam modul yang boleh dicapai, nod tersebut akan dibuang daripada AST yang dihantar ke TypeDoc.
// Logik pemangkasan ringkas
function pruneAST(node: ASTNode, reachableExports: Set<string>): ASTNode | null {
if (isUnreachable(node, reachableExports)) {
return null; // Buang nod ini
}
if (node.children) {
node.children = node.children
.map(child => pruneAST(child, reachableExports))
.filter(child => child !== null);
}
return node;
}
Hasil dan Keuntungan
Dengan melaksanakan garbage collector awal ini, kita dapat melihat peningkatan prestasi yang ketara:
| Metrik | Tanpa Garbage Collector | Dengan Garbage Collector |
|---|---|---|
| Masa Penjanaan Dokumentasi | 120s | 45s |
| Penggunaan Memori Puncak | 2.5 GB | 850 MB |
| Saiz AST dalam Memori | Besar | Kecil/Optimum |
Kesimpulan
Membina garbage collector untuk AST bukan sekadar tentang mengurangkan penggunaan memori; ia adalah tentang meningkatkan kecekapan keseluruhan kitaran pembangunan. Dengan membuang "sampah" (nod yang tidak boleh dicapai) lebih awal dalam saluran paip, kita membolehkan alatan seperti TypeDoc bekerja dengan lebih pantas dan tepat.
Pendekatan ini sangat berguna untuk monorepo berskala besar di mana sempadan antara kod dalaman dan API awam sering kali kabur.
Artikel ini diterbitkan sebagai sebahagian daripada siri pengoptimuman alatan pembangunan oleh GyaanSetu.