Как Vite Module Federation ломается при раздельном старте

от автора

Если у вас есть два приложения на React + Vite — хост и микрофронт (remote) — и при общем старте через одну команду всё магически ок, а при раздельном запуске хост падает с 404 на remoteEntry.js, вы не одиноки. Разбираемся, почему так, и показываю рабочие рецепты.

Remote (react-vite/remote) публикует модуль:

// vite.config.js (remote) import federation from '@originjs/vite-plugin-federation' export default defineConfig({   plugins: [     federation({       name: "remote_app",       filename: "remoteEntry.js",       exposes: { './Button': './src/components/Button' },       shared: ['react','react-dom']     })   ] })

Host (react-vite/host) тянет remote:

// vite.config.js (host) import federation from '@originjs/vite-plugin-federation' export default defineConfig({   plugins: [     federation({       name: 'app',       remotes: {         remoteApp: 'http://localhost:5001/assets/remoteEntry.js',       },       shared: ['react','react-dom']     })   ] })

Импорт в хосте:

// src/App.jsx (host) import Button from 'remoteApp/Button';

Проблема

  • При раздельном запуске: хост запрашивает http://localhost:5001/assets/remoteEntry.js, а remote ещё не готов или отдает другой путь/файл для текущего режима. Результат — 404 и:

  • GET …/remoteEntry.js net::ERR_ABORTED 404

  • Failed to fetch dynamically imported module…

    При общем старте командой вида

    pnpm --parallel --filter "./**" preview

    оба сервиса поднимаются вместе, remote успевает начать отдавать remoteEntry.js, и хост не падает.

    Почему это происходит на самом деле

    • Не “синхронный импорт”, а гонка запуска и/или несоответствие режимов.

    • В Vite:

    • В dev-режиме файл remote может быть “виртуальным” и сервиться на лету плагином.

    • В preview-фазе он отдается из dist после vite build.

    • Если хост открылся раньше, remote ещё не слушает порт 5001 или не собран — будет 404.

    • Ещё один частый кейс — запуск в разных режимах (например, host в preview, а remote в dev): тогда пути и поведение могут различаться.

    Как воспроизвести и увидеть разницу

    # Терминал 1 pnpm --filter "react-vite/remote" preview  # или dev  # Терминал 2 (сразу или чуть раньше) pnpm --filter "react-vite/host" preview 

    Если хост открыли раньше, получите 404 на remoteEntry.js.

    pnpm --parallel --filter "./**" preview

    Обычно remote успевает подняться к первому заходу в хост, и всё ок.

    Рабочие рецепты

    • Запускайте в одном режиме на обоих концах.

    • dev+dev или build+preview для обоих. Не мешайте режимы.

    • Гарантируйте порядок (ждите remote).

    • Делайте URL remote динамическим через env

    // vite.config.js (host) import { defineConfig, loadEnv } from 'vite' import federation from '@originjs/vite-plugin-federation'  export default defineConfig(({ mode }) => {   const env = loadEnv(mode, process.cwd(), '')   return {     plugins: [       federation({         remotes: {           remoteApp: env.VITE_REMOTE_URL // например: http://localhost:5001/assets/remoteEntry.js         },         shared: ['react','react-dom']       })     ]   } })

    Теперь можно явно указывать корректный URL для dev/preview через .env:

    # .env.development VITE_REMOTE_URL=http://localhost:5001/assets/remoteEntry.js
    • Добавьте простой retry/“обновите страницу”.

    • Иногда банально достаточно дождаться старта remote и перезагрузить хост: Vite подхватит remoteEntry.js.

    • Монорепо-скрипт “одним махом”.

    • Уже работающий подход — общая команда, которая стартует оба сервиса. Это снижает вероятность гонки.

    Быстрый чеклист

    • Порты совпадают с конфигом? Host реально указывает на 5001, а remote слушает 5001?

    • Режимы согласованы? dev↔dev, preview↔preview.

    • Remote действительно отдает assets/remoteEntry.js? Откройте URL в браузере.

    • Порядок старта учтен? Ждите remote перед открытием host.

    Итоги

    • Симптом: 404 на remoteEntry.js при раздельном запуске.

    • Причина: гонка старта и/или разные режимы сборки/предпросмотра.

    • Решение: стартовать синхронно, ждать готовность remote, унифицировать режимы, вынести URL remote в переменные окружения, при необходимости — добавить ожидание/ретраи.

    Следуя этим практикам, вы избавитесь от «мистических» 404 и сделаете запуск предсказуемым как локально, так и в CI/CD.


    ссылка на оригинал статьи https://habr.com/ru/articles/938820/


    Комментарии

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *