Правила миграции
Этот справочный раздел подробно описывает, что именно делает команда vp migrate с проектом: как она обновляет зависимости, переписывает импорты в исходном коде и сценарии пакетов, а также изменяет конфигурацию менеджера пакетов. Общее описание команды и процесса миграции см. в руководстве по миграции.
За исключением раздела Перед миграцией, в котором перечислены действия, выполняемые вручную, всё, что описано ниже, происходит автоматически.
Перед миграцией
- Выполните
vp upgrade, чтобы глобальная CLI получила последние правила миграции. Устаревшая локальная версияvite-plusне является препятствием: если локальная копия проекта старее, миграция будет выполняться глобальной CLI. - При необходимости обновите проект до Vite 8+ и Vitest 4.1+.
- Выполните
vp migrateиз корня рабочего пространства. В автоматизированных средах используйте флаг--no-interactive. - Проверьте все изменённые манифесты, конфигурацию менеджера пакетов, изменения исходного кода и сгенерированный lock-файл.
- Выполните проверку с помощью
vp install,vp check,vp testиvp build.
Миграция является идемпотентной: повторный запуск после успешной миграции не должен приводить к появлению новых изменений.
Обновление или полная настройка
Если проект уже использует vite-plus, команда vp migrate выполняет только обновление: обновляет зависимости и конфигурацию менеджера пакетов, а также завершает обновление импортов. При этом первоначальная настройка проекта не затрагивается.
- Флаг
--fullдополнительно выполняет действия по настройке: устанавливает git-хуки, настраивает редактор, создаёт файлы для ИИ-агентов, переносит конфигурации ESLint и Prettier, добавляет совместимость с фреймворками, исправляет параметрbaseUrlвtsconfigи преобразует.nvmrc/Volta в.node-version. - Флаги
--hooks,--agentи--editorпозволяют выполнить только одно из этих действий без использования--full.
Если при обычном обновлении пропускаются действия по настройке, которые можно было бы применить, команда выведет подсказку выполнить vp migrate --full. Для новых проектов (не использующих Vite+) всегда выполняется полная миграция.
Правила обработки зависимостей
Что происходит с каждой зависимостью из набора инструментов:
| Зависимость | Что происходит |
|---|---|
vite-plus | Добавляется в пакет, для которого выполняется миграция; обычные диапазоны версий заменяются на конкретную целевую версию — напрямую или через каталог. |
vite | Существующие объявления сохраняются и перенаправляются на алиас ядра. При использовании pnpm добавляется как прямая зависимость devDependencies там, где это необходимо (см. Vite и overrides). |
vitest | В типичном случае для Node.js удаляется, поскольку vite-plus предоставляет его как транзитивную зависимость. Сохраняется или добавляется только в случаях, когда требуется прямая зависимость. |
@vitest/* | Напрямую устанавливаемые пакеты экосистемы синхронизируются с версией Vitest, поставляемой вместе с Vite+ (см. Пакеты экосистемы Vitest). |
@voidzero-dev/vite-plus-test | Полностью удаляется: из зависимостей, overrides, resolutions и алиасов каталогов. Импорты переписываются на актуальный API vite-plus/test*. |
Выбор версии
vite-plusзакрепляется за конкретной версией CLI, выполняющей миграцию, а не за dist-taglatest.- Алиас
viteуказывает на@voidzero-dev/vite-plus-coreиз того же релиза Vite+. - Если в манифесте используются каталоги (
catalog:или именованные ссылки на каталог), миграция сохраняет ссылку и обновляет значение соответствующей записи каталога до конкретной целевой версии набора инструментов. - Намеренно закреплённые протоколы сохраняются:
workspace:,file:,link:,npm:,github:, Git URL и HTTP URL. - Миграция синхронизирует все пакеты рабочего пространства, а не только корневой манифест. Общие
overridesи каталоги остаются в корне рабочего пространства, а зависимости, предоставляющие peer-зависимости, размещаются в каждом пакете, которому они необходимы.
Vite и overrides
Правила overrides менеджера пакетов сами по себе не создают граф зависимостей. В pnpm пакет, который содержит vite-plus в dependencies или devDependencies, но нигде не объявляет vite (в dependencies, devDependencies, optionalDependencies или peerDependencies), позволяет pnpm автоматически установить исходный Vite для удовлетворения обязательной peer-зависимости vite, требуемой Vitest. В результате проект оказывается разделён между отдельными экземплярами Vite+, Vite и Vitest. Чтобы этого избежать, vp migrate добавляет отсутствующую запись vite в devDependencies каждого такого пакета, после чего правило override на уровне рабочего пространства перенаправляет её на ядро Vite+.
Связанные правила:
- Прямое объявление
viteникогда не удаляется только потому, что в корне рабочего пространства существуетoverride. - Обычные или устаревшие алиасы нормализуются; именованные ссылки на каталог сохраняются.
- Описанное выше правило добавления прямой зависимости относится только к pnpm. Bun аналогичным образом дублирует алиас ядра как прямую зависимость для своего механизма разрешения peer-зависимостей, а при использовании npm некоторые схемы
browser-providerмогут требовать зависимостьviteверхнего уровня, чтобы вложенные пакеты Vitest могли корректно разрешитьvite.
Когда требуется прямая зависимость от Vitest
Во время миграции локальная зависимость vitest сохраняется или добавляется с точной версией, поставляемой вместе с Vite+, если выполняется хотя бы одно из следующих условий:
- установленная зависимость имеет обязательную peer-зависимость от
vitest(как с точной версией, так и с диапазоном версий); - пакет использует браузерный режим Vitest или один из дополнительных браузерных провайдеров;
- исходный код или конфигурация TypeScript сохраняют ссылки на исходный
vitest; - пакет объявляет зависимость
@nuxt/test-utils; или - метаданные зависимостей недоступны, и существующая прямая зависимость
vitestможет удовлетворять неизвестную обязательную peer-зависимость.
Для определения используется информация о peer-зависимостях установленных пакетов, поэтому интеграции вроде vite-plugin-gherkin также обрабатываются корректно, даже если их имя не содержит vitest.
Если пакет подпадает под эти условия, миграция:
- добавляет
vitestтолько в этот пакет, а не во все пакеты рабочего пространства; - использует существующую ссылку на каталог, если она поддерживается, либо точную поставляемую версию в противном случае;
- сохраняет соответствующее правило
overrideилиresolutionна уровне рабочего пространства, чтобы всё дерево зависимостей использовало единственную версию Vitest.
Само по себе объявление peer-зависимости не устанавливает Vitest. Если сохранившаяся запись peerDependencies.vitest использует запись каталога, которая будет удалена в ходе миграции, она сначала преобразуется в публичный диапазон версий.
Пакеты экосистемы Vitest
Официальные пакеты @vitest/* обычно выпускаются синхронно с Vitest. Миграция синхронизирует версии тех из них, которые проект устанавливает напрямую, включая @vitest/coverage-v8, @vitest/coverage-istanbul, @vitest/ui и @vitest/web-worker:
- если менеджер пакетов поддерживает каталоги, зависимости будут ссылаться на каталог набора инструментов: существующие ссылки
catalog:илиcatalog:<имя>сохраняются, для пакетов без такой ссылки создаётся запись каталога, а каждая запись обновляется до версии Vitest, поставляемой вместе с Vite+; - если каталоги не поддерживаются (npm, отдельный проект Bun или версии pnpm/Yarn без поддержки каталогов), записывается конкретная поставляемая версия.
Пакеты, которые не синхронизируются:
@vitest/eslint-pluginиспользует собственную схему версионирования;@vitest/coverage-c8остановился на более раннем релизе и не имеет версии для Vitest 4;- сторонние интеграции
vitest-*сохраняют собственные совместимые версии, хотя их обязательная peer-зависимость от Vitest всё равно может привести к добавлению прямой зависимости.
Для браузерного режима базовые пакеты @vitest/browser и @vitest/browser-preview уже входят в состав Vite+ и удаляются из прямых зависимостей. Провайдеры Playwright и WebdriverIO остаются дополнительными: сохранённый или автоматически добавленный провайдер подключается через предпочтительный каталог набора инструментов с поставляемой версией Vitest (или записывается как конкретная версия, если каталоги не поддерживаются), а вместе с ним устанавливается соответствующая peer-зависимость playwright или webdriverio.
Провайдеры определяются до переписывания импортов. Это обеспечивает корректную обработку устаревших проектов, которые использовали алиас vitest на @voidzero-dev/vite-plus-test и импортировали модули из vitest/browser-<provider>, vitest/browser/providers/<provider> или vitest/plugins/browser-<provider>: такие импорты по-прежнему приводят к установке соответствующей зависимости @vitest/browser-playwright или @vitest/browser-webdriverio вместе с её peer-зависимостью.
Вложенные правила overrides npm и Bun, заданные в виде объектов, сохраняются, поскольку они представляют собой пользовательские области действия, а не обычные закрепления версий.
Правила переписывания исходного кода
Импорты vite
Импорты vite и vite/* переписываются на vite-plus только в файлах конфигурации: vite.config.*, vitest.config.* и любых других конфигурационных файлах, обнаруженных в процессе миграции. Во всех остальных файлах импорты vite остаются без изменений по двум причинам:
vite-plusне является гарантированным надмножеством публичного API Vite. Он предоставляет толькоdefineConfig,defineProjectиlazyPlugins, поэтому переписывание таких символов, какcreateBuilderилиloadConfigFromFile(в том числе в типах видаtypeof import('vite')), может нарушить работу кода.- Импорт
vite, оставленный без изменений, в проекте Vite+ всё равно будет разрешён через алиас@voidzero-dev/vite-plus-core.
Для пакетов плагинов (непространственные имена, начинающиеся с vite-plugin- или unplugin-, а также пакеты, содержащие vite в peerDependencies или dependencies) переписывание не выполняется даже в конфигурационных файлах. Это правило распространяется только на спецификатор vite.
Дополнения модулей через declare module 'vite' подчиняются тем же правилам и сохраняются за пределами файлов конфигурации. Благодаря алиасу ядра они продолжают расширять тот же модуль @voidzero-dev/vite-plus-core, тип UserConfig которого используется функцией defineConfig из vite-plus, поэтому после миграции всё продолжает работать. Сам vite-plus не экспортирует символ UserConfig, поэтому переписанное дополнение declare module 'vite-plus' не с чем было бы объединять. Расширения, предназначенные для собственного API vite-plus, необходимо писать вручную для vite-plus.
Импорты vitest и браузерных модулей
- Обычные импорты
vitestиvitest/*переписываются наvite-plus/test*. - Импорты устаревших провайдеров Playwright и WebdriverIO обнаруживаются до переписывания, чтобы не потерять соответствующие необязательные зависимости.
- Пространственные импорты
@vitest/browser*переписываются на соответствующие экспортыvite-plus/test/browser*, при необходимости автоматически добавляя дополнительные провайдеры. - Уже существующие импорты
vite-plus/test*остаются без изменений.
Что никогда не переписывается
declare module 'vitest'иdeclare module '@vitest/browser*': дополнения модулей должны сохранять идентичность исходного модуля.- Ссылки, которые остаются в проекте, такие как
compilerOptions.types,require.resolve,import.meta.resolveиvitest/package.json, требуют наличия локальной зависимостиvitest(см. раздел Когда требуется прямая зависимость от Vitest). - Если пакет объявляет зависимость
@nuxt/test-utils, все спецификаторы модулейvitestиvitest/*сохраняются без изменений во всём пакете: преобразование Nuxt требует использования исходного имени модуля, иначе может быть добавлен дублирующий импортvi. Это исключение не распространяется на соседние пакеты и не касается пространственных импортов@vitest/browser*.
Правило линтера prefer-vite-plus-imports использует то же исключение для Nuxt, поэтому автоматическое исправление также сохраняет эти импорты.
Правила переписывания сценариев пакетов
Во время миграции команды набора инструментов Vite+ в сценариях package.json переписываются с сохранением всех их аргументов:
| До | После |
|---|---|
vite | vp dev или соответствующая подкоманда vp |
vitest | vp test |
oxlint | vp lint |
oxfmt | vp fmt |
tsdown | vp pack |
lint-staged | vp staged |
eslint | vp lint, если выполняется соответствующая дополнительная миграция |
prettier | vp fmt, если выполняется соответствующая дополнительная миграция |
Для команд, запускаемых через bunx, миграция сохраняет сам bunx и его флаг --bun (оставляя выбранную пользователем среду выполнения), переписывая только управляемую команду. Это также работает, если bunx находится после разделителя запуска команд, например run или --:
| До | После |
|---|---|
bunx --bun vite build | bunx --bun vp build |
bunx --bun vitest run | bunx --bun vp test run |
portless --tailscale run bunx --bun vite | portless --tailscale run bunx --bun vp dev |
dotenv -e .env.test -- bunx --bun oxlint --type-aware | dotenv -e .env.test -- bunx --bun vp lint --type-aware |
Другие команды, запускаемые через bunx, а также иные способы запуска пакетов остаются без изменений.
Правила обработки версии Node.js
Во время миграции устаревшие файлы менеджеров версий Node.js преобразуются в .node-version — формат, который использует Vite+. В уже существующем проекте Vite+ это преобразование входит в состав полной настройки, поэтому выполняется при запуске vp migrate --full. Для новых проектов оно выполняется всегда.
- Файлы
.nvmrcи закреплённая версияvolta.nodeпреобразуются в.node-version. Если файл.node-versionуже существует, он сохраняется. - При удалении
.nvmrcвсе ссылкиnode-version-file: .nvmrcвactions/setup-nodeвнутри.github/workflows/*.{yml,yaml}и составных действий (.github/actions/**/action.{yml,yaml}) автоматически заменяются на.node-version, чтобы предотвратить ошибки CI вида «node version file ... does not exist».
Правила для менеджеров пакетов
pnpm
Расположение корневых настроек. Начиная с pnpm 10.6.2, файл pnpm-workspace.yaml является единственным источником поддерживаемых корневых настроек. Во время миграции распознаваемые поля из package.json#pnpm переносятся туда, включая overrides, правила для peer-зависимостей, настройки патчей, расширения пакетов, параметры архитектуры и политики сборки, конфигурацию аудита и обновлений, а также зависимости конфигурации. Если объект pnpm становится пустым, он удаляется. Неизвестные ключи сохраняются, поскольку они могут использоваться другими инструментами.
- Если одинаковая переносимая настройка определена в обоих файлах, объекты объединяются рекурсивно, а уникальные элементы массивов сохраняются. При конфликте скалярных значений приоритет отдаётся значениям из
package.json#pnpm, а остальные записи, существующие только вpnpm-workspace.yaml, сохраняются. - До версии pnpm 10.6.2 эти настройки остаются в
package.json#pnpm. (Поддержка настроек рабочего пространства появлялась постепенно: начиная с 10.5.0 — в общем случае, с 10.5.1 — дляoverrides, с 10.6.2 — дляpeerDependencyRules. Начиная с pnpm 11 устаревшие настройки вpackage.jsonбольше не читаются.)
Каталоги. Каталоги — это отдельная возможность, поддерживаемая начиная с pnpm 9.5.0 и не зависящая от описанного выше расположения настроек. Даже в версиях ниже 10.6.2, где overrides остаются в package.json#pnpm, миграция всё равно обновляет каталог рабочего пространства, заменяя устаревшие алиасы-обёртки, и сохраняет catalog: в overrides как ссылки, а не подставляет вместо них конкретные версии.
- Ссылки на зависимости, стандартный и именованные каталоги,
overridesиpeerDependencyRulesподдерживаются в согласованном состоянии. - pnpm допускает определение стандартного каталога либо через корневое поле
catalog, либо черезcatalogs.default, но не одновременно. Миграция сохраняет уже используемый вариант и никогда не создаёт второй параллельно. - Если существующий именованный каталог уже содержит записи для
vite-plus,viteилиvitest, миграция использует этот каталог набора инструментов и для новых зависимостей иoverrides. Новый стандартный каталог верхнего уровня создаётся только в том случае, если невозможно использовать существующий стандартный или именованный каталог.
Другие правила.
- Каждый пакет, объявляющий зависимость
vite-plus, также получает прямую зависимостьviteвdevDependencies(см. Vite и overrides). - Не связанные с миграцией
overridesв виде селекторов или объектов сохраняются.
npm
- Прямые алиасы нормализуются до добавления соответствующего
override, чтобы npm не завершался с ошибкойEOVERRIDE. - Если обычная установка Vite заменяется алиасом ядра, перед повторной установкой удаляются устаревшие данные установки Vite и lock-файла.
- При использовании дополнительных браузерных провайдеров добавляется зависимость верхнего уровня
vite, если без неё вложенные пакеты Vitest не могут её разрешить.
Yarn
- Vite+ не поддерживает Plug'n'Play. Миграция обнаруживает явное и неявное использование PnP и переводит проект на
nodeLinker: node-modules, сохраняя все остальные настройки.yarnrc.yml. При использовании--no-interactiveпреобразование выполняется автоматически. Если установленYARN_NODE_LINKER=pnpна уровне процесса, пользователь должен изменить его самостоятельно. - Ссылки на каталоги и пользовательские настройки hoisting сохраняются.
- Миграция предотвращает появление нескольких экземпляров Vitest при изолированном hoisting в рабочих пространствах: если возможно, применяется исправление на уровне пакета, а если безопасно изменить конфигурацию нельзя — выводится предупреждение.
Bun
- Каталоги Bun работают только внутри рабочего пространства (корневой
package.jsonс непустым полемworkspaces). В рабочем пространстве Bun существующие расположения каталогов (верхнего уровня или рабочего пространства), а также ссылки на именованные каталоги сохраняются. Для отдельного проекта Bun (состоящего из одного пакета) используются конкретные версии зависимостей без создания поля каталога, посколькуbun installне умеет разрешать ссылкиcatalog:вне рабочего пространства. - Алиас ядра дублируется как прямая зависимость
vite, чтобы Bun мог обнаружить поставщика peer-зависимости до примененияoverrides.
После миграции
- Каждый файл конфигурации Vite проверяется на наличие конструкций, несовместимых с Rolldown (например,
manualChunks). Все найденные проблемы выводятся в виде предупреждений, но конфигурация автоматически не изменяется. - Зависимости переустанавливаются один раз для обновления lock-файла. Если установка завершается ошибкой, миграция сообщает об этом и завершается с ненулевым кодом.
- После успешной миграции выполняется
vp fmtдля файлов, изменённых в процессе миграции, за исключением путей, которые уже содержали несохранённые изменения в рабочем дереве Git. Oxfmt самостоятельно определяет поддерживаемые форматы файлов; в проектах без Git форматируется весь проект. Форматирование пропускается, если проект всё ещё использует Prettier. Ошибка форматирования выводится как предупреждение, чтобы результаты миграции сохранились, а пользователь мог вручную выполнить команду форматирования.