Эта статья перевод оригинальной статьи «Announcing Rspack 2.3».
Также я веду телеграм канал «Frontend по‑флотски», где рассказываю про интересные вещи из мира разработки интерфейсов и AI.
Вступление
Вышел Rspack 2.3. В релиз вошли парсер SWC Next, ускорение сборки, снижение потребления памяти и размера бандлов, новый экспериментальный кэш с кэшированием отдельных лоадеров и улучшения встроенной поддержки CSS.

Основные изменения касаются интеграции SWC Next, производительности и оптимизации SplitChunks, новой реализации кэша, фильтрации лоадеров по содержимому кода, встроенного CSS и инструментов экосистемы Rstack.
Интеграция SWC Next
SWC Next совместно разрабатывают команды SWC и Rstack. Это новый компилятор JavaScript. Он станет следующей мажорной версией SWC. В основе новой архитектуры парсера, вдохновлённой Yuku, лежит плоское AST на базе ESTree. Оно рассчитано на высокую скорость, экономное использование памяти и расширение средствами JavaScript.
В бенчмарках нативный парсинг SWC Next работает до 3 раз быстрее SWC, а парсинг через JavaScript API работает до 10 раз быстрее.

Команда постепенно переносит модули SWC на эту архитектуру и заменяет существующие реализации Rspack. В Rspack 2.3 уже используется парсер SWC Next: более компактные AST и расположение данных в памяти ускоряют парсинг и обход дерева.
Сравнение времени парсинга и числа инструкций Rspack до и после интеграции SWC Next:
Проект | Время парсинга | Инструкции |
|---|---|---|
three.js | 23 мс → 20 мс (−14%) | 205 млн → 155 млн (−24%) |
React 10k | 207 мс → 193 мс (−6%) | 1597 млн → 1421 млн (−11%) |
Следующий этап развития SWC Next позволит писать высокопроизводительные плагины преобразования на JavaScript. Сейчас для собственных преобразований кода обычно используют плагины Babel или Wasm-плагины SWC. Разработчики хотят объединить производительность Rust с гибкостью написания плагинов на JavaScript. Плоское AST SWC Next позволяет эффективно обмениваться данными между Rust и JavaScript. Лоадер на основе SWC Next с поддержкой JavaScript-плагинов преобразования планируется представить в Rspack 2.4 или 2.5.
Производительность
Снижение потребления памяти и ускорение сборки
Когда несколько агентов работают параллельно, одновременно могут запускаться несколько сборок и серверов разработки, поэтому память становится существенным ограничением. Rspack 2.3.0 потребляет меньше памяти при сборке и разработке. Сравнение RSS в реальном проекте:
Сценарий | Метрика | 2.2.0 | 2.3.0 | Снижение |
|---|---|---|---|---|
Сборка | Пиковый RSS | 28.3 GiB | 20.5 GiB | 27.4% |
Сборка | RSS после сборки | 25.3 GiB | 16.1 GiB | 36.5% |
Разработка | Пиковый RSS при запуске | 28.6 GiB | 19.0 GiB | 33.8% |
Разработка | RSS в установившемся режиме | 28.9 GiB | 18.8 GiB | 34.8% |
В Rspack 2.3 появились снимки памяти на основе allocative, которые помогают находить участки сборки с высоким потреблением памяти. Если проект потребляет много памяти, можно создать и отправить снимки по руководству по диагностике памяти. Они помогут разработчикам найти способы снизить её расход.
SWC Next, оптимизация памяти и другие небольшие улучшения также ускоряют сборку в целом. Бенчмарки показывают прирост около 5% по сравнению с 2.2.0, а в некоторых крупных проектах разработчики наблюдали ускорение до 20%.
Оптимизации SplitChunks
В крупных проектах несколько страниц или точек входа часто зависят от одних и тех же модулей. Если модули попадают в несколько выходных файлов, размер результата увеличивается, а пользователям иногда приходится скачивать один и тот же код повторно. В Rspack 2.3 появились оптимизации, уменьшающие дублирование:
Новый параметр
splitChunks.dedupDepthнаходит больше возможностей вынести общие для страниц и точек входа модули. В production-режиме он включён по умолчанию (dedupDepth: 1).Поддержка
splitChunks.minRemainingSizeпомогает избежать создания очень маленьких выходных файлов при разделении кода. Это может сократить число лишних сетевых запросов и приближает поведение Rspack к webpack.Улучшенная дедупликация модулей при разделении кода позволяет эффективнее повторно использовать существующие модули.
Размеры выходных файлов двух крупных реальных проектов после сжатия Brotli до и после включения dedupDepth: 1:
Проект | До | После | Экономия | Снижение |
|---|---|---|---|---|
A | 23.2 MB | 22.7 MB | 550 KB | 2.4% |
B | 40.0 MB | 36.0 MB | 4.0 MB | 9.9% |
Новая реализация кэша
В Rspack 2.3 появился экспериментальный кэш, который занимает меньше места на диске, снижает затраты на запись и надёжнее восстанавливает результаты. Он устраняет три ограничения старого кэша:
Большие файлы и сложное восстановление. Старый кэш сохранял промежуточное состояние целых этапов сборки, включая связи между модулями. Файлы получались большими, а при восстановлении возникали ошибки. Новый кэш хранит результаты отдельных задач, например сборки модулей, сокращая объём данных и риск ошибок.
Запись кэша блокировала компиляцию. Старый кэш готовил данные для записи на диск во время компиляции, увеличивая время сборки. Новый выполняет эту работу в периоды простоя или в конце сборки, реже прерывая компиляцию.
Ограниченное повторное использование между разработкой и production. Старый кэш был тесно связан с инкрементальной компиляцией при разработке, поэтому некоторые механизмы было сложно использовать в production-сборках. Новый разделяет эти задачи и единообразно управляет кэшем в памяти и на диске. Это упрощает повторное использование результатов в разных сборках и удаление ненужных записей.
В бенчмарках новый кэш сократил использование диска примерно на 79%, а пиковое потребление памяти при холодной сборке примерно на 16%. При этом тёплые сборки заняли немного больше времени.

По умолчанию новый кэш отключён. Включить его можно с помощью experiments.newCache:
// rspack.config.mjs export default { cache: { type: 'persistent', }, experiments: { newCache: true, }, };
Разработчики продолжат оптимизировать производительность в следующих релизах и планируют включить новый кэш по умолчанию в одной из будущих минорных версий.
Кэш лоадеров
Новый кэш позволяет сохранять результаты преобразований отдельных лоадеров. Он работает на более подробном уровне, чем общий постоянный кэш, и для каждого лоадера можно задать свои условия инвалидирования. Изменение конфигурации Rspack может сделать общий кэш недействительным, но результаты лоадера останутся пригодными для повторного использования, если его входные данные, конфигурация и зависимости не изменились. Эти результаты также можно использовать при переключении между режимами разработки и сборки.
Это особенно полезно для ресурсоёмких лоадеров, таких как babel-loader и less-loader: они могут пропустить преобразование неизменённого кода и сократить время сборки. Следующая конфигурация включает новый постоянный кэш и кэширование результатов babel-loader:
// rspack.config.mjs export default { cache: { type: 'persistent', }, experiments: { newCache: true, }, module: { rules: [ { test: /\.[cm]?[jt]sx?$/, use: [ { loader: 'babel-loader', cache: true, }, ], }, ], }, };
В тесте, где babel-loader обрабатывал около 10 000 искусственных модулей, включение кэша лоадера сократило время сборки примерно до 11–12 секунд:
Параллельные лоадеры | Кэш выключен | Кэш включён | Ускорение |
|---|---|---|---|
Выключены | 63.8 с | 11.2 с | 5.7 раза |
Включены | 28.5 с | 11.9 с | 2.4 раза |
Новые возможности
Фильтрация лоадеров по содержимому кода
Новый параметр module.rules[].use.codeFilter позволяет пропускать ненужные преобразования лоадером в зависимости от содержимого кода. Например, можно преобразовывать только файлы с вызовом customMacro():
// rspack.config.mjs export default { module: { rules: [ { test: /\.[cm]?[jt]sx?$/, use: [ { loader: './custom-macro-loader.js', codeFilter: /\bcustomMacro\s*\(/, }, ], }, ], }, };
Ядро Rspack написано на Rust, поэтому вызов JavaScript-лоадера создаёт накладные расходы на взаимодействие между языками даже тогда, когда преобразование не требуется. codeFilter сначала проверяет код на стороне Rust и вызывает лоадер только при необходимости.
В бенчмарке с 10 000 модулей, из которых преобразования требовали только 10%, codeFilter сократил число вызовов лоадера на 90%, а общее время сборки с 622 до 481 мс, примерно на 23%.
Встроенная поддержка CSS
В этом релизе улучшены области видимости CSS Modules, композиция, ссылки на значения и поддержка вложенных селекторов.
Точки входа только с CSS
При публикации отдельной темы или библиотеки стилей может потребоваться только CSS. Теперь Rspack умеет собирать точку входа только с CSS в отдельный CSS-файл, не создавая дополнительный JavaScript-файл:
// rspack.config.mjs export default { entry: { styles: './src/styles.css', }, module: { rules: [{ test: /\.css$/i, type: 'css/auto' }], }, output: { cssFilename: '[name].css', }, };
Эта конфигурация создаёт один файл: styles.css.
Внешние CSS-ресурсы
Когда CSS или изображения размещены на CDN или другом внешнем сервисе, браузер может загружать их напрямую. Новые типы внешних ресурсов css-import и asset-url позволяют исключить из сборки ресурсы, на которые ссылается CSS. Например:
// rspack.config.mjs export default { externals: { 'normalize.css': 'css-import normalize.css', 'https://example.com/a.css': 'css-import https://example.com/a.css', 'https://example.com/a.png': 'asset-url https://example.com/a.png', }, };
Ссылки на эти ресурсы в CSS:
/* styles.css */ @import 'normalize.css'; @import url('https://example.com/a.css'); .logo { background-image: url('https://example.com/a.png'); }
Rspack сохранит ссылки @import и url() в выходном файле, не добавляя сами ресурсы в бандл. CSS-конструкции @import, url() и image-set() также поддерживают комментарии rspackIgnore, позволяющие исключить отдельные ресурсы из сборки:
/* styles.css */ @import /* rspackIgnore: true */ url('./runtime-theme.css');
Другие улучшения
Компиляция по требованию: сокращено число лишних сборок, запускаемых при сохранении кода, и время ожидания обновлений.
Встроенный наблюдатель предоставляет более полные сведения о временных метках файлов, улучшая совместимость с такими библиотеками, как
ts-loaderиvue-loader.Встроенный наблюдатель поддерживает функции в
watchOptions.ignoredи лучше обнаруживает новые каталоги, удалённые и заново созданные файлы.Улучшена совместимость с хуками плагинов webpack и уточнены типы TypeScript для лоадеров, внешних ресурсов и статистики.
Для WebAssembly добавлен параметр
output.wasmStreamingFallback, позволяющий отключить переход к непотоковой загрузке.
Экосистема
Вместе с Rspack 2.3 обновились инструменты экосистемы Rstack: Rsbuild, Rslib, Rsdoctor, Rstest и Rspress.
Rsbuild
Поддержка Rsbuild в TanStack CLI
TanStack CLI официально поддерживает создание проектов TanStack Start с Rsbuild. Для выбора Rsbuild используется флаг --build-tool rsbuild. Например, команда для создания проекта React:
npx @tanstack/cli@latest create my-app --framework React --build-tool rsbuild
В create-rsbuild также добавлен вариант TanStack Start, который автоматически вызывает TanStack CLI для создания проекта. Чтобы использовать шаблон напрямую:
npx -y create-rsbuild@latest my-app -t tanstack-start-react
Плагин Lynx для Rsbuild
В Lynx представили @lynx-js/rsbuild-plugin, перенеся специфичные для Lynx настройки, значения по умолчанию и интеграцию сборки из Rspeedy в pluginLynx. Теперь приложения Lynx можно собирать непосредственно с помощью Rsbuild и этого плагина, без обёртки Rspeedy.
Можно использовать привычные rsbuild.config.ts и CLI Rsbuild, следовать документации Rsbuild и продолжать пользоваться существующими плагинами сборки Rsbuild и Lynx.
В create-rsbuild также появился вариант Lynx, автоматически вызывающий @lynx-js/create-lynx для создания проекта. Например, для проекта ReactLynx с TypeScript:
npx -y create-rsbuild@latest my-app -t lynx-ts
Отчёты о размере файлов
Rsbuild теперь показывает размеры файлов после сжатия Brotli. Для более точной оценки объёма передачи можно задать уровень сжатия gzip или Brotli в соответствии с настройками развёртывания. Чтобы вывести размеры после Brotli, добавьте:
// rsbuild.config.ts export default { performance: { printFileSize: { compressed: { type: 'brotli' }, }, }, };
Другие улучшения Rsbuild
Production-сборки по умолчанию используют
compact-hashedID: короткие стабильные идентификаторы модулей и чанков уменьшают размер результата.В приложениях с клиентским и серверным кодом изменения фронтенда могут быстрее появляться в браузере.
server.publicDirможно настроить для каждого окружения, указав отдельный каталог публичных ресурсов.Для Web Workers при
output.target: 'web-worker'можно установитьoutput.module: true, чтобы получить выходной код в формате ES-модулей.server.allowedHostsограничивает имена хостов, по которым доступны сервер разработки и сервер предпросмотра.Новый хук
onClosePreviewServerпозволяет плагинам освобождать ресурсы при закрытии сервера предпросмотра.В
api.transformможно использоватьcodeFilter, чтобы пропускать ненужные преобразования в зависимости от содержимого кода.
Rslib
Выпуск Rslib 1.0
Вышел Rslib 1.0. Подробности доступны в статье о релизе.
Встраивание Wasm-модулей
Rslib поддерживает встраивание бинарных файлов Wasm в выходной JavaScript с помощью ?inline, поэтому отдельные файлы .wasm распространять и загружать не требуется:
import { add } from './add.wasm?inline'; console.log(add(1, 2));
Другие примеры есть в руководстве по Wasm.
Поддержка TypeScript 7.1
Rslib 1.0.4 умеет генерировать объявления типов с TypeScript 7.1 Beta, в том числе поддерживает новый механизм Content Mappers для обработки дополнительных типов файлов.
Чтобы использовать mapper, установите его и зарегистрируйте обрабатываемые расширения в tsconfig.json. Пример конфигурации mapper для CSS Modules, где example-css-modules-mapper используется как условное имя пакета:
{ "contentMappers": [ { "package": "example-css-modules-mapper", "extensions": [".module.css"] } ] }
При генерации объявлений типов Rslib автоматически загрузит mapper и создаст типы для имён классов CSS Modules. Установите TypeScript 7.1 Beta, чтобы попробовать:
npm add typescript@7.1.0-beta -D
yarn add typescript@7.1.0-beta -D
pnpm add typescript@7.1.0-beta -D
bun add typescript@7.1.0-beta -D
deno add npm:typescript@7.1.0-beta -D
Rsdoctor
Вышел Rsdoctor 2.0. Для анализа с помощью ИИ теперь рекомендуется Agent CLI: он предоставляет прямой доступ к данным сборки и структурированный вывод.
В релизе улучшен анализ Rspack и добавлена поддержка отчётов для нескольких компиляторов. Размер установки сократился на 56%, время анализа на 57%, а время HMR в режиме разработки примерно на 47%.
Rstest
Улучшения API браузерного режима
Обновления браузерного режима упрощают тестирование взаимодействий с клавиатурой и гидратации React в настоящем браузере:
locator.pressSequentially()вводит текст по одному символу, вызывая события клавиатуры для каждого. Это полезно для полей автодополнения и других элементов, реагирующих на отдельные нажатия.render()в@rstest/browser-reactтеперь принимаетhydrateиcreateRootOptions. С их помощью можно гидратировать существующую разметку, созданную на сервере, в заданном контейнере и настроить корень React при тестировании гидратации.
await page.getByLabel('Search').pressSequentially('rspack', { delay: 50 }); await expect.element(page.getByRole('listbox')).toBeVisible();
Тестирование скриншотами
Rstest 0.12.4 добавляет визуальное регрессионное тестирование в браузерный режим при использовании провайдера Playwright. Новый матчер toMatchScreenshot() сравнивает элемент или страницу с сохранённым скриншотом и помогает обнаружить визуальные изменения, которые не видны при проверке DOM.
// button.test.ts import { page } from '@rstest/browser'; import { expect, test } from '@rstest/core'; test('button appearance', async () => { document.body.innerHTML = '<button>Submit</button>'; await expect( page.getByRole('button', { name: 'Submit' }), ).toMatchScreenshot(); await expect(page).toMatchScreenshot('full-page', { fullPage: true }); });
Если сравнение не проходит, Rstest сохраняет фактический скриншот и изображение различий. Можно маскировать динамическое содержимое, настраивать допустимые различия пикселей и обновлять эталонные изображения с помощью --update.
Rspress
Rspress 2.1.0 по умолчанию поддерживает WebMCP. Встроенные инструменты для получения сведений о сайте, поиска по документации и навигации позволяют агентам в браузере напрямую взаимодействовать с сайтами документации.
Чтобы попробовать, выполните следующий код в браузере с поддержкой WebMCP:
const tools = await document.modelContext.getTools(); const tool = tools.find(({ name }) => name === 'rspress_get_current_page'); const page = JSON.parse(await document.modelContext.executeTool(tool, {})); console.log(page.markdown);
Также можно регистрировать собственные инструменты с помощью хука useWebMcp, расширяя возможности агентов на сайте. Подробности есть в документации WebMCP.

