Поле jsc.externalHelpers

### Поле `jsc.externalHelpers` #### Назначение и роль в архитектуре SWC В процессе трансформации JavaScript-кода компилятор SWC генерирует вспомогательные функции (helpers), которые обеспечивают корректную работу современных синтаксических конструкций после транспиляции в более старые версии ECMAScript. Эти вспомогательные функции могут включаться непосредственно в каждый выходной файл или выноситься в отдельную общую зависимость. Поле `jsc.externalHelpers` управляет стратегией использования этих helper-функций: инлайн-генерацией или внешним подключением через единый runtime-пакет. Ключевая идея: * при `false` helpers вставляются в каждый файл отдельно; * при `true` используется общий пакет `@swc/helpers`, который подключается как внешняя зависимость. --- #### Поведение при значении `false` По умолчанию SWC может генерировать вспомогательные функции прямо в каждый модуль, где они требуются. Это приводит к следующей модели: * каждый файл содержит собственные копии `_extends`, `_classCallCheck`, `_asyncToGenerator` и других helper-функций; * отсутствует внешняя зависимость; * упрощается запуск без дополнительных пакетов. Однако такая модель имеет последствия: * увеличение итогового размера бандла; * дублирование кода между модулями; * ухудшение эффективности кеширования; * рост времени загрузки в браузере. Пример результата при инлайн-режиме: ```js function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } ``` Этот код может повторяться в десятках файлов. --- #### Поведение при значении `true` При включении: ```json { "jsc": { "externalHelpers": true } } ``` SWC перестаёт внедрять вспомогательные функции внутрь каждого файла и вместо этого использует импорт из пакета: ```js import { _extends } from "@swc/helpers"; ``` или аналогичных внутренних модулей `@swc/helpers`. --- #### Роль пакета `@swc/helpers` Пакет `@swc/helpers` является централизованным набором runtime-функций, необходимых для корректной работы транспилированного кода. Он включает реализации: * классовых helper-ов (`_classCallCheck`, `_createClass`); * async/await преобразований (`_asyncToGenerator`); * spread-операторов (`_extends`); * генераторов и итераторов; * некоторых утилит для Babel-совместимости. Использование внешнего пакета позволяет: * устранить дублирование runtime-кода; * улучшить кеширование на уровне браузера и CDN; * уменьшить общий размер JavaScript-бандла; * унифицировать поведение между файлами и пакетами. --- #### Принцип работы трансформации При включённом `externalHelpers` SWC выполняет следующие шаги: 1. Анализирует AST и выявляет необходимость helper-функций. 2. Проверяет наличие соответствующих импортов. 3. Заменяет встроенные реализации на импортируемые символы. 4. Добавляет импорт из `@swc/helpers` в начало файла при необходимости. Пример до трансформации: ```js class A {} ``` После трансформации: ```js import { _classCallCheck } from "@swc/helpers/_/_class_call_check"; var A = function A() { _classCallCheck(this, A); }; ``` --- #### Особенности модульного импорта SWC не всегда импортирует весь пакет целиком. Вместо этого используется granular-import подход: * каждый helper импортируется отдельно; * пути могут быть точечными (`@swc/helpers/_/_extends`); * обеспечивается tree-shaking на уровне bundler-а. Это снижает избыточность даже при использовании внешней зависимости. --- #### Совместимость с bundler-ами Использование `externalHelpers` требует корректной работы сборщика: ##### Webpack Webpack корректно обрабатывает `@swc/helpers` как обычный npm-пакет. При этом: * возможна дедупликация через resolve.alias; * поддерживается tree-shaking в production mode. ##### Vite Vite обрабатывает такие импорты через ESBuild prebundle: * `@swc/helpers` попадает в оптимизированные зависимости; * уменьшается количество HTTP-запросов за счёт бандлинга. ##### Rollup Rollup эффективно трясёт дерево зависимостей: * helper-функции включаются только при использовании; * возможна агрессивная оптимизация размера. --- #### Влияние на размер бандла Разница между режимами особенно заметна в крупных проектах. ##### Без externalHelpers * каждый модуль содержит дублирующие runtime-функции; * увеличение размера пропорционально числу файлов; * особенно критично при микрофронтендах. ##### С externalHelpers * helpers загружаются один раз; * размер растёт только за счёт фактического использования функций; * уменьшается общий JS payload. --- #### Проблемы и ограничения Несмотря на преимущества, использование `externalHelpers` вводит ряд требований: ##### 1. Необходимость зависимости Проект обязан включать: ```bash npm install @swc/helpers ``` Отсутствие пакета приводит к runtime-ошибкам импорта. --- ##### 2. Версионные несоответствия Разные версии SWC и `@swc/helpers` могут: * изменять сигнатуры helper-функций; * добавлять новые импорты; * изменять пути модулей. Это требует синхронизации версий в монорепозиториях. --- ##### 3. Особенности SSR В Node.js окружении: * external helpers увеличивают число импортов; * возможна задержка cold start; * требуется корректная резолюция ESM/CJS. --- #### Монорепозитории и повторное использование В монорепозиториях `externalHelpers` часто используется совместно с workspace-зависимостями. Преимущества: * единый runtime для всех пакетов; * отсутствие дублирования helpers между пакетами; * упрощённый контроль версий. Типичная конфигурация: ```json { "jsc": { "externalHelpers": true } } ``` и единый `@swc/helpers` в корне workspace. --- #### Взаимодействие с другими опциями SWC `externalHelpers` тесно связан с другими параметрами: * `jsc.target` — влияет на набор необходимых helpers; * `module.type` — определяет формат импортов; * `minify` — может удалять неиспользуемые helpers; * `keepClassNames` — снижает количество генераций class helpers. Чем старее target (например, ES5), тем больше helpers требуется. --- #### Практическая модель выбора Решение о включении опции определяется архитектурой: * небольшие проекты → допустим inline-режим; * библиотеки → предпочтителен external режим; * крупные SPA → почти всегда externalHelpers; * микрофронтенды → обязательное использование external runtime. --- #### Влияние на повторное использование кода External helpers создают единый слой абстракции: * одинаковые трансформации используют одни и те же реализации; * уменьшается вероятность расхождений между модулями; * упрощается анализ и отладка транспилированного кода. --- #### Поведение при tree-shaking При корректной настройке bundler-а: * неиспользуемые helpers исключаются; * импортируются только реально задействованные функции; * итоговый runtime минимизируется до фактического набора операций. --- #### Типовые ошибки конфигурации На практике встречаются следующие проблемы: * отсутствие `@swc/helpers` в dependencies; * смешивание external и inline режимов в разных пакетах; * неправильная резолюция путей импорта; * несовместимость с legacy bundler-ами без ESM поддержки. Каждая из них приводит либо к дублированию, либо к runtime-ошибкам. --- #### Поведение при миграции с Babel При переходе с Babel на SWC: * аналогом `@babel/plugin-transform-runtime` выступает `externalHelpers`; * аналогом `@babel/runtime` является `@swc/helpers`; * логика разделения runtime идентична. Это упрощает миграцию крупных кодовых баз без изменения архитектуры импорта helpers.