От Parcel к Vite: Краткая история миграции 100K LOC
Мы перенесли наши три фронтенд проекта с Parcel на Vite, и процесс прошел... гладко.
Мы перенесли наши три фронтенд проекта с Parcel на Vite, и процесс прошел... гладко.
У нас есть три основных фронтенд проекта в Logto: интерфейс входа, Консоль и предварительный просмотр в реальном времени. Все эти проекты написаны на TypeScript, React и SASS модулях; в сумме они содержат около 100K строк кода.
Нам нравился Parcel за его простоту и настройку без необходимости конфигурации. Я до сих пор помню день, когда был шокирован, насколько легко было создать новый проект с Parcel. Вы можете просто запустить parcel index.html и вуаля, все необходимые зависимости установлены и проект работает. Если ты "опытный" разработчик, возможно, ты чувствуешь то же самое, сравнивая это с прежними днями когда нужно было настраивать Gulp и Webpack. Parcel — это настоящая волшебная палочка.
Простота Parcel была основной причиной, по которой мы оставались с ним так долго, несмотря на то, что иногда он был капризным. Например:
Так почему же мы решили перейти на что-то другое?
Кто-то даже открыл обсуждение, чтобы спросить мертв ли Parcel. Официальный ответ - нет, Parcel все еще жив, но он находится в состоянии «мы работаем над крупным рефакторингом и у нас нет времени на минорные версии». Для нас это выглядит как «смерть утки»: последнюю версию, которую мы можем использовать, выпустили больше года назад, и мы не знаем, когда выйдет следующая версия. Кажется, что Parcel мертв, он ведет себя как мертвец, так что для нас он мертв.

