Исключение неиспользуемых плагинов

Архитектура плагинов и причина их попадания в бандл

Tom Sel ect построена вокруг модульной системы плагинов, где каждый дополнительный модуль расширяет базовый класс селекта. Плагины подключаются явно или косвенно через точку входа библиотеки и могут включаться как в runtime, так и на этапе сборки.

Основная проблема, возникающая при использовании сборщиков (Vite, Rollup, Webpack), заключается в том, что неаккуратный импорт приводит к включению всех плагинов в итоговый бандл. Это увеличивает размер JavaScript-файла, ухудшает производительность и нарушает принципы tree-shaking.

Типичный источник проблемы:

import TomSelect fr om "tom-select";

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


Принцип tree-shaking и условия его работы

Tree-shaking работает только при соблюдении нескольких условий:

  • используется ESM-импорт (import/export)
  • зависимости не имеют побочных эффектов (sideEffects: false)
  • плагины импортируются из отдельных модулей, а не через агрегатор
  • сборщик способен анализировать статическую структуру импортов

Если хотя бы одно условие нарушено, неиспользуемые плагины могут попасть в финальный бандл.


Правильная стратегия импорта ядра

Базовый подход — импортировать только ядро без побочных расширений:

import TomSelect from "tom-select/dist/js/tom-select.base.js";

В этой конфигурации подключается минимальная версия без предустановленных плагинов. Далее расширения добавляются вручную.


Явное подключение плагинов

Каждый плагин должен импортироваться отдельно, чтобы сборщик мог точно определить используемую часть библиотеки:

import TomSelect from "tom-select/dist/js/tom-select.base.js";
import { plugin_clear_button } from "tom-select/dist/js/plugins/clear_button.js";

TomSelect.define("clear_button", plugin_clear_button);

Такой подход обеспечивает:

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

Изоляция плагинов через точечные импорты

Некоторые сборки позволяют импортировать плагины напрямую из внутренних модулей:

import TomSelect from "tom-select/dist/js/tom-select.esm.js";
import dropdown_input from "tom-select/dist/js/plugins/dropdown_input.js";

После чего плагины регистрируются вручную:

TomSelect.define("dropdown_input", dropdown_input);

Ключевая идея — избегать любых импортов вида:

import "tom-select/plugins";

или

import * as plugins from "tom-select/plugins";

Такие конструкции гарантированно отключают tree-shaking.


SideEffects и package.json

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

{
  "sideEffects": false
}

Если библиотека или её часть помечена как содержащая side effects, сборщик не будет удалять неиспользуемые импорты, даже если они явно не применяются.

В случае с плагинами важно, чтобы каждый файл плагина был чистым ES-модулем без глобальных побочных действий.


Настройка Vite для исключения лишних плагинов

В Vite tree-shaking работает автоматически, но только при корректных импортax:

import TomSelect from "tom-select/dist/js/tom-select.esm.js";

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

export default {
  optimizeDeps: {
    exclude: ["tom-select"]
  }
}

Однако чаще всего исключение не требуется, если не используются агрегационные импорты.


Rollup и явный контроль включаемых модулей

В Rollup важно контролировать входные точки:

export default {
  input: "src/main.js",
  output: {
    format: "esm"
  },
  treeshake: {
    moduleSideEffects: false
  }
}

Если используется базовая ESM-версия библиотеки, Rollup способен исключить неиспользуемые плагины при условии явных импортов.


Webpack и проблема агрегационных импортов

Webpack часто включает лишний код при следующих условиях:

  • использование CommonJS сборки
  • импорт из index-файлов
  • отсутствие строгих ESM-путей

Корректный вариант:

import TomSelect from "tom-select/dist/js/tom-select.esm.js";

И избегание:

const TomSelect = require("tom-select");

Для усиления tree-shaking:

module.exports = {
  mode: "production",
  optimization: {
    usedExports: true,
    sideEffects: true
  }
};

Разделение плагинов на ручную сборку

Наиболее эффективный подход — формирование минимального набора плагинов:

import TomSelect from "tom-select/dist/js/tom-select.base.js";

import caret_position from "tom-select/dist/js/plugins/caret_position.js";
import change_listener from "tom-select/dist/js/plugins/change_listener.js";

TomSelect.define("caret_position", caret_position);
TomSelect.define("change_listener", change_listener);

Такой подход позволяет:

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

Ошибочные подходы, приводящие к раздуванию бандла

Следующие паттерны приводят к включению всех плагинов:

import TomSelect from "tom-select";
import "tom-select/dist/js/plugins";
import * as TomSelectPlugins from "tom-select/dist/js/plugins";

Причина — отсутствие статической ясности для сборщика.


Использование кастомных сборок

Для крупных проектов иногда создаётся собственная сборка Tom Sel ect с минимальным набором функций:

// custom-tomselect.js
import TomSelect fr om "tom-select/dist/js/tom-select.base.js";
import dropdown from "tom-select/dist/js/plugins/dropdown_input.js";

TomSelect.define("dropdown_input", dropdown);

export default TomSelect;

Далее используется единая точка импорта:

import TomSelect from "./custom-tomselect.js";

Контроль итогового размера и аудит бандла

После настройки исключения плагинов важно проверять результат сборки:

  • анализ через webpack-bundle-analyzer
  • проверка rollup-plugin-visualizer
  • инспекция Vite build report

Цель — убедиться, что не подключены плагины, которые не были явно зарегистрированы.


Принципы устойчивой архитектуры плагинов

Эффективная работа с плагинами строится на нескольких принципах:

  • каждый плагин импортируется явно
  • отсутствуют глобальные импорты плагин-пакетов
  • базовое ядро отделено от расширений
  • сборка использует ESM-версии
  • tree-shaking проверяется на этапе сборки

Такой подход обеспечивает предсказуемое поведение и минимальный размер итогового JavaScript-кода.