Как стать автором
Обновить

Снимаем оковы Webpack: как мы ускорили сборку проекта в 10 раз, потратив меньше рабочего дня

Уровень сложностиСредний
Время на прочтение6 мин
Количество просмотров4.2K

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

Это касается и одного из самых ключевых этапов в разработке - сборка проекта. Множество проектов, на которых я работал, собирались (и собираются) с помощью Webpack. Это классический и проверенный временем инструмент: со своими преимуществами и недостатками.  

В какой-то момент недостатки стали перешивать:  

  • Время сборки: среднее время ожидание сборки нашего проекта на достаточно среднем ПК составляет около 3-х минут. До этого активно предпринимались попытки оптимизировать скорость сборки (esbuild-loader, например); 

  • HMR (Hot Module Replacement): составлял, в среднем, около 8-12 секунд, что также сложно назвать плюсом; 

  • Сложность конфигурации: необходимость подключения скриптов, плагинов (HtmlWebpackPlugin, miniCssExrtactPlugin, HMR, EnvironmentPlugin и т.д).

Мы задумались об альтернативах. И единственным подходящим вариантом для нас показался Vite из-за его простой, а главное быстрой сборки. А получилось ли у нас успешно мигрировать и каких результатов мы достигли, я и расскажу в данной статье. 

Почему именно Vite? 

1. Актуальность, экосистема 

С одной стороны, Webpack, выпущенный уже более 13 лет назад, до сих пор остается актуальным сборщиком, согласно статистике по скачиваниям с npmjs. 

С другой стороны, относительно молодой Vite, дебютировавший в 2020 году, актуальность которого с каждым годом активно растёт.  

Что Webpack, что Vite регулярно обновляются, а также, судя по статистике Npm, активно используются. Несмотря на уже солидный возраст существования Webpack, выпущен 13 лет назад, Vite, дебютировавший в 2020 году, не сильно от него отстаёт.  

Более того, пока популярность Webpack находится на плато, у Vite она только растёт. 

Статистика загрузок (2020 – 2024 год) с npmjs
Статистика загрузок (2020 – 2024 год) с npmjs
Vite: статистика загрузок  (2020 – 2024 год) с npmjs
Vite: статистика загрузок (2020 – 2024 год) с npmjs
Иллюстрация спроса на использование Webpack и Vite в разных странах в период с 2020–2024 год, согласно Google trends. Топ страны по использованию Webpack: Беларусь, Китай (родина Vite, внезапно) и Россия 
Иллюстрация спроса на использование Webpack и Vite в разных странах в период с 2020–2024 год, согласно Google trends. Топ страны по использованию Webpack: Беларусь, Китай (родина Vite, внезапно) и Россия 

2.Базовая конфигурация 

