Наша компания 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 небольшие внутренние проекты. Процесс миграции для каждого проекта выглядел следующим образом:

  1. Локальное использование Rspack с помощью переменной среды BUNDLER=rspack.
  1. Назначение Rspack локальным бандлером по умолчанию (и разрешение отказаться от использования BUNDLER=webpack).
  1. Переключение продакшн-сборки на Rspack.
  1. Удаление поддержки 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 предлагает замечательные настройки по умолчанию «из коробки»:

  • заменили свой пользовательский 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

Предыдущая статьяМой первый опыт работы с языком Gleam 
Следующая статья11 общедоступных аналогов SaaS: собственный хостинг с Docker