В Rollup tree-shaking является одним из ключевых механизмов
оптимизации, основанных на статическом анализе модулей ES. Поле
treeshake в конфигурации управляет тем, насколько
агрессивно и каким образом сборщик удаляет неиспользуемые части графа
зависимостей.
Механизм tree-shaking в Rollup опирается на несколько факторов:
структуру импортов/экспортов, чистоту модулей, наличие побочных эффектов
и корректную аннотацию кода. Конфигурация treeshake
позволяет управлять этими аспектами на уровне сборки.
Поле treeshake может принимать два основных вида
значений:
export default {
treeshake: true
}
export default {
treeshake: false
}
true — включает стандартный алгоритм tree-shakingfalse — полностью отключает удаление неиспользуемого
кодаОтключение используется редко, в основном для диагностики или при работе с кодом, который ломается из-за побочных эффектов анализа.
Для тонкой настройки используется объект:
export default {
treeshake: {
moduleSideEffects: true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
}
}
Каждый параметр управляет отдельной частью модели анализа.
moduleSideEffects определяет, считает ли Rollup импорт
модуля потенциально “грязным” (имеющим побочные эффекты).
true — каждый модуль потенциально имеет побочные
эффектыfalse — модули считаются чистыми, если явно не указано
иное(id) => boolean — точечный контроль по пути
модуляexport default {
treeshake: {
moduleSideEffects: id => {
if (id.includes('styles')) return true
return false
}
}
}
Если модуль считается “чистым”, Rollup может удалить его импорт даже если он не использует экспорт напрямую, но импорт присутствует в графе.
Если модуль “грязный”, он сохраняется целиком при любом импорте.
Этот параметр управляет тем, считаются ли обращения к свойствам объектов потенциально имеющими побочные эффекты.
export default {
treeshake: {
propertyReadSideEffects: true
}
}
true — доступ к свойствам может блокировать удаление
кодаfalse — чтение свойств считается безопасным и не влияет
на side effectsexport const obj = {
get value() {
console.log('side effect')
return 42
}
}
При включённых побочных эффектах чтения Rollup сохранит код, даже
если obj.value нигде не используется явно.
Блоки try/catch усложняют статический анализ, так как
потенциальные ошибки могут скрывать выполнение побочных эффектов.
export default {
treeshake: {
tryCatchDeoptimization: true
}
}
true — при наличии try/catch Rollup
снижает уровень оптимизации внутри блокаfalse — Rollup продолжает агрессивную оптимизацию даже
внутри try/catchВключённое значение повышает безопасность, но уменьшает эффективность tree-shaking в сложных участках кода.
Этот параметр определяет, считать ли обращения к неизвестным глобальным переменным потенциально опасными.
export default {
treeshake: {
unknownGlobalSideEffects: true
}
}
true — любое обращение к неизвестным глобальным
переменным считается побочным эффектомfalse — Rollup предполагает, что такие обращения
безопасныconsole.log(window.SOME_GLOBAL)
Если глобальная переменная не определена в анализе, при включённом режиме Rollup может сохранить больше кода, чем необходимо.
Tree-shaking в Rollup тесно связан с тем, как интерпретируются экспортируемые сущности:
При агрессивной настройке treeshake возможно удаление
даже промежуточных модулей, если они не влияют на итоговый граф
выполнения.
Rollup поддерживает специальные комментарии, влияющие на treeshaking:
/*#__PURE__*/
const x = createSomething()
Такая аннотация сигнализирует, что вызов функции не имеет побочных эффектов и может быть удалён, если результат не используется.
Конфигурация treeshake определяет, насколько доверять
этим аннотациям.
Внешние зависимости (external) обычно исключаются из
анализа, но их импорты всё равно влияют на структуру графа.
Особенности:
Tree-shaking ограничен статическим анализом. Следующие конструкции ухудшают оптимизацию:
evalrequireПри таких случаях Rollup может:
export default {
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
tryCatchDeoptimization: false,
unknownGlobalSideEffects: false
}
}
Используется в библиотеках, где код полностью контролируется и строго модульный.
export default {
treeshake: {
moduleSideEffects: id => !id.includes('polyfill'),
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
}
}
Подходит для реальных приложений с внешними зависимостями и частично неконтролируемым кодом.
export default {
treeshake: {
moduleSideEffects: true,
propertyReadSideEffects: true,
tryCatchDeoptimization: true,
unknownGlobalSideEffects: true
}
}
Используется при сложных legacy-проектах, где безопасность важнее оптимизации.
Эффективность treeshaking в Rollup напрямую зависит от качества исходного кода:
/*#__PURE__*/ аннотацииЧем чище архитектура, тем более предсказуем результат работы
treeshake.
Несмотря на гибкость, tree-shaking не способен:
Поэтому treeshake всегда является балансом между
безопасностью и агрессивной оптимизацией.