Этап compress в SWC отвечает за семантическое упрощение и
сокращение JavaScript-кода на уровне абстрактного синтаксического дерева
(AST). В отличие от модуля mangle, который изменяет только
идентификаторы, compress анализирует структуру программы,
устраняет лишние конструкции, упрощает выражения и выполняет агрессивные
оптимизации без изменения поведения программы.
Основная цель — уменьшение размера итогового кода и повышение его эффективности за счёт удаления избыточной логики и статически вычислимых выражений.
Ключевые операции этапа включают:
Внутренний пайплайн SWC можно представить как последовательность преобразований AST:
compress
mangle
Этап compress работает на промежуточном AST, когда
структура программы уже нормализована, но имена переменных ещё не
изменены. Это важно, поскольку оптимизации зависят от семантики и
требуют читаемых ссылок на идентификаторы.
Одной из ключевых задач compress является вычисление
выражений на этапе компиляции.
Примеры преобразований:
2 + 3 → 5
10 * 100 → 1000
“a” + “b” → “ab”
true && false → false
В AST это реализуется как проход по узлам выражений с попыткой определить их статическую вычислимость. Если оба операнда выражения являются литералами, SWC выполняет вычисление и заменяет поддерево на новый литерал.
Особое внимание уделяется безопасным операциям: деление на ноль, переполнения чисел IEEE-754 и побочные эффекты функций не оптимизируются без явной гарантии отсутствия side effects.
Dead Code Elimination (DCE) — одна из самых агрессивных оптимизаций.
Типичные случаи:
if (false) {
doSomething();
}
После compress:
Также удаляются:
if (true) с альтернативной веткой else
Особый случай — работа с модулями ES:
import { a } from "lib";
console.log(1);
Если a нигде не используется, импорт может быть удалён.
Этап compress активно сокращает булеву алгебру:
!!x → Boolean(x)
x && true → x
x && false → false
x || false → x
x || true → true
Также происходит нормализация условных выражений:
if (a === true)
может быть преобразовано в:
if (a)
если типовая информация и контекст позволяют исключить неоднозначность.
SWC выполняет ограниченный инлайнинг выражений, когда это безопасно:
const x = 10;
const y = x + 5;
становится:
const y = 15;
Если переменная используется единожды и не имеет побочных эффектов, её значение подставляется напрямую.
Также упрощаются конструкции:
Ключевой аспект compress — анализ side effects.
Функция считается безопасной для удаления или инлайна, если:
Пример:
pureFunction();
Если pureFunction определена как чистая (или помечена через
pure_funcs), вызов может быть удалён:
Конфигурация позволяет явно указывать такие функции:
{
"jsc": {
"minify": {
"compress": {
"pure_funcs": ["console.log"]
}
}
}
}
compress преобразует сложные ветвления в более компактные
формы.
Пример:
if (a) {
b();
} else {
c();
}
При известном значении a на этапе компиляции:
a ? b() : c();
Если a статически истинно:
b();
Если ложно:
c();
Некоторые оптимизации затрагивают циклы:
Пример:
while (false) {
work();
}
исчезает полностью.
Хотя compress и mangle часто используются
вместе, их роли разделены:
compress работает с логикой и структурой кода
mangle работает с именами идентификаторов
Порядок критичен: сначала выполняется compress, затем
mangle. Это позволяет оптимизатору видеть семантически
значимые имена до их сокращения.
Настройка выполняется через .swcrc:
{
"jsc": {
"parser": {
"syntax": "ecmascript"
},
"minify": {
"compress": {
"unused": true,
"dead_code": true,
"conditionals": true,
"evaluate": true,
"booleans": true,
"drop_console": false,
"drop_debugger": true,
"keep_fargs": false,
"pure_getters": true,
"join_vars": true
},
"mangle": true
}
}
}
Ключевые параметры:
unused — удаление неиспользуемых переменных
dead_code — удаление недостижимых блоков
conditionals — упрощение условных выражений
evaluate — вычисление константных выражений
booleans — упрощение булевой логики
drop_console — удаление console-вызовов
drop_debugger — удаление debugger-инструкций
join_vars — объединение объявлений переменных
Оптимизатор строит модель побочных эффектов для каждого узла AST. Любое выражение классифицируется как:
Это позволяет безопасно удалять конструкции вида:
a();
b();
если a() признана чистой и её результат не используется.
Кома-оператор и цепочки выражений оптимизируются:
a(), b(), c();
может быть преобразовано в:
c();
если a() и b() не имеют побочных эффектов.
compress способен сворачивать структуры:
const obj = {
a: 1,
b: 2
};
Если свойства не изменяются, возможны оптимизации доступа и удаление неиспользуемых полей.
Для массивов:
const arr = [1, 2, 3];
могут применяться оптимизации при частичном использовании элементов.
Несмотря на агрессивность, compress не выполняет:
eval,
with)
Это связано с необходимостью сохранять корректность выполнения JavaScript в динамической среде.
Этап compress наиболее эффективен в следующих случаях:
Наибольший эффект достигается при сочетании: