Файл .parcelrc: структура и синтаксис

Файл конфигурации .parcelrc используется Parcel для управления внутренними этапами сборки: преобразованием модулей, разрешением зависимостей, оптимизацией, минификацией и формированием итогового бандла. Это ключевой механизм расширения поведения сборщика без изменения исходного кода проекта.

Базовая структура файла

.parcelrc представляет собой JSON-подобный файл, в котором описываются пайплайны (pipelines) и подключаемые плагины. Формально это JSON, допускающий расширенную конфигурацию через Parcel plugin system.

Минимальная структура:

{
  "extends": "@parcel/config-default"
}

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


Основные концепции конфигурации

Parcel строит сборку как последовательность этапов обработки модулей. Каждый этап управляется определённым типом плагинов:

  • resolver — отвечает за поиск и разрешение модулей
  • transformer — преобразует исходный код (например, Babel, TypeScript)
  • bundler — формирует граф бандлов
  • namer — задаёт имена выходных файлов
  • runtime — добавляет runtime-логику Parcel
  • optimizer — выполняет финальную оптимизацию (minify, tree-shaking)
  • packager — собирает код в финальный формат файла
  • reporter — обрабатывает события сборки и выводит информацию

Эти сущности объединяются в pipelines.


Pipelines: основа .parcelrc

Pipeline — это последовательность обработчиков для конкретного типа ресурсов.

Структура pipeline:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.ts": ["@parcel/transformer-typescript-tsc"]
  }
}

Однако более гибкий способ — использование расширенной структуры:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.{js,jsx}": [
      "@parcel/transformer-babel",
      "@parcel/transformer-js"
    ],
    "*.css": [
      "@parcel/transformer-postcss"
    ]
  }
}

Каждый ключ — это glob-паттерн, определяющий тип файлов, а значение — массив плагинов, выполняемых последовательно.


Transformer: синтаксис и порядок выполнения

Transformers применяются к исходным модулям до их включения в граф зависимостей.

Пример цепочки трансформации Jav * aScript:

{
  "transformers": {
    "*.js": [
      "@parcel/transformer-babel",
      "@parcel/transformer-js"
    ]
  }
}

Порядок имеет критическое значение:

  1. первый трансформер выполняет предварительную обработку (например, Babel)
  2. следующий приводит код к внутреннему формату Parcel

Ошибочная перестановка может привести к некорректной компиляции или потере синтаксических преобразований.


Resolver: управление разрешением модулей

Раздел resolvers определяет, как Parcel ищет зависимости.

{
  "resolvers": [
    "@parcel/resolver-default",
    "@parcel/resolver-glob"
  ]
}

Механизм работает по принципу цепочки ответственности:

  • каждый resolver пытается найти модуль
  • если не удаётся, запрос передаётся следующему

Это позволяет внедрять кастомные стратегии поиска, например:

  • алиасы модулей
  • поддержка монорепозиториев
  • нестандартные пути импорта

Optimizers: постобработка бандлов

Оптимизаторы применяются после упаковки кода.

Пример:

{
  "optimizers": {
    "*.js": [
      "@parcel/optimizer-terser"
    ],
    "*.css": [
      "@parcel/optimizer-cssnano"
    ]
  }
}

Оптимизаторы выполняют:

  • минификацию
  • удаление мёртвого кода
  • сжатие строк
  • оптимизацию структуры AST

Namer: контроль имён выходных файлов

Namer определяет структуру output файлов.

{
  "namers": [
    "@parcel/namer-default"
  ]
}

Возможные сценарии:

  • hash-based naming для кеширования
  • структурирование по директориям
  • разделение по entry points

Пример кастомного поведения:

{
  "namers": [
    "./custom-namer.js"
  ]
}

Packager: финальная сборка

Packager отвечает за объединение модулей в конечный файл.

{
  "packagers": {
    "*.js": "@parcel/packager-js",
    "*.css": "@parcel/packager-css"
  }
}

