Фото Seth Doyle на Unsplash
В Alan ми використовували Webpack протягом кількох років. Хоча він прекрасно виконував свої функції, з часом став вузьким місцем для розробки. Нещодавно ми завершили міграцію на Rspack, альтернативу на Rust, яка обіцяє кращу продуктивність. Це коротка історія нашого шляху та здобутих уроків.
Вибір бандлера
Бандлери для JavaScript — це інструменти, які пакують наш код і його залежності в один або кілька JavaScript файлів, оптимізованих для продуктивності та завантаження у браузері.
Коли Alan починав свою діяльність (у 2016 році), Webpack був де-факто бандлером для JavaScript додатків. Він пройшов перевірку часом, мав велику екосистему та широкі можливості для налаштування.
Webpack чудово виконував свою роль протягом усіх цих років, але з часом став вузьким місцем для розвитку.
Наш локальний збір та гаряча заміна модулів (HMR) не були достатньо швидкими:
- перше завантаження при старті сервера могло займати до 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).
Хоча ми й не любимо використовувати новітні технології, обіцянка була настільки привабливою, що ми вирішили спробувати його під час тихого тижня (перехідний тиждень між кварталами, без визначеного плану, що дозволяє експериментувати з новими ідеями).
Наш шлях міграції
Етап експериментів
Оскільки конфігурація Webpack в основному сумісна з Rspack, початкова перевірка концепції була досить простою.
Для несумісних частин ми реалізували невеликий шар сумісності, який перетворював будь-яку конфігурацію Webpack на конфігурацію Rspack. Цей шар обробляв такі моменти, як:
- видалення непотрібних лоадерів (наприклад,
css-loader
) - заміна деяких плагінів на їхні еквіваленти в Rspack (наприклад,
plugin-name
) - заміна плагіна
html-webpack-plugin
наrspack.HtmlWebpackPlugin
- заміна нашого власного лоадера та мінімізатора Esbuild на вбудовані, що використовують SWC
Для шару сумісності знадобилося всього ~200 рядків коду, завдяки тому, що Rspack був спроектований як заміна Webpack "для миттєвого підключення".
І результативність була … вражаюча ⚡:
- часи початкової збірки локально були до 3x швидші за Webpack (з 16с до 6с)
- заміна гарячих модулів була до 20x швидша за Webpack (з 7с до 400мс)
Більше того, ці цифри є заниженим оцінюванням реального приросту продуктивності, оскільки:
- Порівнюються Webpack без sourcemaps з Rspack з sourcemaps (у Webpack sourcemaps були настільки повільними, що ми не вмикали їх за замовчуванням під час розробки).
- Ми використовували кеш файлів для Webpack, тоді як у Rspack взагалі немає кешу.
На цьому етапі ми стикнулися з деякими проблемами, оскільки Rspack був ще дуже молодим проектом: ми не змогли налаштувати нашу конфігурацію SSR, екстракція CSS не була готова, а також траплялися тимчасові помилки HMR.
Але цього було достатньо, щоб ми вирішили дозволити інженерам добровільно перейти на Rspack під час розробки та подивитися, як це працює.
Реальний моніторинг користувачів
Хоча ми одразу побачили переваги Rspack у локальній розробці, ми хотіли переконатися, що значно покращили досвід розробника.
Ми вирішили зібрати дані про початкові збірки та оновлення HMR. Ці дані збиралися на машинах розробників і надсилалися до Datadog для зручного візуалізування.
Ми реалізували дуже простий плагін, сумісний і з Webpack, і з Rspack, завдяки Unplugin
.
Це дозволило нам підтвердити, що покращення були помітні для всіх наших інженерів, а не лише в окремих сценаріях.
Поступовий розгортання
Як тільки Rspack покращився і перейшов від версії 0.1 до стабільної версії v1.0, ми продовжували оновлювати та покращувати нашу конфігурацію.
Ми почали мігрувати невеликі внутрішні проекти на Rspack.
Наш процес міграції для кожного проєкту виглядав так:
- локальне використання Rspack з перемінною середовища
BUNDLER=rspack
- зробити Rspack стандартним локальним бандлером (та дозволити вихід з нього через
BUNDLER=webpack
) - переключити продакшн-збірку на Rspack
- прибрати підтримку Webpack
Перемінна середовища BUNDLER
була ключовою для збору додаткової інформації про Rspack, при цьому не обмежуючи інженерів. Встановлення цієї перемінної на rspack
дозволяло:
- переключити бандлер для розробки на Rspack
- додавати більше інформації в виведення консолі, щоб допомогти інженерам (наприклад, посилання на нашу внутрішню документацію Rspack, вказівки, до кого звертатися у випадку проблем і як повернутись до Webpack)
Під час міграції кожного проєкту ми відразу побачили покращення в часах збірки, і ми змогли поступово переносити все більш складні частини нашого коду на 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%).
Підтримка
Ми також змогли прибрати багато шаблонних налаштувань, оскільки Rspack має чудові налаштування за замовчуванням:
- Прибрали 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 змінив моє життя у фронтенд-розробці за останні 1+ рік.
Rspack зробив фронтенд-розробку набагато простішою!
ВАУ, це значно краще ⚡
Перспективи
Ми дуже захоплені майбутнім бандлерів.
Ми дуже задоволені Rspack, але також уважно слідкуємо за тим, що відбувається з Vite (особливо з майбутнім Rolldown, їхньою альтернативою Rust для Rollup).
Команда, яка стоїть за Rspack, випустила Rsbuild. Це більш високорівневий абстракційний шар над Rspack. Він має чудові налаштування за замовчуванням, забезпечує хорошу продуктивність і багато функцій з коробки.
Уся екосистема також рухається швидко і адаптує це нове покоління бандлерів. Наприклад, ми використовуємо Docusaurus для деякої внутрішньої документації і не можемо дочекатися, коли вони завершать перехід з Webpack на Rspack!
Якщо ви плануєте перейти з Webpack на Rspack, ми настійно рекомендуємо спробувати його!
Перекладено з: A bundler story: migrating from Webpack to Rspack