Мы узнали о Vite от Vitest. Несколько месяцев назад мы устали от поддержки ESM в Jest (в тестировании) и решили попробовать что-то новое. Vitest покорил наши сердца благодаря поддержке ESM на уровне ядра и совместимости с Jest. У него потрясающий опыт для разработчиков, и его поддерживает Vite.
Возможно, у вас в проекте можно настроить по-разному, но обычно вы найдете плагиновые замены, так как экосистема Vite развивается. Вот наши настройки на момент миграции:
Мы начали процесс миграции, создав новый проект на Vite, и поиграли с ним, чтобы понять, как он работает. Процесс прошел гладко, и реальная миграция заняла всего несколько дней.
Vite поддерживает монорепозитории, ESM, TypeScript, React и SASS из коробки. Нам нужно было только установить необходимые плагины и конфигурации, чтобы все заработало.
Vite имеет встроенную поддержку псевдонимов путей, например, в нашем tsconfig.json:
Нам нужно было только добавить такое же разрешение в наш vite.config.ts:
Обратите внимание, что путь для замены должен быть абсолютным, хотя он относительно корня проекта. Альтернативно, вы можете использовать плагин vite-tsconfig-paths, чтобы считывать псевдонимы путей из tsconfig.json.
Хотя Vite поддерживает HMR из коробки, для включения React Fast Refresh необходимо установить плагин. Мы использовали плагин @vitejs/plugin-react, который предоставлен командой Vite и отлично поддерживает такие возможности React, как Fast Refresh:
Мы используем плагин vite-plugin-svgr, чтобы конвертировать SVG в компоненты React. Все, что нужно - добавить плагин в конфигурацию Vite:
Однако мы не указали, при каких условиях SVG должен быть преобразован в компоненты React, так что все импорты были конвертированы. Плагин предлагает лучшую конфигурацию по умолчанию: конвертировать только те SVG, которые импортированы с расширением .svg?react. Мы обновили наши импорты соответственно.
Хотя Vite поддерживает SASS модули на уровне ядра, есть одно, на что нам нужно обратить внимание: как форматируются имена классов. Это может вызвать проблемы у пользователей и наши интеграционные тесты, если имена классов будут отформатированы непоследовательно. Одна строка конфигурации в vite.config.ts может решить эту проблему:
Кстати, Parcel и Vite имеют разные способы импорта SASS файлов:
Синтаксис * as, однако, работает в Vite, но он приведет к потере модульных имен классов, когда вы используете динамические ключи для доступа к объекту styles. Например:
Поскольку Vite использует Rollup под капотом, мы можем использовать официальный плагин @mdx-js/rollup, чтобы поддерживать MDX, а также его плагины. Конфигурация выглядит так:
Плагин remarkGfm используется для поддержки GitHub Flavored Markdown, а плагин rehypeMdxCodeProps - для передачи пропсов к блокам кода в файлах MDX, как это делает Docusaurus.
Мы хотим использовать диаграммы Mermaid в наших файлах MDX так же, как и другие языки программирования. Использование должно быть таким же простым, как и другие блоки кода:
Должно рендериться как:
Поскольку наше приложение поддерживает светлую и темную темы, мы немного закодировали, чтобы заставить диаграммы Mermaid работать с темной темой. Была создана компонента React:
useTheme - это настраиваемый хук для получения текущей темы из контекста. Библиотека mermaid импортируется асинхронно, чтобы уменьшить размер загрузки на начальной странице.
Для блока кода в файле MDX у нас есть единый компонент, который выполняет работу:
Наконец, мы определяем MDX провайдер следующим образом:
Это не что-то специфичное для Vite, но все же стоит упомянуть, так как мы обновили наши страницы для использования ленивой загрузки во время миграции, и после этого ничего не сломалось.
React имеет встроенную функцию React.lazy для ленивой загрузки компонентов. Однако это может вызвать некоторые проблемы, когда вы быстро итератируете. Мы разработали небольшую библиотеку под названием react-safe-lazy, чтобы решить эти проблемы. Она является заменой для React.lazy, и подробное объяснение можно найти в этом посте в блоге.
Существует аккуратный плагин под названием vite-plugin-compression, чтобы создавать сжатые файлы. Он поддерживает как gzip, так и brotli сжатие. Конфигурация проста:
Одна из отличных функций Vite (или Rollup, который лежит в его основе) - это ручные чанки. Пока React.lazy используется для ленивой загрузки компонентов, мы можем иметь больше контроля над чанками, определяя ручные чанки, чтобы решить, какие компоненты или модули следует объединить вместе.
Например, мы можем сначала использовать vite-bundle-visualizer, чтобы проанализировать размер бандла и зависимости. Затем мы можем написать правильную функцию для разделения чанков:
В отличие от продакшн-сборки, Vite НЕ будет объединять ваш исходный код в режиме разработки (включая связанные зависимости в той же монорепозиторие) и будет обрабатывать каждый модуль как файл. При этом, браузер загрузит сотни модулей впервые, что может выглядеть странно, но в большинстве случаев это совершенно нормально. Вы можете ознакомиться с обсуждением здесь.
Если для вас это проблема, альтернативное, но не идеальное решение - указать связанные зависимости в опции optimizeDeps файла vite.config.ts:
Это "предварительно объединит" связанные зависимости и ускорит работу dev сервера. Недостатком является то, что HMR может не работать так, как ожидалось, для связанных зависимостей.
Кроме того, мы используем прокси, который обслуживает статические файлы в продакшене и проксирует запросы на сервер Vitest в режиме разработки. У нас есть несколько настроенных портов для избежания конфликтов, и это также легко настроить в файле vite.config.ts:
В отличие от Parcel, Vite использует современный подход к обработке переменных среды с использованием import.meta.env. Он автоматически подгружает .env файлы и заменяет переменные в коде. Однако, это требует, чтобы все переменные среды были префиксированы VITE_ (можно настроить).
Когда мы использовали Parcel, он просто заменял переменные process.env, не проверяя префикс. Поэтому мы придумали обходной путь, используя поле define, чтобы облегчить миграцию:
Это позволяет нам постепенно добавлять префикс к переменным среды и удалять поле define.
Вот и все! Мы успешно перенесли наши три фронтенд проекта с Parcel на Vite и надеемся, что эта короткая история поможет вам с вашей миграцией. Вот как конфигурация выглядит в конце: