Поле jsc.keepClassNames
Поле `jsc.keepClassNames` в конфигурации SWC относится к этапу трансформации классов и напрямую влияет на то, сохраняются ли исходные имена классов при компиляции JavaScript-кода. Это поведение становится критически важным в сценариях, где имя класса используется не только как синтаксическая метаинформация, но и как часть логики приложения, диагностики или интеграций с внешними системами.
SWC (Speedy Web Compiler) выполняет преобразование современного JavaScript и TypeScript в более совместимый JavaScript. В процессе трансформации классы могут быть переименованы, минифицированы или полностью изменены для уменьшения размера кода. Именно здесь `jsc.keepClassNames` определяет стратегию сохранения имени класса.
## Назначение `jsc.keepClassNames`
Флаг управляет сохранением свойства `name` у функций-конструкторов, созданных из классов.
Класс в Jav * aScript:
```js
class UserService {}
```
После трансформации может быть превращён в:
```js
var UserService = function UserService() {};
```
или, при агрессивной оптимизации:
```js
var a = function a() {};
```
В последнем случае имя класса теряется, что влияет на:
* `Function.name`
* отражение в stack trace
* работу DI-контейнеров
* логирование и telemetry
* тестовые фреймворки
## Поведение при включённом `keepClassNames`
При значении `true` SWC сохраняет оригинальные имена классов в итоговом коде.
Пример входного кода:
```js
class ApiClient {}
```
Результат трансформации:
```js
var ApiClient = function ApiClient() {};
```
Здесь сохраняется:
```js
ApiClient.name === "ApiClient"
```
Это обеспечивает предсказуемость поведения рефлексивных механизмов.
## Поведение при отключённом `keepClassNames`
При значении `false` SWC имеет право переименовывать классы для оптимизации:
```js
class ApiClient {}
```
Может стать:
```js
var a = function a() {};
```
В этом случае:
```js
a.name === "a"
```
или при дальнейшей минификации:
```js
var _a = function _a() {};
```
Имена становятся нестабильными и зависят от pipeline сборки.
## Влияние на tree-shaking и минификацию
Сохранение имён классов увеличивает читаемость итогового кода, но может ограничивать степень оптимизации.
При `keepClassNames: false`:
* минификатор может агрессивно сокращать идентификаторы
* улучшается эффективность tree-shaking
* уменьшается размер бандла
При `keepClassNames: true`:
* сохраняется структура для диагностики
* уменьшается эффективность переименования
* увеличивается предсказуемость runtime-отражений
## Взаимодействие с `jsc.minify`
Поле тесно связано с минификацией. В конфигурации SWC:
* `mangle` может переименовывать классы
* `keepClassNames` ограничивает это поведение
Если включены оба механизма:
```json
{
"jsc": {
"keepClassNames": true
},
"minify": {
"mangle": true
}
}
```
то SWC будет вынужден сохранять имена классов даже при активном mangling.
## Использование в DI и фреймворках
Многие архитектурные решения зависят от имени класса:
### Dependency Injection
```ts
container.register(UserService, UserService);
```
Здесь `UserService.name` используется как ключ регистрации.
Если `keepClassNames = false`, регистрация может ломаться:
* ключи становятся неконсистентными
* отражение типов теряет точность
### Runtime reflection
Некоторые ORM и серверные фреймворки используют:
```js
entity.constructor.name
```
Для сериализации или построения схем.
## Влияние на stack trace
Имена классов участвуют в формировании читаемых stack trace:
```js
class DatabaseError extends Error {}
```
С `keepClassNames: true` стек выглядит информативнее:
```
DatabaseError: connection failed
```
С отключённым флагом:
```
Error: connection failed
```
или менее информативные идентификаторы.
## Связь с TypeScript компиляцией
При использовании SWC как TypeScript-трансформера:
```ts
class Service {}
```
TypeScript не сохраняет runtime-тип, но SWC может контролировать JavaScript-имя.
Важно различать:
* TypeScript типы (compile-time)
* JS class name (runtime)
`keepClassNames` влияет только на второе.
## Оптимизационные компромиссы
Решение о включении флага зависит от архитектуры:
### Когда включать
* используется DI по имени класса
* требуется стабильный stack trace
* есть runtime-интроспекция
* применяется logging/telemetry по именам классов
### Когда отключать
* критична минимизация бандла
* используется агрессивный production-mangling
* отсутствует зависимость от `Function.name`
* применяется внешняя система идентификации типов
## Примеры реального поведения в сборке
### Конфигурация SWC
```json
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"keepClassNames": true
},
"minify": {
"compress": true,
"mangle": true
}
}
```
### Код до трансформации
```ts
class Logger {
log() {
console.log("test");
}
}
```
### Код после трансформации (упрощённо)
```js
var Logger = function Logger() {};
Logger.prototype.log = function () {
console.log("test");
};
```
## Особенности реализации в SWC
SWC опирается на AST (Abstract Syntax Tree). При трансформации:
* узел `ClassDeclaration` преобразуется в `FunctionExpression`
* имя класса может быть привязано к идентификатору функции
* `keepClassNames` контролирует сохранение этого идентификатора
Если флаг выключен:
* имя может быть отброшено или заменено на минимизированное
* AST-узлы теряют семантическую связь с исходным идентификатором
## Побочные эффекты
Некоторые неожиданные эффекты включают:
* различия между dev и prod окружением
* несовпадение имен классов в тестах snapshot-based
* ошибки в метапрограммировании
* нарушение контрактов библиотек, зависящих от `.name`
## Совместимость с другими инструментами
### Babel
Аналогичная опция:
* `keepClassNames` в Babel minify
* поведение близко, но не идентично SWC
### Webpack / Vite
Флаг действует только на уровне трансформации SWC, но может конфликтовать с:
* Terser
* esbuild minify
* custom plugins, переопределяющими идентификаторы
## Практическое значение в архитектуре
Сохранение имени класса становится частью контрактной модели приложения. В системах, где классы используются как идентификаторы:
* сервисы регистрируются по имени
* события маппятся на классы
* логирование группирует ошибки по типу класса
влияние `keepClassNames` выходит за пределы оптимизации и становится архитектурным параметром сборки.