Если у вас есть два приложения на 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.

    Комментарии (0)