Поле sideEffects в package.json

Поле sideEffects в package.json используется сборщиком модулей (в первую очередь Webpack) для анализа побочных эффектов модулей и оптимизации tree shaking. Его основная задача — помочь определить, какие файлы можно безопасно удалить при сборке, если их экспортированные значения не используются.

В основе механизма лежит предположение: если модуль не содержит побочных эффектов, то его импорт можно считать «чистым» и потенциально удалить при отсутствии использования экспортов. Однако JavaScript по своей природе допускает выполнение кода при импорте, поэтому без явного указания невозможно гарантировать безопасность удаления.


Под побочными эффектами понимаются любые операции, которые происходят при загрузке модуля и не связаны напрямую с его экспортами:

  • изменение глобального состояния
  • регистрация полифиллов
  • выполнение кода вне функций
  • модификация прототипов
  • подключение CSS, которое влияет на DOM
  • инициализация сторонних библиотек

Пример:

// logger.js
console.log('logger initialized');

export function log(msg) {
  console.log(msg);
}

Даже если log не используется, строка console.log('logger initialized') выполнится при импорте. Это и есть побочный эффект.


Поведение Webpack без sideEffects

При включённом tree shaking Webpack анализирует ESM-экспорты и удаляет неиспользуемые части кода. Однако без дополнительной информации он вынужден считать, что любой импорт может иметь побочные эффекты.

import { log } from './logger';

Если модуль не используется напрямую, но импортирован, Webpack не сможет безопасно удалить его, если не уверен в отсутствии побочных эффектов.


Поле sideEffects в package.json

Поле sideEffects объявляется в package.json и сообщает сборщику, содержит ли пакет модули с побочными эффектами.

Вариант boolean

{
  "sideEffects": false
}

Значение false означает:

  • ни один файл пакета не имеет побочных эффектов
  • любой неиспользуемый импорт можно безопасно удалить

Это максимально агрессивный режим оптимизации.


Вариант массива

{
  "sideEffects": [
    "*.css",
    "*.scss"
  ]
}

В этом случае:

  • все файлы считаются «чистыми»
  • кроме тех, что соответствуют указанным паттернам
  • перечисленные файлы сохраняются всегда

Типичный пример — стили:

import './styles.css';

CSS импорт часто не имеет JS-экспортов, но его удаление приведёт к потере стилей. Поэтому он явно помечается как побочный эффект.


Связь с tree shaking

Tree shaking работает только в условиях статического анализа ESM:

  • import / export должны быть статическими
  • код должен быть в production режиме
  • минимизация должна быть включена

Webpack использует sideEffects как дополнительный сигнал:

  • false → можно удалять неиспользуемые импорты даже без анализа содержимого
  • массив → частичная защита отдельных типов файлов
  • отсутствие поля → осторожный режим (ничего не удаляется агрессивно)

Влияние на CSS и ассеты

Частая проблема связана с импортом немодульных ресурсов:

import './reset.css';
import './theme.css';

Если не указать sideEffects, Webpack может ошибочно удалить такие импорты при оптимизациях.

Правильная конфигурация:

{
  "sideEffects": [
    "*.css",
    "*.scss",
    "*.sass"
  ]
}

Это позволяет:

  • сохранить стили
  • продолжить удаление неиспользуемого JS
  • не ломать побочные импорты

Связь с библиотечным кодом

Для библиотек sideEffects критически важен, поскольку они распространяются как зависимости.

Библиотека без побочных эффектов

{
  "name": "math-utils",
  "sideEffects": false
}

Такая библиотека:

  • полностью tree-shakeable
  • позволяет удалять неиспользуемые функции
  • оптимальна для сборки приложений

Пример кода:

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

Если используется только add, функция multiply исключается из бандла.


Библиотека с частичными побочными эффектами

{
  "sideEffects": [
    "./polyfills.js"
  ]
}
// polyfills.js
import 'core-js/stable';
import 'regenerator-runtime/runtime';

Такой файл должен выполняться всегда, даже если его экспорты не используются.


Взаимодействие с Webpack optimization.sideEffects

Webpack имеет собственную настройку:

module.exports = {
  optimization: {
    sideEffects: true
  }
};

Она включает анализ поля sideEffects. В production режиме обычно включено по умолчанию.

Если отключить:

optimization: {
  sideEffects: false
}

то:

  • Webpack перестаёт учитывать sideEffects
  • tree shaking становится менее агрессивным
  • увеличивается размер бандла

Ошибки при неправильной настройке

Неверная конфигурация может привести к серьёзным проблемам.

Ложное указание false

{
  "sideEffects": false
}

Если пакет фактически содержит:

import './global.css';
window.APP_VERSION = '1.0.0';

то при tree shaking:

  • CSS может быть удалён
  • глобальные изменения не произойдут
  • приложение сломается

Отсутствие указания

Если поле не задано:

  • Webpack действует осторожно
  • часть оптимизаций отключается
  • бандл становится больше

Влияние на ESM и CJS

sideEffects наиболее эффективно работает с ES Modules:

  • static import/export
  • возможность анализа зависимости
  • предсказуемая структура кода

В CommonJS:

const mod = require('./mod');

tree shaking ограничен, поэтому sideEffects почти не даёт эффекта.


Практическая модель принятия решений Webpack

При анализе модуля происходит цепочка:

  1. Проверка import
  2. Проверка использования экспортов
  3. Проверка sideEffects
  4. Решение об удалении или включении

Если одновременно:

  • экспорт не используется
  • sideEffects = false

то модуль удаляется полностью.


Сложные случаи: динамические импорты

import('./module.js');

Для динамических импортов:

  • sideEffects не влияет на загрузку самого чанка
  • но влияет на содержимое чанка при оптимизации

Роль в архитектуре современных библиотек

Современные npm-пакеты стремятся к:

  • максимальной tree-shakeability
  • минимальному побочному поведению
  • явному разделению модулей

Типичная структура:

src/
  index.js
  pure/
  side-effects/
dist/

И соответствующая конфигурация:

{
  "sideEffects": [
    "./dist/side-effects/**"
  ]
}

Типичные паттерны использования

  • UI-библиотеки помечают CSS как side effect
  • polyfill-бандлы всегда считаются побочными
  • утилитарные библиотеки используют false
  • крупные фреймворки комбинируют оба подхода

Взаимодействие с минификацией

Tree shaking и sideEffects работают до этапа минификации. После удаления неиспользуемых модулей:

  • Terser удаляет мёртвый код
  • уменьшается количество AST-узлов
  • ускоряется финальная сборка

Итоговая логика поведения поля

sideEffects можно рассматривать как контракт:

  • разработчик сообщает сборщику о природе модулей
  • сборщик использует эту информацию для безопасной оптимизации
  • результатом становится уменьшение итогового бандла без изменения логики приложения