Vite предлагает простую «нулевую» настройку, где достаточно использовать один плагин для запуска приложения. Настройка сервера разработки, параметры сборки уже предустановлены по умолчанию в настройках самого Vite: 

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https: //vite.dev/config/
export default defineConfig({
plugins: [react()]

Webpack: необходимо указать точки входа, выхода, плагины, модули (загрузчики по типу babel/css-loader) 

export default (): webpack.Configuration => ({
mode: 'development',
entry: path.resolve (__dirname,'src','index.tsx'),
output: {
  filename: 'test-bundle.js',
  path: path.resolve(__dirname, 'dist'),
},
plugins: [
  new HtmlWebpackPlugin ({
  template: path.resolve (__dirname, 'public','index.html'),
  }),
],
module: {
  rules: [
    { test: /\.(js|jsx|tsx)$/, exclude: /node_modules/,use: 'babel-loader' },
    { test: /\.css$/,use:['style-loader','css-loader']},
 ],
},
resolve: {
  extensions: ['.tsx','.ts', '.js'],
  mainFiles: ['index'],
},
devServer: {
  port: 3000,
  open: true,
  hot: true,
},
});

Наш конфиг в Webpack составлял под 200+ строк.  

Vite вышел примерно в 60 строк кода с максимально простым и понятным конфигом. 

3. Время сборки (dev) 

При первом запуске в Webpack, происходит следующая цепочка действий: 

  • Чтение всех файлов, начиная с точки входа; 

  • Определение зависимостей; 

  • Обработка через скрипты (Babel), плагины; 

  • Генерация бандлов. 

В данном случае происходит линейная обработка всех файлов. С учетом увеличения их количества растягивается время начальной сборки. 

Конечно, есть варианты оптимизации: кэширование результатов лоадеров, разделения кода на чанки, многопоточная обработка с помощью thread-loader, замена Babel на esbuild-loader и многое другое. И результат действительно есть, но хочется все ещё быстрее и, в идеале, попроще. 

На Vite же, принцип работы строится вокруг деления приложения на зависимости (node_modules) и исходный код: 

  • Зависимости, которые предварительно собираются с помощью esbuild - бандлер, написанный на Go, в задачи которого входят: транспиляция и минификация; 

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

Vite запускает сервер практически мгновенно за счет использования инструментов ESM, esbuild и отсутствия бандлинга в dev-режиме. 

4. HMR  

Hot Module Replacement (HMR), она же - горячая замена модулей - механизм, связанный с обновлением модулей на клиенте при их изменении на сервере. По результатам миграции, HMR на Vite происходит практически мгновенно (~40-50мс). На Webpack этот процесс занимает чуть дольше (~400мс на основном проекте). Несмотря на достаточно быструю реакцию со стороны обоих сборщиков, Vite выходит победителем, причем данные показатели сохраняются как на пустом, так и на мигрированном проекте. 

За счёт чего достигается такая разница в скоростях HMR? 

На Webpack при включении плагина HotModuleReplacementPlugin внедряется HMR Runtime, который получает уведомления об изменениях на сервере и, при изменении модулей (загрузка/замена/удаление), генерирует и применяет соответствующие обновления для этих модулей. Даже при изменении одного файла, HMR runtime необходимо провести: 

  1. Анализ графа зависимостей - поиск модулей, которые находятся в зависимости от изменённого файла. Если измененный файл является зависимостью для других модулей, они также будут пересобраны; 

  2. Пересборку этих модулей с обновлением маппинга; 

  3. Отправку в браузер обновленных изменений в виде JSON (the updated manifest). 

Есть следующая структура зависимостей: 

App.js -> Component.js -> data.js 

index.js -> data.js 

При изменении файла “data.js” (например, добавлен комментарий), произойдет пересборка всех зависимых модулей, т.е: 

- data.js;

- Component.js; 

- App.js;

- index.js.

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

На Vite используется ESM-ориентированный подход с использованием HMR API (встроенный плагин, не требует дополнительных установок), который использует нативные возможности браузера для точечных обновлений и включает следующие этапы при изменении файла: 

  1. Обработка измененного файла через плагины (например, TypeScript -> JavaScript); 

  2. HMR Update: отправка уведомления от сервера к браузеру; 

  3. Перезагрузка модуля через динамический импорт  

Используя пример с структурой файлов выше, изменения затронут только файл data.js: изменения файла -> транспиляция -> динамическое обновление модуля (зависимые модули Component.js, App.js и index.js также остаются в кеше, но их зависимости обновляются).  

Подводя итоги, ключевыми отличиями HMR от Webpack можно выделить: 

  • Отсутствие пересборки зависимостей; 

  • Минимальная нагрузка на сеть: загрузка только изменённого data.js, вместо JSON со всеми зависимостями (как на Webpack); 

  • Кеширование модулей: Kek.js, App.js, Index.js остаются в кеше браузера, пока не изменятся. 

Дополнительно, оставлю небольшие замеры скорости холодного старта (в dev) и HMR на пустом и нашем проекте: 

В качестве железа используется ноутбук со следующими характеристиками: 

  • Ryzen 7 4800H; 

  • Оперативной памяти 16гб;

  • OS Ubuntu версии 24.04. 

Пустой проект
Пустой проект
Основной проект
Основной проект

Процесс миграции на Vite

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

  • Включение плагинов (react, tailwindcss, mkcert); 

  • Определили env-переменные через define; 

  • Настроили rollupOptions в build.

И вуаля! Практически с первого раза, наш фронтенд завёлся без каких-либо явных проблем. 

Бонусом: на замену Jest, подключили Vitest , обладающего своими преимуществами по сравнению c Jest

  • Несложная миграция за счёт API, похожего на Jest; 

  • Не требует отдельных конфигурационных файлов (jest.config.js). Vitest использует тот же vite.config.ts. Нет необходимости дублировать настройки (транспиляции, алиасы).

О недостатках переезда на Vite 

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

  • Необходимость немного покопаться в rollupOptions: prod-сборка по времени +- не изменилась, но иногда она занимает чуть больше времени, чем на Webpack; 

  • Module Federation: микрофронтенды с первого раза завести не удалось. Shared-зависимости 1 микрофронтенда в Webpack имели примерно следующую структуру: 

shared: {
'some-library': {
// Загружаем модуль только один раз
singleton: true, 
// Минимальная версия для загрузки 
requiredVersion: '99.09',
// Загрузка модуля сразу при инициализации приложения
eager: true, 
},

На Vite каждая shared-зависимость включала в себя лишь requiredVersion и микрофронты изначально не завелись, ссылаясь на несовпадения версий. По итогу shared-зависимости просто были переданы массивом, и они заработали. 

Заключение 

Vite - очень быстрый и простой по настройкам сборщик, который в нашем кейсе оправдал себя на 100%: 

  • Успешно и практически бесшовно переехали на новый сборщик; 

  • Легко настроили его конфиг под наши потребности; 

  • Сократили время сборки (в dev) минимум в 25–30 раз; 

  • Идеально работающий HMR;

  • Подключили новый для нас инструмент для тестирования (Vitest).

 

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
А на чьей стороне ты?
71.43% Vite35
16.33% Webpack8
12.24% Свой вариант оставлю в комментариях6
Проголосовали 49 пользователей. Воздержались 5 пользователей.
Теги:
Хабы:
Всего голосов 6: ↑6 и ↓0+6
Комментарии6

Публикации

Работа

Ближайшие события