Переопределение конфигурации на уровне пакета
### Механизм переопределения конфигурации в 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 внутри пакета
Эта модель позволяет масштабировать систему трансформации без дублирования конфигурации и без потери контроля над поведением отдельных модулей.