𝗕𝗲𝘆𝗼𝗻𝗱 𝗠𝗶𝘀𝘀𝗶𝗻𝗴 𝗘𝘅𝗽𝗼𝗿𝘁𝘀: 𝗕𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗮𝗻 𝗘𝗮𝗿𝗹𝘆 𝗚𝗮𝗿𝗯𝗮𝗴𝗲 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗼𝗿

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:

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.

Більше ніж просто відсутні експорти: створення раннього збирача сміття для AST TypeDoc у Webpack

Коли ми говоримо про оптимізацію бандлів, ми зазвичай маємо на увазі "tree shaking" — процес видалення невикористаного коду. Але що, якби ми могли застосувати цей принцип не до самого коду, а до абстрактного синтаксичного дерева (AST), яке використовує TypeDoc?

У цій статті я розповім про те, як я розробив механізм "раннього збирача сміття" (early garbage collector) для AST, що генерується TypeDoc під час роботи з Webpack.

Проблема з AST TypeDoc

TypeDoc створює детальне AST для вашого проєкту, щоб генерувати документацію. Проте, коли проєкт стає великим, це AST стає величезним. Проблема полягає в тому, що TypeDoc часто включає в це дерево символи, які насправді не використовуються або не експортуються. Це призводить до зайвого споживання пам'яті та уповільнення процесу збірки, особливо коли плагіни Webpack мають обробляти це дерево.

Ідея: Ранній збирач сміття

Замість того, щоб чекати, поки Webpack зробить свою магію під час tree shaking, ми можемо очистити AST ще на етапі його створення. Моя ідея полягала в тому, щоб реалізувати простий механізм збирання сміття, який працює безпосередньо з вузлами AST.

Реалізація

Я використав підхід, схожий на класичний алгоритм Mark-and-Sweep:

  1. Позначення (Mark): Ми починаємо з точок входу (експортів) і рекурсивно проходимо по дереві, позначаючи всі вузли, до яких ми можемо дістатися.
  2. Очищення (Sweep): Ми проходимо по всьому дереву ще раз і видаляємо всі вузли, які не були позначені як досяжні.

Як це працює на практиці

Процес починається з ідентифікації кореневих вузлів — тих, що є публічними експортами вашого модуля. Потім ми обходимо дерево, відстежуючи всі посилання на символи, типи та інші елементи, що використовуються цими експортами. Все інше — це "сміття", яке можна видалити.

// Спрощений приклад логіки обходу
function markReachable(node: ASTNode) {
  if (node.isMarked) return;
  node.isMarked = true;
  
  for (const child of node.references) {
    markReachable(child);
  }
}

function sweepUnreachable(root: ASTNode) {
  // Видалення вузлів, які не мають позначки isMarked
}

Результати

Завдяки цьому підходу ми змогли значно зменшити розмір AST перед тим, як він потрапляє в основний конвеєр Webpack. Це призвело до:

Висновок

Створення раннього збирача сміття для AST — це лише початок. Оптимізація на рівні структури даних, таких як AST, може дати значний приріст продуктивності в складних інструментах збірки. У майбутньому можна додати ще більше інтелектуальних правил для обрізки дерева, щоб зробити процес ще ефективнішим.