7. Tree Shaking
Tree shaking (встряхивание дерева) — это процесс удаления неиспользуемого кода из финального бандла. Название метафорично: представьте дерево зависимостей, которое встряхивают, и мёртвые (неиспользуемые) ветки-модули опадают.
Как работает Tree Shaking
Заголовок раздела «Как работает Tree Shaking»Tree shaking основан на статическом анализе import/export ES модулей. Webpack строит граф зависимостей и помечает код как “используемый” или “мёртвый”.
// math.js — библиотека функцийexport const add = (a, b) => a + b; // ✅ используетсяexport const subtract = (a, b) => a - b; // ❌ мёртвый кодexport const multiply = (a, b) => a * b; // ❌ мёртвый кодexport const divide = (a, b) => a / b; // ❌ мёртвый код
// app.js — использует только addimport { add } from './math';console.log(add(1, 2));После tree shaking в бандл попадёт только add. subtract, multiply, divide будут удалены.
Требования для Tree Shaking
Заголовок раздела «Требования для Tree Shaking»1. Используйте ESM (ES Modules)
Заголовок раздела «1. Используйте ESM (ES Modules)»Tree shaking не работает с CommonJS! Только ES модули (import/export) поддаются статическому анализу:
// ❌ CommonJS — tree shaking не работаетconst { add } = require('./math');module.exports = { add, subtract };
// ✅ ESM — tree shaking работаетimport { add } from './math';export { add };2. Production Mode
Заголовок раздела «2. Production Mode»module.exports = { mode: 'production', // Включает TerserPlugin, который удаляет мёртвый код};3. Babel не должен компилировать ESM в CommonJS
Заголовок раздела «3. Babel не должен компилировать ESM в CommonJS»// .babelrc — важно!{ "presets": [ ["@babel/preset-env", { "modules": false // ← Не компилировать import/export → require() }] ]}sideEffects в package.json
Заголовок раздела «sideEffects в package.json»Чтобы Webpack знал, какие файлы можно безопасно удалить, укажите sideEffects:
{ "name": "my-library", "sideEffects": false // Весь код без побочных эффектов — можно удалять}// Если некоторые файлы имеют side effects (CSS, polyfills):{ "sideEffects": [ "*.css", // CSS файлы нельзя удалять "./src/polyfills.js", "./src/setup.js" ]}Что считается side effect:
- Изменение глобальных переменных:
window.MyLib = ... - Полифиллы:
Array.prototype.includes = ... - Автоматически выполняемый код при импорте
- CSS файлы (изменяют стили)
Что не является side effect:
- Чистые функции
- Классы и типы
- Константы
Проверка эффективности Tree Shaking
Заголовок раздела «Проверка эффективности Tree Shaking»# Анализ бандла — что попало в итоговый файл?npx webpack-bundle-analyzer dist/stats.json
# Генерация stats.jsonnpx webpack --json > dist/stats.jsonTree Shaking с популярными библиотеками
Заголовок раздела «Tree Shaking с популярными библиотеками»// ❌ Импортирует ВСЮ lodash (70 KB)import _ from 'lodash';const result = _.debounce(fn, 300);
// ✅ Импортирует только debounce (2 KB)import debounce from 'lodash/debounce';// илиimport { debounce } from 'lodash-es'; // ESM версия lodash
// Material UI — правильный импорт// ❌ import { Button } from '@mui/material'; // может импортировать всё// ✅ import Button from '@mui/material/Button'; // только ButtonusedExports и optimization
Заголовок раздела «usedExports и optimization»optimization: { usedExports: true, // Помечает неиспользуемые экспорты minimize: true, // Удаляет помеченный код (через Terser) concatenateModules: true, // Scope hoisting — объединяет модули}Ниже — интерактивная демонстрация tree shaking. Импортируйте разные функции и смотрите что попадёт в бандл.