Механизм tree-shaking в Rollup основан на статическом анализе графа
ES-модулей и удалении недостижимого или неиспользуемого кода. Однако
корректность удаления напрямую зависит от того, считается ли модуль
потенциально выполняющим побочные эффекты при импорте. Параметр
treeshake.moduleSideEffects управляет тем, как Rollup
принимает решение о «безопасности» удаления модулей целиком.
Ключевая идея заключается в том, что не каждый импортируемый модуль можно безопасно исключить, даже если его экспорт не используется. Некоторые модули при загрузке изменяют глобальное состояние, регистрируют плагины, модифицируют прототипы или выполняют побочные действия.
При стандартной работе Rollup анализирует:
Но без дополнительной информации Rollup вынужден считать, что любой модуль может иметь побочные эффекты, особенно если это нельзя доказать статически. В результате:
Параметр moduleSideEffects определяет, как Rollup
оценивает наличие побочных эффектов на уровне модулей.
true (значение по
умолчанию)Каждый модуль считается потенциально содержащим побочные эффекты.
Последствия:
falseВсе модули считаются чистыми (без побочных эффектов).
Последствия:
Использование этого режима оправдано только в строго контролируемых кодовых базах, где гарантируется отсутствие side effects при импорте.
'no-external'Специфический режим, при котором:
Это компромиссный вариант для проектов, где:
package.json(id, external) => booleanНаиболее гибкий вариант, позволяющий задавать правила на уровне каждого модуля.
Аргументы:
id — путь к модулюexternal — булево значение, указывающее, является ли
модуль внешнимПример логики:
src/polyfills/**src/utils/**При анализе графа модулей Rollup выполняет несколько шагов:
moduleSideEffects влияет именно на шаг 3.
Если модуль считается «чистым»:
Если модуль считается «грязным»:
Часто возникает пересечение с полем sideEffects в
package.json, используемым webpack и частично
Rollup-плагинами.
Однако логика различается:
| Механизм | Уровень | Назначение |
|---|---|---|
package.json sideEffects |
пакет | помечает файлы с побочными эффектами |
treeshake.moduleSideEffects |
Rollup | глобальная политика анализа модулей |
Если используется оба механизма:
package.json sideEffects даёт первичную информациюmoduleSideEffects может переопределять или уточнять
поведение RollupДля библиотек часто используется стратегия максимальной оптимизации:
В этом случае допустимо:
'no-external'Polyfill-модули часто:
Пример:
core-jsregenerator-runtimeТакие модули должны всегда считаться имеющими побочные эффекты, иначе возможны критические ошибки выполнения.
Импорт стилей:
import './styles.css';
Даже если экспортов нет, сам факт импорта:
Такие файлы почти всегда должны быть отмечены как side-effectful через кастомную функцию.
export default {
treeshake: {
moduleSideEffects: false
}
};
Используется только если проект полностью контролируется и отсутствуют скрытые побочные эффекты.
export default {
treeshake: {
moduleSideEffects: true
}
};
Максимальная совместимость, минимальная оптимизация на уровне модулей.
export default {
treeshake: {
moduleSideEffects: 'no-external'
}
};
Внутренний код оптимизируется агрессивно, внешние зависимости сохраняются как безопасные.
export default {
treeshake: {
moduleSideEffects(id, external) {
if (id.includes('polyfill')) return true;
if (id.includes('utils')) return false;
if (external) return false;
return true;
}
}
};
Позволяет явно контролировать поведение для различных слоёв архитектуры.
Установка false без анализа проекта приводит к:
Некоторые эффекты невозможно определить статически:
window или globalThisRollup не всегда может это вывести автоматически.
При использовании 'no-external' внешние зависимости
считаются чистыми, но:
package.json sideEffectsЧем более точная настройка moduleSideEffects:
Функциональная форма увеличивает время анализа, но обычно не критично для средних проектов.
Правильная настройка moduleSideEffects фактически
становится частью архитектурного контракта:
В крупных кодовых базах это часто дополняется соглашениями:
Симптомы неправильной настройки:
Для диагностики полезно:
moduleSideEffects в
true