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-функції. Потім плагіни виконують додаткові перетворення: мініфікацію, інлайнінг зображень, генерацію 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також