Поле 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` выходит за пределы оптимизации и становится архитектурным параметром сборки.