Что такое сборщик модулей и зачем он нужен

Современные JavaScript-приложения редко состоят из одного файла. Даже небольшой проект обычно включает десятки или сотни модулей:

  • JavaScript-файлы
  • стили CSS и SCSS
  • изображения
  • шрифты
  • SVG
  • конфигурации
  • шаблоны
  • JSON-файлы

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

  • большое количество HTTP-запросов;
  • медленная загрузка;
  • сложность управления зависимостями;
  • конфликт глобальных переменных;
  • дублирование кода;
  • отсутствие оптимизации.

Сборщик модулей решает эти задачи, объединяя проект в оптимизированный набор файлов для браузера.

Webpack относится именно к таким инструментам.


Как работал JavaScript до появления сборщиков

Ранние JavaScript-приложения подключались через обычные теги <script>:

<script src="utils.js"></script>
<script src="api.js"></script>
<script src="app.js"></script>

Такой подход создавал множество ограничений.

Глобальная область видимости

Все переменные оказывались в window.

var user = {};

Если другой файл содержал:

var user = [];

возникал конфликт.


Жёсткий порядок подключения

Если app.js использовал функцию из utils.js, то подключение должно было идти строго по порядку.

Ошибка последовательности ломала приложение.


Отсутствие изоляции

Файлы могли случайно изменять данные друг друга.


Масштабирование становилось проблемой

Когда проект разрастался до сотен файлов:

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

Появление модульной системы

Для решения этих проблем появились модульные системы.

CommonJS

Использовалась в Node.js.

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

console.log(math.sum(2, 3));

Экспорт:

module.exports = {
  sum
};

ES Modules

Современный стандарт JavaScript.

import { sum } from './math.js';

console.log(sum(2, 3));

Экспорт:

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

Модули позволили:

  • изолировать код;
  • управлять зависимостями;
  • разбивать приложение на части;
  • улучшить читаемость.

Но появилась новая проблема.


Почему модулей недостаточно без сборщика

Даже при использовании ES Modules остаются ограничения.

Большое количество запросов

Если приложение состоит из 500 модулей, браузер должен загрузить 500 файлов.


Невозможность обработки нестандартных ресурсов

Браузер не умеет импортировать:

import './styles.scss';

или:

import logo from './logo.svg';

без дополнительной обработки.


Отсутствие оптимизации

Исходный код обычно содержит:

  • комментарии;
  • неиспользуемые функции;
  • дубли;
  • неэффективные импорты.

Проблемы совместимости

Некоторые возможности JavaScript поддерживаются не всеми браузерами.

Например:

const user = profile?.user?.name;

Старые браузеры не понимают optional chaining.


Роль Webpack

Webpack анализирует проект как граф зависимостей и преобразует его в набор файлов, готовых к запуску в браузере.

Процесс выглядит так:

  1. Webpack находит входную точку.
  2. Анализирует импорты.
  3. Строит дерево зависимостей.
  4. Обрабатывает каждый ресурс.
  5. Объединяет результат.
  6. Выполняет оптимизацию.
  7. Генерирует финальные файлы.

Что такое граф зависимостей

Webpack рассматривает приложение как цепочку связанных модулей.

Например:

import { render } from './ui';

Webpack обнаруживает зависимость:

app.js
 └── ui.js

Если ui.js импортирует другие файлы:

import './styles.css';
import Button from './Button';

граф расширяется:

app.js
 └── ui.js
      ├── styles.css
      └── Button.js

Webpack рекурсивно проходит по всем зависимостям.


Что именно умеет Webpack

Объединение файлов

Множество модулей превращаются в несколько оптимизированных bundle-файлов.


Минификация

Исходный код:

function sum(a, b) {
  return a + b;
}

После минификации:

function n(n,r){return n+r}

Размер уменьшается.


Удаление неиспользуемого кода

Технология называется Tree Shaking.

Пример:

export function used() {}
export function unused() {}

Если импортируется только:

import { used } from './math';

Webpack может удалить unused.


Транспиляция

Webpack интегрируется с Babel.

Современный код:

const result = user?.profile?.name;

превращается в совместимый со старыми браузерами JavaScript.


Обработка стилей

Webpack умеет:

  • импортировать CSS;
  • компилировать SCSS;
  • работать с PostCSS;
  • добавлять vendor prefixes;
  • минимизировать стили.

Работа с изображениями

Изображения можно импортировать как модули:

import logo from './logo.png';

Webpack:

  • копирует файл;
  • генерирует имя;
  • оптимизирует изображение;
  • возвращает путь.

Разделение кода

Приложение можно загружать частями.

import('./admin');

Webpack создаёт отдельный chunk.

Код загрузится только при необходимости.


Hot Module Replacement

Во время разработки изменения применяются без полной перезагрузки страницы.

Это ускоряет разработку.


Почему Webpack стал популярным

Webpack объединил множество задач в одном инструменте.

