0%

1. Введение


Create React App (далее - CRA) был хорошим другом. В 2018 году.


Он убрал боль с конфигурацией Webpack (т.к. было два варианта - npx create-react-app my-app или настраивать Webpack самому), дал тебе надежную сборку (которая запускалась одной командой - npm start) и ты просто работал. Но в 2025 году этот друг стал тем, кто приходит в гости на час, а остаётся на три дня. Медленный старт. Медленный Hot Module Replacement (HMR). Устаревшие инструменты сборки (Webpack 5 + Babel). И ощущение, что ты тащишь телегу сам вместо того чтобы ехать.


Мы мигрировали шестилетний боевой React веб проект на Vite. Не ради чего-то такого - ради того, чтобы перестать смотреть на спиннер на localhost, каждый раз когда нажимаешь Cmd/Ctrl+S.

Вот что нас ждало по дороге - и что мы получили в конце.


2. Почему вообще уходить с CRA?


Для понимания масштаба:


Примечание: Лягушка в закипающей воде. С каждой фичей сборка медленнее, но на доли секунды.


Это не катастрофа. Это просто медленно. И когда делаешь это 200 раз в день - считай часы жизни, которые уходят в никуда.


CRA больше не получает активной поддержки. Под капотом куча решений (Webpack 5, Babel), которые никто не торопится обновлять. Экосистема React давно двигается в сторону Vite, и игнорировать это становится всё сложнее.

Решение принято - мигрировать. Звучит просто. Оказалось - нет.


3. Проблемы, которые нас встретили


3.1 Переменные окружения: REACT_APP_* → VITE_*


Первое, что сломалось это .env файлы. Полностью.

CRA читает только переменные с префиксом REACT_APP_ и отдаёт их через process.env. Vite работает иначе: ему нужен префикс VITE_, а доступ - через import.meta.env.



Если у тебя десятки переменных разбросаны по проекту - готовьтесь к поиску и замене. Плюс все .env, .env.production, .env.staging нужно переименовывать. Автоматизируется скриптом, но сначала нужно это понять:


3.2 Проблемы с импортами SCSS


Vite не понимает CRA-специфичные пути вида @import './src/_mixins'. Он не знает, как сопоставлять такой путь - и просто вылетает с ошибкой.

Решение: настроить additionalData или includePaths в vite.config.js:


Либо заменить все проблемные импорты на относительные пути. Второй вариант чище, первый - быстрее, если импортов много.


3.3 Устаревший синтаксис SASS: @import и if()


