Наша компания Alan много лет использовала Webpack. Несмотря на то, что этот JS-бандлер во многом нам помог, в конце концов он стал узким местом в разработке. Недавно мы завершили переход на Rspack — альтернативу Rust, обещающую более высокую производительность. Предлагаем краткий рассказ о наших поисках нового бандлера, переходе с Webpack на Rspack и его результатах.
Выбор бандлера
Бандлеры JavaScript — это инструменты, которые упаковывают код и его зависимости в один или несколько JavaScript-файлов, оптимизированных для производительности и загрузки в браузере.
Когда наша компания Alan была запущена в 2016 году, Webpack был де-факто бандлером для JavaScript-приложений. Он прошел проверку на практике, обладал большой экосистемой и предоставлял довольно широкие возможности настройки.
Webpack отлично служил нам все эти годы, но потом стал узким местом в разработке. Наша локальная сборка и горячая замена модулей оказались недостаточно быстрыми:
- первая загрузка при запуске сервера занимала до 45 секунд;
- HMR могла занимать до 15 секунд;
- сборка продакшн-кода занимала более 5 минут на CI.
За прошедшие годы нам удалось улучшить настройку с помощью кэша файловой системы, замены Babel и Terser на Esbuild и прочих мер. Но наступил момент, когда стало трудно добиваться большего повышения производительности без полного переписывания.
Решили оптимизировать петлю обратной связи как в разработке, так и в продакшне, найдя новый бандлер.
За последние несколько лет в экосистеме JavaScript появилось множество новых инструментов сборки — Parcel, Vite, Esbuild, Rspack, Turbopack, Farm, Mako и т. д. Каждый из них обещает свои преимущества в плане улучшения опыта разработчиков и повышения производительности.
Но в Alan отдается предпочтение привычным технологиям. Мы не стремимся использовать технологические инновации, требующие от инженеров глубокого изучения новых концепций или траты времени на преодоление проблем с инструментарием. Придерживаясь этого подхода, мы приступили к изучению двух новых бандлеров — Vite и Rspack.
Vite
В прошлом мы уже рассматривали возможность перехода на Vite, поскольку он стал очень популярным инструментом в экосистеме React. Vite — удивительный инструмент с совершенно особым подходом: он не связывает активы в процессе разработки, что позволяет быстрее запускать серверы и производить горячую замену модулей. Однако мы обнаружили, что Vite нам не подходит по следующим причинам:
- Vite использует разные инструменты для сборок разработки и продакшна (Esbuild в разработке, Rollup в продакшне). Это может привести к расхождениям между сборками разработки и продакшна, а также затруднить отладку проблем в процессе сборки.
- Некомплектный подход Vite к разработке часто приводил к перегрузке сети браузера из-за большого количества модулей в приложении. Эту проблему можно было бы устранить, но оптимизация заняла бы слишком много времени.
- Vite сильно отличается от Webpack. Нам пришлось бы переписать всю конфигурацию сборки, что чревато большими временными затратами и появлением ошибок.
Rspack
В начале 2023 года появился новый бандлер — Rspack. Его разработчики обещали совместимость с Webpack, но с огромным приростом производительности (в частности, благодаря экосистеме Rust).
Хотя Alan — противник внедрения совершенно новых технологий, обещания разработчиков Rspack были столь соблазнительны, что мы решили попробовать его в течение кулдаун-недели — относительно свободной недели между кварталами (без установленной дорожной карты), позволяющей спокойно изучить новые идеи.
Процесс перехода на новый бандлер
Этап экспериментов
Поскольку конфигурация Webpack в основном совместима с Rspack, первоначальный этап подтверждения концепции был довольно прост. Для несовместимых частей мы реализовали небольшой слой совместимости, преобразующий любую конфигурацию Webpack в конфигурацию Rspack. Этот слой решал следующие проблемы:
- удаление ненужных загрузчиков (например,
css-loader
);
- замена некоторых плагинов на их эквиваленты в Rspack (например,
html-webpack-plugin
наrspack.HtmlWebpackPlugin
);
- замена наших загрузчика и минификатора Esbuild на встроенные с помощью SWC.
Для слоя совместимости потребовалось всего ~200 строк кода, поскольку Rspack был разработан как замена Webpack.
А производительность в результате оказалась впечатляющей:
- локальная первоначальная сборка происходила в 3 раза быстрее, чем в Webpack (время сократилось с 16 с до 6 с);
- горячая замена модулей осуществлялась в 20 раз быстрее, чем в Webpack (время сократилось с 7 с до 400 мс).
Более того, эти цифры не позволяют оценить истинного прироста производительности, поскольку:
- мы сравнивали Webpack без карт исходного кода с Rspack с картами исходного кода (в Webpack карты исходного кода стали настолько медленными, что мы не включали их по умолчанию в разработке);
- мы использовали кэш файловой системы для Webpack, в то время как Rspack вообще не предполагает кэша.
На этом этапе у нас возникло несколько проблем, связанных с ранней стадией реализации проекта Rspack: мы не могли наладить SSR-конфигурацию, извлечение CSS не было готово, и возникали HMR-ошибки. Но все остальное работало достаточно хорошо, чтобы позволить инженерам подключиться к Rspack в процессе разработки и посмотреть, как все пойдет.
Мониторинг опыта реальных пользователей
Хотя мы сразу увидели преимущества Rspack в локальной разработке, все же хотели убедиться, что значительно улучшили опыт разработчиков.
Решили собирать данные о начальных сборках и обновлениях HMR. Эти данные собирались с компьютеров наших разработчиков и отправлялись в Datadog, чтобы их можно было легко визуализировать.
Благодаря Unplugin мы реализовали очень простой плагин, совместимый как с Webpack, так и с Rspack.
Это позволило подтвердить оптимизацию опыта всех наших инженеров, и не только в конкретных сценариях.
Прогрессивное развертывание
По мере совершенствования Rspack и перехода от версии 0.1 к первой стабильной версии v1.0 мы продолжали модернизировать и улучшать нашу систему.
Начали переносить на Rspack небольшие внутренние проекты. Процесс миграции для каждого проекта выглядел следующим образом:
- Локальное использование Rspack с помощью переменной среды
BUNDLER=rspack
.
- Назначение Rspack локальным бандлером по умолчанию (и разрешение отказаться от использования
BUNDLER=webpack
).
- Переключение продакшн-сборки на Rspack.
- Удаление поддержки Webpack.
Переменная среды BUNDLER
была ключевой для сбора большого количества информации о Rspack без излишних ограничений для инженеров. Установка переменной в rspack
позволит:
- переключить используемый в разработке бандлер на Rspack;
- добавить больше полезной для инженеров информации в консольный вывод (например, ссылки на внутреннюю документацию по Rspack, подсказки, к кому обращаться в случае проблем и как переключиться обратно на Webpack).
В каждом проекте, в котором был реализован переход с Webpack на Rspack, мы видели мгновенное улучшение времени сборки. Это позволяло постепенно переводить все более сложные части кодовой базы на Rspack.
Некоторые внутренние проекты мы переводили на новый бандлер параллельно. В то же время ждали, пока Rspack станет стабильным для более важных проектов. В конце концов единственным проектом, все еще работающим на Webpack, осталось приложение, обслуживающее целевые страницы, с рендерингом на стороне сервера (мы ждали выхода Rspack v1.0, чтобы перейти на эту версию).
Завершение переноса
Со временем все проблемы, с которыми мы столкнулись при работе с Rspack, были решены либо с помощью новых версий, либо путем изменения конфигурации.
Когда на прошлой неделе Rspack достиг своей первой стабильной версии, мы были готовы перевести на нее наше последнее приложение.
В завершение этапа переноса мы сделали следующее:
- перевели последнее приложение на Rspack для разработки и продакшна;
- удалили слой совместимости и начали использовать конфиги Rspack в качестве единственного источника истины.
Мы также заменили webpack5-сборщика Storybook на storybook-rsbuild (Rsbuild — это слой абстракции над Rspack, который совместим со Storybook).
Результаты
Производительность
Хотите увидеть реальные цифры? Если взять статистику по одному из наших самых сложных проектов, то улучшения очевидны:
+---------------------+---------+--------------+
| | Webpack | Rspack |
+---------------------+---------+--------------+
| Dev - Первоначальная сборка | 16.17 с | 5.99 с (-62%) |
| Dev - HMR | 2.90 с | 700 мс (-72%) |
| Prod - Сборка | 2 мин. 10 с | 34 с (-86%) |
+---------------------+---------+--------------+
А время сборки Storybook сократилось с 2 мин 25 с до 33 с (-88%).
Удобство обслуживания
Мы смогли обойтись без множества шаблонных настроек, поскольку Rpsack предлагает замечательные настройки по умолчанию «из коробки»:
- удалили css-loader, style-loader, resolve-url-loader и mini-css-extract-plugin в пользу experiments.css в Rspack;
- заменили свой пользовательский esbuild-loader на встроенный swc-loader;
- удалили webpack-bundle-analyzer в пользу более функционального Rsdoctor (совместимого и с Rspack, и с Webpack).
Кроме того, пропала необходимость поддерживать собственный кэш файловой системы в процессе разработки (и иногда удалять его вручную), поскольку Rspack работает быстро без кэша.
Внутренние отзывы
Обратная связь от команды была очень положительной. Для кого-то переход на Rspack стал переломным моментом в фронтенд-разработках за последний год. К тому же Rspack намного упростил разработку фронтенда.
Взгляд в будущее бандлеров
Мы с энтузиазмом смотрим в будущее бандлеров. Мы очень довольны Rspack, но также внимательно следим за тем, что происходит с Vite (с особым нетерпением ждем предстоящего выпуска Rolldown — Rust-альтернативы Rollup).
Команда разработчиков Rspack выпустила Rsbuild с более высоким уровнем абстракции сборки, чем у Rspack. Rsbuild предлагает замечательные настройки по умолчанию, обеспечивает высокую производительность и обладает множеством функций «из коробки».
Вся экосистема также быстро развивается, принимая бандлеры нового поколения. Например, мы полагаемся на Docusaurus при создании внутренней документации и ждем не дождемся, когда его разработчики завершат переход с Webpack на Rspack!
Если вы подумываете о переходе с Webpack на Rspack, настоятельно рекомендуем попробовать!
Читайте также:
Читайте нас в Telegram, VK и Дзен
Перевод статьи Tim Petricola: A bundler story: migrating from Webpack to Rspack