До него разработчикам приходилось отдельно использовать:

  • минификаторы;
  • конкатенаторы;
  • обработчики CSS;
  • транспиляторы;
  • оптимизаторы изображений.

Webpack создал единую экосистему.


Основные проблемы, которые решает Webpack

Производительность

Webpack уменьшает:

  • количество запросов;
  • размер файлов;
  • объём неиспользуемого кода.

Поддерживаемость

Проект разделяется на независимые модули.


Масштабирование

Большие приложения становятся управляемыми.


Автоматизация

Webpack автоматизирует:

  • сборку;
  • оптимизацию;
  • генерацию файлов;
  • обработку ресурсов.

Кроссбраузерность

Через Babel и дополнительные loaders обеспечивается поддержка старых браузеров.


Что происходит во время сборки

Процесс сборки называется build.

Во время него Webpack:

1. Читает entry point

Например:

entry: './src/index.js'

2. Строит граф зависимостей

Анализируются все import.


3. Применяет loaders

Каждый файл проходит обработку.

Например:

test: /\.scss$/

означает обработку SCSS.


4. Применяет plugins

Плагины изменяют процесс сборки.


5. Генерирует bundles

Создаются итоговые файлы.


Что такое bundle

Bundle — итоговый файл, созданный Webpack.

Например:

main.bundle.js
vendors.bundle.js

Внутри bundle находятся:

  • модули;
  • зависимости;
  • служебный runtime-код Webpack.

Почему нельзя просто использовать ES Modules без Webpack

Теоретически современные браузеры поддерживают ES Modules.

Однако на практике Webpack всё ещё нужен.

Причины

Оптимизация

Браузер не минимизирует код автоматически.


Разделение vendor-кода

Webpack умеет отделять библиотеки от основного приложения.


Работа со стилями

Браузер не понимает SCSS.


Обработка ассетов

Импорт изображений требует сборщика.


Tree Shaking

Webpack удаляет лишний код.


Production-режим

Webpack создаёт оптимизированные production-сборки.


Концепция единого пайплайна

Webpack рассматривает всё как модули:

  • JavaScript;
  • CSS;
  • изображения;
  • SVG;
  • шрифты.

Например:

import './styles.scss';
import logo from './logo.svg';

Это одна из ключевых идей Webpack.


Архитектура Webpack

Webpack состоит из нескольких основных компонентов.

Entry

Точка входа.

entry: './src/index.js'

Output

Настройки выходных файлов.

output: {
  filename: 'bundle.js'
}

Loaders

Преобразуют файлы.

Например:

  • Babel Loader
  • CSS Loader
  • Sass Loader

Plugins

Расширяют возможности Webpack.

Например:

  • генерация HTML;
  • очистка папки;
  • извлечение CSS.

Mode

Режим сборки.

mode: 'development'

или:

mode: 'production'

Development и Production

Development

Приоритет:

  • скорость сборки;
  • удобство отладки;
  • source maps.

Production

Приоритет:

  • минимальный размер;
  • производительность;
  • оптимизация.

Webpack автоматически меняет поведение в зависимости от режима.


Почему сборщик особенно важен для SPA

Одностраничные приложения содержат:

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

Без сборщика такие проекты становятся практически неуправляемыми.

Webpack обеспечивает:

  • lazy loading;
  • code splitting;
  • оптимизацию vendor chunks;
  • кэширование.

Эволюция фронтенд-разработки и роль Webpack

Рост популярности:

  • React
  • Vue
  • Angular

резко увеличил сложность фронтенд-приложений.

Webpack стал центральным инструментом инфраструктуры:

  • React Scripts;
  • Vue CLI;
  • Angular CLI;
  • Next.js;
  • Nuxt;
  • Storybook.

Многие инструменты скрывают конфигурацию Webpack, но продолжают использовать его внутри.


Пример типичной задачи без Webpack

Необходимо:

  • объединить JS;
  • скомпилировать SCSS;
  • оптимизировать изображения;
  • минимизировать код;
  • обновлять браузер при изменениях.

Без сборщика потребуется множество отдельных инструментов.

Webpack объединяет всё в единую систему.


Ограничения и сложность Webpack

Несмотря на мощность, Webpack известен сложностью конфигурации.

Причины:

  • большое количество настроек;
  • сложная экосистема loaders;
  • разнообразие plugins;
  • высокая гибкость.

Именно поэтому появились более простые инструменты:

  • Vite
  • Parcel
  • esbuild

Тем не менее Webpack остаётся одним из самых мощных и гибких сборщиков.


Когда Webpack особенно полезен

Крупные SPA


Многостраничные приложения


Проекты со сложной инфраструктурой


Приложения с большим количеством ассетов


Системы с legacy-поддержкой


Основная идея Webpack

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

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

  • анализировать;
  • преобразовывать;
  • оптимизировать;
  • разделять;
  • собирать в итоговый bundle.