Parcel как программный API

Parcel предоставляет программный API, позволяющий управлять процессом сборки напрямую из Node.js-кода без использования CLI. Этот подход применяется в сценариях, где требуется динамическая конфигурация сборки, интеграция с серверными процессами, кастомные пайплайны или запуск bundling как части более крупной системы.

Программный интерфейс Parcel построен вокруг нескольких ключевых сущностей:

  • Bundler/Compiler — основной объект, отвечающий за сборку проекта
  • Options — конфигурация окружения и входных точек
  • Graph — внутренняя модель зависимостей
  • Watcher — механизм отслеживания изменений файлов
  • Reporter — система событий сборки

В современных версиях Parcel основным объектом является Parcel, который объединяет функциональность компиляции и наблюдения за изменениями.

Создание экземпляра компилятора

Программный API начинается с инициализации компилятора через конструктор Parcel.

import { Parcel } from "@parcel/core";

const bundler = new Parcel({
  entries: "src/index.html",
  defaultConfig: "@parcel/config-default",
  mode: "development",
  shouldDisableCache: false,
  hmrOptions: {
    port: 1234
  }
});

Ключевое значение имеет параметр entries. Он определяет точку входа графа зависимостей. Parcel автоматически анализирует HTML, JavaScript, CSS и другие ресурсы, строя дерево зависимостей.

Сборка проекта через API

Одноразовая сборка выполняется через метод run().

const { bundleGraph, buildTime } = await bundler.run();

bundleGraph.getBundles().forEach(bundle => {
  console.log(bundle.filePath);
});

console.log(`Build completed in ${buildTime}ms`);

Метод run() инициирует полный цикл:

  1. Построение dependency graph
  2. Трансформация модулей через трансформеры
  3. Синтез бандлов
  4. Запись результата на диск

Результатом является BundleGraph, который отражает структуру финальной сборки.

Работа с графом бандлов

BundleGraph — центральная структура данных, описывающая результат компиляции.

Основные операции:

const bundles = bundleGraph.getBundles();
const entryBundles = bundleGraph.getEntryBundles();
const childBundles = bundleGraph.getChildBundles(bundle);

Каждый bundle содержит:

  • список модулей
  • путь вывода
  • тип (js, css, html)
  • зависимости

Граф позволяет анализировать структуру сборки без обращения к файловой системе.

Режим наблюдения за изменениями

Для разработки используется watch-режим:

const subscription = await bundler.watch((err, event) => {
  if (err) {
    console.error(err);
    return;
  }

  if (event.type === "buildSuccess") {
    const bundles = event.bundleGraph.getBundles();
    bundles.forEach(b => console.log("Updated:", b.filePath));
  }

  if (event.type === "buildFailure") {
    console.error(event.diagnostics);
  }
});

Watch API реализует непрерывный цикл сборки. При изменении файлов Parcel пересчитывает только затронутые части графа, используя инкрементальную модель.

Инкрементальная компиляция

Одной из ключевых особенностей программного API является кэширование на уровне модулей.

Каждый модуль имеет:

  • хеш исходного кода
  • список зависимостей
  • результат трансформации

При изменении файла Parcel сравнивает хеши и пересобирает только затронутые узлы графа, минимизируя время пересборки.

Конфигурация через API

В отличие от CLI, программный API позволяет динамически изменять конфигурацию:

const bundler = new Parcel({
  entries,
  mode: process.env.NODE_ENV,
  targets: {
    main: {
      context: "browser",
      distDir: "./dist",
      sourceMap: true
    }
  }
});

Параметр targets управляет выходными артефактами. Можно определить несколько целей сборки с разными настройками.

Управление ассетами

Ассеты в Parcel представляют собой абстракцию файлов.

const assets = bundle.getAssets();

assets.forEach(asset => {
  console.log(asset.type);
  console.log(asset.filePath);
});

Каждый asset проходит цепочку трансформаций:

  • parser
  • transformer
  • optimizer
  • packager

Эта цепочка может быть расширена через плагины.

Интеграция с пользовательскими пайплайнами

Программный API позволяет встраивать Parcel в собственные системы сборки:

async function buildProject() {
  const bundler = new Parcel({
    entries: "./src/index.html",
  });

  const { bundleGraph } = await bundler.run();

  const bundles = bundleGraph.getBundles();

  return bundles.map(b => ({
    path: b.filePath,
    size: b.stats?.size
  }));
}

Такой подход используется в серверных приложениях, CI/CD и автоматизированных системах деплоя.

Обработка ошибок и диагностика

Parcel возвращает структурированные диагностические сообщения:

if (event.type === "buildFailure") {
  event.diagnostics.forEach(d => {
    console.log(d.message);
    console.log(d.hints);
    console.log(d.codeFrames);
  });
}

Диагностика включает:

  • сообщение об ошибке
  • контекст кода
  • подсказки по исправлению
  • стек модулей

Hot Module Replacement через API

HMR интегрирован в watch-режим и доступен через события сборки:

if (event.type === "buildSuccess") {
  if (event.changedAssets.length > 0) {
    console.log("HMR updates available");
  }
}

Parcel формирует HMR-граф, определяя минимальный набор модулей, требующих обновления без перезагрузки страницы.

Расширение через плагины

Программный API тесно связан с системой плагинов. Плагины могут вмешиваться в:

  • парсинг
  • трансформацию
  • генерацию кода
  • оптимизацию

Пример подключения кастомного конфигурационного плагина:

new Parcel({
  entries: "src/index.html",
  defaultConfig: "@parcel/config-default"
});

Плагины подключаются через конфигурацию и влияют на весь граф компиляции.

Управление жизненным циклом компилятора

Экземпляр Parcel поддерживает явное завершение работы:

const watcher = await bundler.watch(callback);

// завершение
await watcher.unsubscribe();

Это важно для серверных приложений, где утечки наблюдателей приводят к росту потребления памяти.

Параллелизм и производительность

Parcel использует многопоточную архитектуру:

  • worker threads для трансформаций
  • параллельную обработку ассетов
  • ленивую загрузку зависимостей

Программный API не требует ручного управления потоками, но поведение можно косвенно контролировать через конфигурацию кэша и targets.

Взаимодействие с файловой системой

Parcel абстрагирует доступ к файлам через собственный FS-слой:

  • кеширование чтения
  • отслеживание изменений
  • виртуальные модули

Это позволяет запускать сборку в нестандартных окружениях, включая in-memory FS или контейнеры CI.

Использование в серверных приложениях

Типичный сценарий — интеграция с Node.js сервером:

import express from "express";
import { Parcel } from "@parcel/core";

const app = express();

const bundler = new Parcel({
  entries: "./src/index.html"
});

app.get("/build", async (req, res) => {
  const { bundleGraph } = await bundler.run();

  res.json(
    bundleGraph.getBundles().map(b => b.filePath)
  );
});

app.listen(3000);

Такой подход позволяет динамически инициировать сборку по запросу.

Метрики и профилирование

Parcel предоставляет доступ к статистике сборки:

const { buildTime, inputCount, totalAssetSize } = await bundler.run();

console.log(buildTime);

Эти данные используются для оптимизации пайплайнов и выявления узких мест в проекте.