В экосистеме TypeScript файл tsconfig.json традиционно
выступает центральной точкой конфигурации компилятора tsc.
Он определяет правила анализа типов, структуру проекта, пути модулей,
целевую версию JavaScript и множество других параметров, влияющих на
поведение компиляции.
В проектах, где вместо стандартного компилятора используется SWC, роль
tsconfig.json меняется: он перестаёт быть источником
трансформации кода и становится источником метаданных для понимания
структуры TypeScript-проекта, при этом реальная трансформация
управляется через .swcrc.
Такое разделение приводит к важному архитектурному принципу:
tsconfig.json — описание проекта и типизации
.swcrc — описание трансформации кода
SWC изначально спроектирован как высокопроизводительный транспайлер,
который не обязан повторять поведение tsc во всех деталях.
Это отражается в разделении конфигураций:
tsconfig.json отвечает за:
include, exclude,
files)
compilerOptions.paths)
composite, incremental)
strict, noImplicitAny)
declaration,
emitDeclarationOnly)
.swcrc отвечает за:
Такое разделение позволяет SWC игнорировать тяжёлую часть type-checking и сосредоточиться на скорости преобразования AST.
tsconfig.json
Несмотря на то что SWC не выполняет type-checking, он частично читает
tsconfig.json. Это происходит не для валидации типов, а для
извлечения информации о структуре проекта.
paths, baseUrl)
Одна из ключевых причин, почему SWC обращается к
tsconfig.json, — поддержка алиасов.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/app/*"],
"@shared/*": ["src/shared/*"]
}
}
}
SWC использует эти данные, чтобы корректно переписывать импорты при трансформации.
Поле include и exclude может использоваться
инструментами вокруг SWC (например, сборщиками), чтобы определить набор
файлов для обработки:
{
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Важно: сам SWC не всегда напрямую интерпретирует эти поля, но они активно используются интеграциями (Next.js, Vite-плагины, custom build pipelines).
SWC может учитывать некоторые флаги, влияющие на синтаксис TypeScript:
jsx
experimentalDecorators
useDefineForClassFields
target
Однако критическое различие заключается в том, что эти параметры
дублируются в .swcrc и могут конфликтовать.
.swcrc как основной источник трансформации
Файл .swcrc является основным конфигурационным файлом SWC.
Пример:
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": true
},
"transform": {
"legacyDecorator": true,
"react": {
"runtime": "automatic"
}
},
"target": "es2020"
},
"module": {
"type": "es6"
},
"sourceMaps": true
}
Если tsconfig.json описывает проект, то .swcrc
описывает поведение трансформации.
SWC не объединяет их автоматически в единую модель, поэтому возникает слой интеграции, который решает:
tsconfig.json
tsconfig.json и .swcrc
На практике часто возникает ситуация, когда одинаковые концепции задаются в двух местах.
target
tsconfig.json:
{
"compilerOptions": {
"target": "ES2022"
}
}
.swcrc:
{
"jsc": {
"target": "es2020"
}
}
В этом случае приоритет имеет .swcrc, так как именно он
управляет трансформацией.
tsconfig.json:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
.swcrc:
{
"jsc": {
"transform": {
"react": {
"runtime": "classic"
}
}
}
}
Поведение определяется SWC-конфигурацией, а tsconfig.json
влияет только на IDE и type-checking.
TypeScript и SWC исторически различаются в реализации декораторов:
experimentalDecorators
legacyDecorator
{
"jsc": {
"parser": {
"decorators": true
},
"transform": {
"legacyDecorator": true
}
}
}
При расхождении поведения именно .swcrc определяет итоговую
трансформацию.
tsconfig.json в SWC-пайплайнах
В реальных сборках tsconfig.json часто используется не
самим SWC, а инструментами вокруг него.
В Next.js tsconfig.json используется для:
SWC при этом выполняет транспиляцию через встроенный pipeline Next.js.
В связке Vite + SWC:
tsconfig.json читается плагинами для резолвинга импортов
.swcrc управляет трансформацией
В NestJS SWC используется как ускоренная замена tsc, при
этом:
tsconfig.json определяет структуру проекта
.swcrc отвечает за emit JavaScript
В типичном SWC-пайплайне можно выделить следующую иерархию:
.swcrc — трансформация AST
tsconfig.json — структура и типизация
Это означает, что:
tsconfig.json не может переопределить поведение
трансформации SWC
.swcrc не обязан учитывать все TypeScript-опции
Одним из наиболее важных пересечений является работа с импортами.
tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"]
}
}
}
SWC сам по себе не выполняет полноценный module resolution. Вместо этого:
tsconfig.json
tsconfig-paths)
Таким образом, алиасы не являются функцией SWC напрямую, а зависят от окружения.
Ключевой концепт взаимодействия:
tsconfig.json не влияет на кодогенерацию
SWC
Это приводит к необходимости параллельного запуска TypeScript:
swc src -d dist
tsc --noEmit
Такой подход разделяет:
В монорепозиториях взаимодействие становится сложнее:
tsconfig.json
tsconfig.base.json
tsconfig.json
SWC обычно работает в контексте одного .swcrc, поэтому:
TypeScript поддерживает:
{
"references": [
{ "path": "../shared" }
]
}
SWC не интерпретирует это напрямую, поэтому сборка зависит от внешнего оркестратора.
Логически взаимодействие можно описать как два параллельных слоя:
Они пересекаются только в ограниченных точках:
Все остальные аспекты существуют независимо.
tsconfig.json
Если tsconfig.json отсутствует:
.swcrc
Это ещё раз подчёркивает, что tsconfig.json не является
обязательным для SWC как трансформера.
.swcrc
Если .swcrc отсутствует:
Разные сборщики по-разному комбинируют конфигурации:
.swcrc — основной источник трансформации
tsconfig.json — используется через ts-loader
или резолверы
.swcrc
tsconfig.json для алиасов
Финальная модель взаимодействия выглядит как:
tsconfig.json описывает семантику проекта
.swcrc описывает синтаксическую
трансформацию
Разделение позволяет добиться высокой скорости трансформации без потери гибкости проектной структуры.