Tree shaking и циклические зависимости
Tree Shaking и циклические зависимости
Tree shaking — устранение неиспользуемого кода бандлером. Работает только с ESM, потому что его импорты статичны и анализируются до выполнения.
Как работает tree shaking
// utils.js — большая библиотека
export function usedFunction() { return 'используется' }
export function unusedFunction() { return 'не используется' }
export const BIG_CONSTANT = new Array(10000).fill(0) // большой массив
// main.js — импортируем только нужное
import { usedFunction } from './utils.js'
// unusedFunction и BIG_CONSTANT не попадут в бандл!
// ПЛОХО для tree shaking — импорт всего
import * as utils from './utils.js' // всё попадёт в бандл
// ХОРОШО — только нужное
import { usedFunction } from './utils.js'
Tree shaking не работает с CommonJS!
require() выполняется в runtime, бандлер не знает заранее что будет использоваться. Для tree shaking нужны именно ESM-экспорты.Побочные эффекты (side effects)
// sideEffect.js
import './polyfills.js' // выполняет код при загрузке!
console.log('модуль загружен') // это побочный эффект
// Бандлер по умолчанию считает все файлы имеющими побочные эффекты
// Объяви чистые файлы в package.json:
{
"sideEffects": false, // весь код без побочных эффектов
// Или укажи конкретные файлы с побочными эффектами:
"sideEffects": ["./src/polyfills.js", "*.css"]
}
Циклические зависимости
Циклические зависимости — когда A импортирует B, а B импортирует A. В ESM это допустимо благодаря живым привязкам, но требует осторожности:
// a.js
import { b } from './b.js'
export const a = 'A: ' + b // b может быть undefined при инициализации!
// b.js
import { a } from './a.js'
export const b = 'B' // инициализируется первой (если её загружают первой)
// БЕЗОПАСНЫЙ паттерн: используй функции, не константы
// a.js
import { getB } from './b.js'
export function getA() { return 'A: ' + getB() } // вызов отложен!
// b.js
import { getA } from './a.js'
export function getB() { return 'B' }
Циклические зависимости — обычно сигнал о проблеме архитектуры. Выдели общую зависимость в отдельный модуль (shared), на который ссылаются оба.
ESM строит граф зависимостей до выполнения кода. При цикле A→B→A JavaScript создаёт «дырки» (TDZ-подобные) для неинициализированных привязок. Когда B попытается читать
a до того как A был выполнен, получит undefined (или TDZ-ошибку для const/let). Функции в безопасности — их тела не выполняются при объявлении.