Bundler — инструмент сборки, который объединяет множество модулей JavaScript в один или несколько файлов для использования в браузере или мобильном приложении. Современные бандлеры (Webpack, Metro, Vite) не только склеивают файлы, но и выполняют транспиляцию, минификацию и оптимизацию ресурсов. По данным Webpack Concepts (2026), грамотная настройка бандлера сокращает размер сборки на 40–60% без потери функциональности.
Главное
Bundler (сборщик модулей) — это инструмент командной строки, который принимает на вход точку входа (entry point) — главный файл приложения — и рекурсивно обходит все его зависимости, строя граф модулей. На выходе бандлер генерирует один или несколько файлов, которые можно подключить в HTML-страницу или запустить в мобильном приложении.
Браузеры долгое время не поддерживали модульную систему JavaScript на уровне платформы. Bundler решал эту проблему, превращая сотни import и require в единый файл. Сегодня, даже с нативной поддержкой ES модулей в браузерах, бандлеры выполняют дополнительные задачи: транспиляция JSX и TypeScript, минификация кода, code splitting для ленивой загрузки и hot module replacement (HMR) для ускорения разработки.
В мобильной разработке React Native использует Metro как бандлер по умолчанию, а Flutter — собственную систему сборки на основе Dart. Выбор бандлера напрямую влияет на скорость разработки, размер приложения и производительность runtime.
Бандлинг проходит несколько этапов: парсинг входных файлов, построение графа зависимостей, преобразование модулей и генерация выходных файлов. На каждом этапе бандлер применяет лоадеры для трансформации исходного кода и плагины для оптимизации.
Бандлер начинает с точки входа, читает файл и строит AST (абстрактное синтаксическое дерево). Из AST извлекаются все операторы import и require. Для каждого найденного импорта бандлер повторяет процесс рекурсивно, пока все зависимости не будут собраны в единый граф.
// Упрощённая реализация бандлера
const fs = require('fs');
const path = require('path');
function buildGraph(entry) {
const content = fs.readFileSync(entry, 'utf-8');
const imports = content.match(/require\(['"](.+?)['"]\)/g);
const modulePath = path.resolve(path.dirname(entry), imports[0]);
return { entry, content, deps: [buildGraph(modulePath)] };
}
После построения графа бандлер применяет лоадеры — трансформации, которые конвертируют файлы в JavaScript: TypeScript → JS, SCSS → CSS, JSX → JSX-функции. Затем plugins выполняют дополнительные преобразования: минификация, инлайнинг изображений, генерация service worker.
Бандлеры делятся на три поколения: классические, специализированные и нового поколения на основе ES модулей. Каждый тип имеет собственную архитектуру и область применения.
Webpack — самый распространённый бандлер с огромной экосистемой. Его главное преимущество — гибкость: тысячи лоадеров и плагинов покрывают практически любой сценарий сборки. Parcel предлагает zero-config подход, автоматически определяя необходимые трансформации на основе расширений файлов. Оба бандлера поддерживают code splitting и HMR.
Metro создан специально для React Native и работает только с JavaScript и TypeScript. Его архитектура оптимизирована для мобильной разработки: поддержка inline requires, асинхронная загрузка модулей и интеграция с Hermes engine. Rollup ориентирован на библиотеки и npm-пакеты, генерируя чистый ES модульный вывод без лишней обёртки.
Выбор бандлера зависит от платформы и требований проекта. Webpack универсален, но требует детальной настройки. Metro безальтернативен для React Native. Vite обеспечивает самую быструю разработку благодаря нативным ES модулям.
| Характеристика | Webpack | Metro | Vite |
|---|---|---|---|
| Платформа | Веб, универсальная | React Native | Веб, универсальная |
| Скорость dev-сборки | Средняя | Высокая | Очень высокая |
| Code splitting | Да | Да | Да |
| HMR | Да | Fast Refresh | Мгновенный HMR |
| Экосистема плагинов | Огромная | Ограниченная | Растущая |
| Конфигурация | Сложная | Простая | Простая |
| Поддержка TypeScript | Через лоадеры | Встроенная | Встроенная |
Vite использует esbuild для пре-бандлинга зависимостей и Rollup для production-сборки, что даёт прирост скорости в 5–10 раз по сравнению с Webpack в режиме разработки. Metro не поддерживает веб-таргеты, но обеспечивает бесшовную интеграцию с React Native bridge и Turbo Modules.
Конфигурация бандлера определяет, как обрабатываются разные типы файлов, куда генерируется сборка и какие оптимизации применяются. Типовой файл конфигурации включает точку входа, правила для модулей, плагины и настройки вывода.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
},
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react'] } },
},
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
],
},
plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
devServer: { port: 3000, hot: true },
};
Metro использует отдельные файлы metro.config.js и babel.config.js для настройки. В отличие от Webpack, конфигурация Metro значительно проще, поскольку бандлер специализирован под React Native и не требует настройки лоадеров для стилей или изображений.
Даже опытные разработчики сталкиваются с ошибками бандлинга. Duplicate module — одна из самых частых проблем, когда одна и та же зависимость попадает в бандл несколько раз из-за несовместимости версий в package.json. Module not found возникает, когда путь импорта указан неверно или пакет не установлен.
Metro ограничен размерами бандла для мобильных устройств. При превышении лимита в 2–5 МБ возникает ошибка Unable to resolve module из-за нехватки памяти на устройстве. Решение — использовать inline requires и RAM bundles для ленивой загрузки модулей. Также Metro чувствителен к симлинкам, поэтому для монорепозиториев требуется дополнительная настройка watchFolders в конфигурации.
Для Webpack типичная проблема — Module parse failed, когда файл имеет неожиданный формат или отсутствует необходимый лоадер. Проверка расширения файла и добавление соответствующего правила в module.rules решает проблему. Использование source-map-explorer помогает найти дублирующиеся модули и избыточные зависимости в финальном бандле.
Медленная сборка — одна из главных проблем при работе с бандлерами. Для ускорения используйте persistent caching, который сохраняет результаты трансформации модулей между запусками. Webpack 5 поддерживает файловый кэш через cache: { type: 'filesystem' }, Vite использует esbuild для пре-бандлинга, а Metro опирается на модульный кэш в памяти. Дополнительно укажите exclude для node_modules в лоадерах, чтобы не обрабатывать уже готовые пакеты повторно.
Code splitting — разделение бандла на чанки, загружаемые по требованию. Разные бандлеры реализуют эту стратегию по-своему. Webpack поддерживает динамический импорт import(), создающий отдельные чанки для каждого модуля. Metro использует inline requires для отложенной загрузки. Vite автоматически разделяет vendor-чанки и динамические импорты без дополнительной конфигурации. Выбор стратегии зависит от требований проекта: для мобильных приложений предпочтительны меньшие начальные бандлы с ленивой загрузкой.
Для корректной работы code splitting в React Native требуется дополнительная настройка: Metro должен быть сконфигурирован для работы с асинхронными чанками через inlineRequires. В Webpack и Vite code splitting работает из коробки при использовании динамического синтаксиса import(), который автоматически создаёт точки разделения. Для максимальной эффективности комбинируйте code splitting с preload-подсказками через <link rel="preload"> для критических чанков.
Часто задаваемые вопросы
Для простых проектов без JSX, TypeScript или CSS-модулей можно обойтись нативными ES модулями в браузере. Однако для production-сборки бандлер обеспечивает минификацию, tree shaking и code splitting, которые критичны для производительности. Без бандлера сложно поддерживать модульную архитектуру в больших проектах.
Для React Native — Metro (единственный поддерживаемый вариант). Для веб-приложений — Vite для новых проектов (благодаря скорости) или Webpack для существующих с богатой экосистемой. Для библиотек и npm-пакетов — Rollup, так как он генерирует чистый ES модульный вывод.
Бандлер напрямую определяет размер финального JS-бандла. Webpack с tree shaking может сократить размер на 30–50%. Metro для React Native поддерживает Hermes bytecode, который уменьшает размер на 20–30% по сравнению с обычным JavaScript. Code splitting позволяет загружать модули по требованию, уменьшая стартовый бандл.
Для веба бандлер генерирует код, совместимый с разными браузерами, и поддерживает CSS, изображения и шрифты. Для мобильных платформ Metro генерирует код для JavaScript-движка (Hermes или JSC), не обрабатывает CSS или HTML и оптимизирует сборку под ограниченные ресурсы устройства.
Да, существуют проекты, которые используют Webpack для веб-части и Metro для React Native — например, в монолитных репозиториях с общей кодовой базой. Однако это усложняет конфигурацию CI/CD и требует синхронизации версий зависимостей. Рекомендуется использовать единый бандлер для всех таргетов, если это возможно.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также