Переопределение конфигурации на уровне пакета

### Механизм переопределения конфигурации в SWC на уровне пакета В монорепозиториях и многоуровневых JavaScript-проектах базовая конфигурация транспилятора часто оказывается недостаточной. Разные пакеты могут требовать различного уровня трансформаций: один модуль ориентирован на Node.js с современными возможностями ECMAScript, другой — на старые браузеры, третий — на специфические ограничения окружения. SWC предоставляет механизм переопределения конфигурации, позволяющий задавать поведение трансформации на уровне отдельных пакетов без дублирования всей конфигурации. --- ### Базовая модель конфигурации SWC SWC использует файл конфигурации `.swcrc`, который описывает глобальные правила трансформации: * параметры компиляции JavaScript/TypeScript (`jsc`) * настройки модулей (`module`) * target окружения * опции минификации * source maps Пример базовой структуры: ```json { "jsc": { "parser": { "syntax": "typescript", "tsx": true }, "target": "es2020" }, "module": { "type": "es6" } } ``` Эта конфигурация применяется ко всему проекту, если не задано иное поведение через механизмы переопределения. --- ### Переопределение через `overrides` Ключевой механизм пакетного управления конфигурацией SWC — поле `overrides`. Оно позволяет определять набор правил, которые применяются только к определённым файлам или пакетам в зависимости от условий сопоставления. Структура `overrides` представляет собой массив правил: ```json { "jsc": { "target": "es2020" }, "overrides": [ { "test": "./packages/legacy/**", "jsc": { "target": "es5" } } ] } ``` #### Логика применения Каждое правило содержит: * `test` — путь или glob-шаблон * `exclude` — исключения * частичную конфигурацию SWC, которая перекрывает базовую SWC применяет первое совпадение по маршрутизации файлов, после чего объединяет конфигурацию по принципу глубокого слияния. --- ### Пакетный уровень в монорепозитории В монорепозиториях (например, pnpm, Yarn Workspaces, Turborepo) часто используется стратегия изоляции конфигурации на уровне пакетов. Каждый пакет может содержать собственный `.swcrc`, при этом общий конфиг хранится в корне. Структура: ``` /repo .swcrc /packages /ui .swcrc /server .swcrc /legacy .swcrc ``` SWC выбирает конфигурацию по ближайшему `.swcrc`, если он найден в директории пакета. Это поведение позволяет полностью разделить правила трансформации. --- ### Иерархия конфигураций При запуске компиляции SWC учитывает несколько уровней: 1. Глобальный `.swcrc` в корне проекта 2. Локальный `.swcrc` внутри пакета 3. Переопределения через `overrides` 4. Внешние инструменты (webpack, Next.js, Vite плагин SWC) При конфликте приоритет определяется следующим образом: * локальный конфиг пакета имеет более высокий приоритет, чем глобальный * `overrides` внутри пакета перекрывают базовые настройки этого пакета * конфигурации сборщика могут дополнительно модифицировать результат --- ### Изоляция конфигурации для разных целей Типичная задача — разделить современные и устаревшие пакеты. #### Современный пакет ```json { "jsc": { "target": "es2022", "parser": { "syntax": "typescript" } }, "module": { "type": "es6" } } ``` #### Устаревший пакет ```json { "jsc": { "target": "es5" }, "module": { "type": "commonjs" } } ``` Такая изоляция позволяет избегать избыточных транспиляций и сохранять оптимальный баланс между совместимостью и производительностью. --- ### Использование `exclude` для контроля границ пакета Помимо `test`, важную роль играет `exclude`. Он позволяет исключать файлы даже внутри совпавших пакетов: ```json { "overrides": [ { "test": "./packages/shared/**", "exclude": "**/*.spec.ts", "jsc": { "target": "es2020" } } ] } ``` Это особенно важно в пакетах, содержащих тестовые и вспомогательные файлы, которые не должны подвергаться одинаковым трансформациям. --- ### Слияние конфигураций (deep merge) SWC использует глубокое слияние объектов конфигурации. Это означает, что переопределение может быть частичным: ```json { "jsc": { "parser": { "syntax": "typescript", "tsx": true }, "target": "es2020" }, "overrides": [ { "test": "./packages/mobile/**", "jsc": { "target": "es5" } } ] } ``` В этом случае: * `parser` остаётся неизменным * `target` заменяется только для совпавших файлов Такой подход исключает необходимость повторного описания всей структуры `jsc` в каждом override. --- ### Конфигурация на уровне package.json Некоторые сборочные пайплайны позволяют размещать SWC-конфигурацию прямо в `package.json`, что удобно для изолированных пакетов: ```json { "name": "ui", "swc": { "jsc": { "target": "es2021" } } } ``` Хотя такой способ менее распространён, он упрощает интеграцию в небольших пакетах и снижает количество конфигурационных файлов. --- ### Переопределение в зависимости от окружения Часто пакетная конфигурация комбинируется с переменными окружения: * development * production * test Пример: ```json { "env": { "development": { "jsc": { "minify": { "compress": false } } }, "production": { "jsc": { "minify": { "compress": true } } } } } ``` Хотя `env` не является строго пакетным механизмом, он часто используется совместно с `overrides`, формируя многоуровневую систему конфигурации. --- ### Монорепозиторные стратегии с SWC В крупных проектах применяются комбинированные подходы: 1. Общий `.swcrc` задаёт базовые правила 2. Каждый пакет имеет локальный `.swcrc` 3. Для групп пакетов используются `overrides` 4. Специальные пакеты (legacy, experimental) получают полностью изолированные конфигурации Пример гибридной структуры: ```json { "jsc": { "target": "es2020" }, "overrides": [ { "test": "./packages/legacy/**", "jsc": { "target": "es5", "minify": { "compress": true } } }, { "test": "./packages/experimental/**", "jsc": { "target": "esnext" } } ] } ``` --- ### Влияние порядка и конфликтов правил Порядок `overrides` критически важен. При совпадении нескольких правил применяется первое подходящее совпадение или результат последовательного слияния в зависимости от контекста запуска SWC. Неправильное расположение правил может привести к: * неожиданной транспиляции в более старый стандарт * потере оптимизаций * несогласованности между пакетами Поэтому правила обычно группируются от наиболее специфичных к общим или наоборот, в зависимости от выбранной стратегии конфигурации. --- ### Изоляция типов трансформаций внутри пакета Пакетная конфигурация часто разделяется по назначению: * runtime-код * тесты * сборочные скрипты * утилиты Пример: ```json { "overrides": [ { "test": "**/runtime/**", "jsc": { "target": "es2020" } }, { "test": "**/*.test.ts", "jsc": { "target": "es2018" } } ] } ``` Такой подход снижает избыточность трансформации и ускоряет сборку. --- ### Совместимость с внешними сборщиками При использовании SWC через: * Next.js * Vite * Webpack (swc-loader) * esbuild-bridge сценарии конфигурация пакетов может быть переопределена на уровне сборщика. Это создаёт дополнительный слой, который может: * игнорировать `.swcrc` * частично переопределять `jsc` * внедрять собственные presets Поэтому пакетная конфигурация должна учитывать возможные внешние перекрытия и не полагаться исключительно на локальные настройки. --- ### Практическая модель управления пакетами В зрелых проектах применяется модель трёх уровней: * глобальная конфигурация SWC * пакетная конфигурация * файловые overrides внутри пакета Эта модель позволяет масштабировать систему трансформации без дублирования конфигурации и без потери контроля над поведением отдельных модулей.