PKG: від магії до архіву – як працював Node.js пакувальник та чому його заархівували

Коли один бінарний файл замінював цілий Node.js runtime — розбираємо внутрішню кухню pkg та причини його “пенсії”

13 січня 2024 року в світі Node.js сталася тиха революція навпаки — команда Vercel заархівувала репозиторій pkg. Інструмент, який дозволяв упакувати весь Node.js проект в один виконуваний файл, офіційно пішов на пенсію. Але перед тим як попрощатися з pkg, давайте розберемо його внутрішню магію та зрозуміємо, чому він став жертвою власного успіху.

Що таке pkg: магія в одному файлі

Уявіть: ваш Node.js проект з усіма залежностями, runtime та асетами — все в одному виконуваному файлі. Не потрібно встановлювати Node.js на цільовій машині, не потрібно npm install — просто запускаєте .exe і все працює.

Саме цю магію і творив pkg — упаковував JavaScript-код, всі node_modules, нативні addon’и та навіть сам Node.js runtime у єдиний standalone executable.

Анатомія pkg: як це працювало всередині

Віртуальна файлова система

Серце pkg — це snapshot filesystem. Під час збірки pkg створював повний знімок вашого проекту та “вшивав” його прямо в executable:

Усі файли з вашого проекту потрапляли у віртуальний шлях /snapshot/ (або C:\snapshot\ на Windows). Це була ізольована файлова система всередині бінарного файла.

Двоїстість файлових систем

Pkg створював цікаву дуальність:

Snapshot FS — для файлів проекту:

Real FS — для зовнішніх файлів:

Bytecode компіляція та захист коду

Pkg не просто копіював JavaScript файли — він компілював їх у V8 bytecode:

Це давало два преимущества:

  • Захист коду — вихідники стали недоступні
  • Швидший старт — bytecode завантажувався швидше за JS

Cross-compilation магія

Pkg дозволяв збирати executable для різних платформ з однієї машини:

Як це працювало? Pkg завантажував готові Node.js бінарники для кожної target-платформи і “вшивав” ваш код у них.

Внутрішня архітектура: від коду до executable

Крок 1: Dependency Traversal

Крок 2: Asset Detection

Крок 3: Virtual FS Creation

Крок 4: Runtime Injection

При запуску executable pkg “підмінював” стандартні Node.js API:

Проблеми, які наростали

Native Modules — головний біль

Нативні addon’и (.node файли) не могли бути упаковані всередину executable. Їх доводилося розміщувати поряд з бінарником — що ломало ідею “одного файла”.

Dynamic Requires

Memory Overhead

Вся віртуальна файлова система завантажувалася в пам’ять при старті. Великі проекти могли “з’їдати” сотні мегабайт RAM.

Debugging Nightmare

Чому pkg заархівували: ідеальний шторм

1. Node.js 21 та Single Executable Applications

Найголовніша причина — Node.js Core Team випустила власне рішення:

Це було рішення на рівні самого runtime, без сторонніх залежностей.

2. Maintenance Burden

Кожна нова версія Node.js вимагала оновлення pkg:

  • Патчі для підтримки нових API
  • Збірка нових базових бінарників
  • Тестування сумісності

3. Serverless Revolution

Команда Vercel зосередилась на serverless-рішеннях, де pkg був не потрібен:

“pkg був створений для контейнерів і не призначений для serverless середовищ”

4. Ecosystem Fragmentation

З’явилися численні форки та альтернативи:

  • @yao-pkg/pkg — найактивніший форк
  • ncc — для bundling без runtime
  • esbuild + Node.js SEA — сучасний стек

Спадщина pkg: що залишилося

Community Forks

Спільнота не дала pkg померти:

Архітектурні рішення

Багато ідей pkg перекочували в Node.js SEA:

  • Віртуальна файлова система
  • Asset bundling
  • Cross-platform builds

Уроки для індустрії

1. Тимчасовість інструментів Навіть популярні інструменти можуть стати legacy за одну ніч.

2. Community vs Corporate Open source проекти можуть “вижити” завдяки форкам та спільноті.

3. Официал wins Коли офіційний runtime додає функціонал, сторонні рішення втрачають сенс.

Альтернативи у 2024: що замість pkg?

Node.js SEA (Recommended)

esbuild + SEA

Community Forks

Висновок: кінець ери, початок нової

Pkg був піонером, який показав можливість “standalone Node.js apps”. Його архівування — не поразка, а природна еволюція. Коли платформа достатньо розвивається, сторонні інструменти або інтегруються в core, або відходять в історію.

Урок для розробників: не бійтеся експериментувати з інструментами, але будьте готові до змін. Те, що працює сьогодні, може стати legacy завтра.

P.S. Якщо у вас є проекти на pkg — час планувати міграцію на Node.js SEA або community forks. Магія упаковки нікуди не поділася, просто змінилася форма заклинання.

Pkg мертвий. Хай живе pkg! 🎭

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *