Почему Vite
Проблемы
Прежде чем модули ES стали доступны в браузерах, у разработчиков не было встроенного механизма для написания JavaScript в модульном формате. Именно поэтому мы все знакомы с концепцией «упаковки»: использованием инструментов, которые сканируют, обрабатывают и объединяют наши исходные модули в файлы, которые могут выполняться в браузере.
Со временем появились такие инструменты, как webpack, Rollup и Parcel, которые значительно улучшили опыт разработки для фронтенд-разработчиков.
Однако по мере создания всё более амбициозных приложений объём JavaScript, с которым мы работаем, также резко увеличивается. Не редкость, когда крупные проекты содержат тысячи модулей. Мы начинаем сталкиваться с узким местом в производительности инструментов на основе JavaScript: запуск dev-сервера может занимать неоправданно долгое время (иногда до нескольких минут!), а даже с использованием горячей замены модулей (HMR) изменения в файлах могут отражаться в браузере с задержкой в несколько секунд. Медленный цикл обратной связи может значительно повлиять на продуктивность и удовлетворенность разработчиков.
Vite стремится решить эти проблемы, используя новые достижения в экосистеме: доступность встроенных ES-модулей в браузере и рост инструментов JavaScript, написанных на языках, компилируемых в нативный код.
Медленный запуск сервера
При холодном старте dev-сервера настройка сборки на основе сборщика должна заранее просканировать и собрать всё ваше приложение, прежде чем его можно будет обслуживать.
Vite улучшает время запуска dev-сервера, сначала разделяя модули в приложении на две категории: зависимости и исходный код.
Зависимости в основном представляют собой обычный JavaScript, который не часто изменяется в процессе разработки. Некоторые крупные зависимости (например, библиотеки компонентов с сотнями модулей) также довольно дорого обрабатываются. Зависимости могут также поставляться в различных форматах модулей (например, ESM или CommonJS).
Vite предварительно объединяет зависимости с помощью esbuild. esbuild написан на Go и предварительно упаковывает зависимости в 10-100 раз быстрее, чем сборщики на основе JavaScript.
Исходный код часто содержит не простой JavaScript, который требует трансформации (например, JSX, CSS или компоненты Vue/Svelte) и будет редактироваться очень часто. Кроме того, не весь исходный код нужно загружать одновременно (например, с использованием разделения кода на основе маршрутов).
Vite обслуживает исходный код через встроенные ESM. Это по сути позволяет браузеру взять на себя часть работы сборщика: Vite нужно только трансформировать и обслуживать исходный код по мере необходимости, когда браузер его запрашивает. Код, связанный с условными динамическими импортами, обрабатывается только в случае его фактического использования на текущем экране.
Медленные обновления
Когда файл редактируется в настройке сборки на основе сборщика, неэффективно пересобирать весь пакет по очевидной причине: скорость обновления будет ухудшаться линейно с увеличением размера приложения.
В некоторых сборщиках dev-сервер выполняет объединение в памяти, так что ему нужно только аннулировать часть графовой структуры своего модуля, когда файл изменяется, но ему всё равно нужно заново собрать весь пакет и перезагрузить веб-страницу. Восстановление пакета может быть затратным, а перезагрузка страницы приводит к потере текущего состояния приложения. Именно поэтому некоторые сборщики поддерживают горячую замену модулей (HMR): позволяя модулю «горячо заменять» себя без влияния на остальную часть страницы. Это значительно улучшает опыт разработки (DX) — однако на практике мы обнаружили, что даже скорость обновления HMR значительно ухудшается по мере роста размера приложения.
В Vite HMR выполняется через встроенные ESM. Когда файл редактируется, Vite нужно только точно аннулировать цепочку между редактируемым модулем и его ближайшей границей HMR (в большинстве случаев только сам модуль), что делает обновления HMR всегда быстрыми, независимо от размера вашего приложения.
Vite также использует HTTP-заголовки для ускорения полной перезагрузки страницы (снова позволяя браузеру выполнять больше работы за нас): запросы модулей исходного кода выполняются условно через 304 Not Modified
, а запросы модулей зависимостей кэшируются с помощью Cache-Control: max-age=31536000,immutable
, чтобы они не обращались к серверу снова после кэширования.
Как только вы испытаете, насколько быстро работает Vite, мы сильно сомневаемся, что вы захотите снова мириться с разработкой на основе пакетов.
Зачем нужна продакшен-сборка
Хотя встроенные ESM теперь широко поддерживаются, доставка неупакованных ESM в продакшен-среде всё ещё неэффективна (даже с HTTP/2) из-за дополнительных сетевых запросов, вызванных вложенными импортами. Для достижения оптимальной производительности загрузки в продакшен-среде всё ещё лучше упаковывать ваш код с использованием tree-shaking («встряхивания дерева»), ленивой загрузки и разделения общих чанков (для лучшего кэширования).
Обеспечить оптимальный вывод и согласованность поведения между dev-сервером и продакшен-сборкой не так просто. Именно поэтому Vite поставляется с предварительно настроенной командой сборки, которая включает в себя множество оптимизаций производительности из коробки.
Почему бы не сделать сборку с esbuild?
Текущий Plugin API Vite несовместим с использованием esbuild
в качестве сборщика. Несмотря на то, что esbuild
быстрее, принятие Vite гибкого Plugin API и инфраструктуры Rollup значительно способствовало его успеху в экосистеме. На данный момент мы считаем, что Rollup предлагает лучшее соотношение производительности и гибкости.
Rollup также работает над улучшением производительности, переключая свой парсер на SWC в версии 4. Ведется работа над созданием порта Rollup на Rust, который называется Rolldown. Как только Rolldown будет готов, он может заменить как Rollup, так и esbuild в Vite, значительно улучшив производительность сборки и устранив несоответствия между разработкой и сборкой. Вы можете посмотреть выступление Эвана Ю на ViteConf 2023 для получения дополнительных деталей.
Чем Vite отличается от X?
Более подробную информацию о том, чем Vite отличается от других подобных инструментов, вы можете найти в главе Сравнения.