SASS давно объявил @import устаревшим в пользу @use и @forward (https://sass-lang.com/documentation/breaking-changes/import/). В CRA это ещё прощалось - предупреждения были при сборке, но всё работало. В Vite с обновленным SASS они начинают мешать сборке.

Та же история с функцией if() - синтаксис изменился, и старые конструкции вызывают предупреждения об устаревшем.


Можно скрыть ошибки через silenceDeprecations в конфигурации - быстрая правка. Но лучше пройтись и мигрировать: SASS предоставляет sass-migrator (https://www.npmjs.com/package/sass-migrator) для автоматической замены @import на @use.


3.4 react-pdf и pdfjs-dist: специфичные внутренности Webpack


Это была самая неприятная проблема. react-pdf внутри использует entry.webpack - путь, который существует только в webpack-окружении. В Vite он просто не сопоставляется.



Web worker нужно либо копировать в public/ и указывать путь явно, либо использовать import.meta.url для динамической ссылки. Документация react-pdf для Vite есть, но найти её с первого раза это отдельный квест (https://docs.react-pdf-kit.dev/introduction/basic-usage/#vite).


3.5 Ошибки импорта SVG


В CRA SVG можно было импортировать двумя способами одновременно:


В Vite по умолчанию любой .svg - это просто URL. Для компонентного импорта нужен vite-plugin-svgr (https://www.npmjs.com/package/vite-plugin-svgr). Но есть нюанс - даже с этим плагином нужно правильно настроить, чтобы оба формата работали:



3.6 Стилизованные компоненты


Если в проекте использовались styled-components/macro - они не работают в Vite напрямую, так как макросы это Webpack/babel-macro механизм.



В большинстве случаев простая замена импорта решает проблему. Если использовался css helper из macro - тоже самое. Для более сложных случаев есть babel-plugin-styled-components (https://www.npmjs.com/package/babel-plugin-styled-components) через @vitejs/plugin-react с опцией babel.


7. Псевдонимы путей: @/components


Пути типа @/components/Button не работают из коробки ни в Vite, ни в ESLint, ни в VSCode. Нужно настроить три места синхронно:



Три файла. Один псевдоним. Если забудешь хотя бы один - будет работать, но с красными подчёркиваниями или ошибками ESLint.


8. require() → import()


Vite работает на стандартных ES-модулях. Динамические require() это не его язык.



Статические require() решаются простой заменой на import. Динамические - на import() с await. Сложнее всего, когда require() встречается в устаревших утилитах или сторонних пакетах, тогда там нужно или латать, или искать альтернативу.


3.9 Замена Jest на Vitest


Jest и Vite плохо уживаются вместе. Jest работает на CommonJS, а Vite на ES-модулях. Настроить Jest для работы с Vite проектом можно, но это боль с трансформерами и конфигурациями.


Vitest (https://vitest.dev/) - родное решение для Vite. Стиль взаимодействия практически идентичен Jest, миграция в большинстве случаев сводится к следующему:


А также замена импортов в тестах:



Большинство тестов просто заработают. Исключение - тесты с использованием снимков и специфичные для Jest функции сравнения: их нужно проверить отдельно.


4. Что мы получили в итоге


После того как всё заработало, пора посмотреть на цифры и они говорят сами за себя.


4.1 Холодный старт:


CRA: ~35 секунд

Vite: ~1.5 секунды

HMR (обновление после Cmd/Ctrl+S):

CRA: 3-8 секунд

Vite: ~100-300ms - браузер обновляется быстрее, чем ты успеваешь отпить кофе


4.2 Размер сборки: примерно тот же, но Vite лучше очищает дерево зависимостей по умолчанию.


4.3 Опыт разработки:

  1. Ошибки показываются прямо в браузере с понятной историей вызовов;
  2. HMR точечный - меняется только тот модуль, который ты изменил, а не весь граф зависимостей;
  3. Конфигурация читаемая и компактная - vite.config.ts на 40 строк против webpack.config.js на 300;
  4. Можно использовать TypeScript из коробки, без дополнительных плагинов;

import.meta - стандарт, который работает везде, не только в Webpack;


4.4 Экосистема:

Vite сегодня это стандарт для новых React-проектов. Remix, SvelteKit, SolidStart, Astro - все используют Vite, а значит: много документации, больше плагинов, ошибки исправляются быстрее.


5. Стоит ли оно того?


Да! Но если честно - миграция не за пару выходных.


Если проект небольшой и без тяжелых зависимостей, то скорее всего управитесь за день-два. Если есть PDF, SVG-компоненты, макросы, сложные SCSS-структуры и куча написанных тестов, то закладывайте неделю и тестируйте тщательно.


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


Каждая из этих проблем решаемая. Некоторые - за 5 минут, некоторые - за полдня. Но когда всё работает, и ты нажимаешь “Сохранить” и видишь изменение в браузере через 200 миллисекунд, то понимаешь, что оно стоило каждой потраченной минуты.


CRA дал нам хороший старт. Vite даёт нам скорость для работы сегодня!

разработка
webpack
vite
jest
vitest
babel
react
cra
миграция
аутсорсинг
аутстаффинг

Vadim Sinichenko

-

Похожие статьи

ВСЕ СТАТЬИ

Не умею готовить, но Superset сделал из меня шеф-повара данных

Не умею готовить, но Superset сделал из меня шеф-повара данных

1 Каждый понедельник - одно и то же (или с чем столкнулся наш фуллстек) Приходишь на работу, а сообщений уже лавина: “Можешь выгрузить данные за прош

разработка
4 мин. читать
19 марта 2026 г.

Такой разный Agile

Такой разный Agile

Случай из финтеха когда вы строили автомобиль, а бизнес просто хотел громче сигналить в бибикалку (или история одного рабства от нашего ведущего фронт

разработка
2 мин. читать
24 февраля 2026 г.