Он работает после оптимизации и формирует финальный формат:

  • ESM
  • CommonJS
  • IIFE (в зависимости от настроек)

Reporter: события сборки

Reporter используется для наблюдения за процессом сборки.

{
  "reporters": [
    "@parcel/reporter-default",
    "@parcel/reporter-cli"
  ]
}

Он может:

  • выводить логи
  • формировать отчёты
  • интегрироваться с CI/CD
  • собирать метрики сборки

Синтаксис расширения конфигурации

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

{
  "extends": [
    "@parcel/config-default",
    "./parcel.config.base.json"
  ]
}

Приоритет правил:

  1. локальная конфигурация
  2. конфигурации из extends (слева направо)
  3. дефолтные настройки Parcel

Глобальные паттерны и соответствие файлов

Все секции, работающие с файлами, используют glob-выражения:

  • *.js — все JS файлы в директории
  • **/*.ts — рекурсивно во всех подпапках
  • *.{js,ts} — несколько расширений
  • !*.test.js — исключение файлов

Пример комбинирования:

{
  "transformers": {
    "*.{js,ts}": ["@parcel/transformer-babel"],
    "**/*.worker.js": ["@parcel/transformer-web-worker"]
  }
}

Приоритеты и порядок обработки

Parcel строго соблюдает порядок выполнения:

  1. Resolver — поиск модулей
  2. Transformer — преобразование кода
  3. Bundler — построение графа
  4. Namer — генерация имён
  5. Packager — упаковка
  6. Optimizer — финальная обработка
  7. Reporter — наблюдение

Изменение порядка возможно только внутри соответствующих цепочек (transformers, optimizers и т.д.), но не между этапами.


Пользовательские плагины

.parcelrc поддерживает подключение локальных модулей.

{
  "transformers": {
    "*.md": ["./transformers/markdown-transformer"]
  }
}

Такой подход используется для:

  • обработки нестандартных форматов (MD, YAML, TOML)
  • интеграции внутренних DSL
  • внедрения экспериментальных трансформаций

Сложные конфигурации с несколькими пайплайнами

Для различных типов файлов можно задавать независимые цепочки обработки:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.ts": [
      "@parcel/transformer-typescript-tsc"
    ],
    "*.vue": [
      "@parcel/transformer-vue"
    ],
    "*.scss": [
      "@parcel/transformer-sass"
    ]
  },
  "optimizers": {
    "*.js": [
      "@parcel/optimizer-terser"
    ],
    "*.css": [
      "@parcel/optimizer-cssnano"
    ]
  }
}

Каждая цепочка изолирована и не влияет на другие типы ресурсов.


Особенности синтаксиса и ограничения

Формат .parcelrc имеет ряд ограничений:

  • отсутствует произвольная логика (только декларативная структура)
  • порядок массивов строго определяет последовательность выполнения
  • нельзя смешивать несовместимые плагины в одной цепочке
  • glob-паттерны не должны пересекаться без необходимости

Ошибки конфигурации чаще всего связаны с:

  • неправильным порядком transformers
  • отсутствием базового extends
  • конфликтующими optimizers
  • неверными glob-выражениями

Механизм разрешения конфликтов

При пересечении правил Parcel применяет приоритетность:

  • более специфичный glob имеет приоритет над общим
  • локальные конфигурации перекрывают наследуемые
  • последний плагин в цепочке может переопределять поведение предыдущих

Пример:

{
  "transformers": {
    "*.js": ["A", "B"],
    "src/special/*.js": ["C", "B"]
  }
}

Файлы из src/special будут обрабатываться отдельной цепочкой.


Работа с несколькими конфигурациями

Parcel позволяет комбинировать конфигурации через монорепозитории и разные уровни директорий:

  • глобальный .parcelrc в корне проекта
  • локальный .parcelrc в подпроекте
  • конфигурации пакетов внутри workspace

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