Skip to content

Настройка host и remote

Эта страница настраивает только загрузку remote module. Перед ней прочитайте Bootstrap и mount.

Рекомендуемая структура

text
apps/
  shell/                 host application
  billing-remote/        remote application
packages/
  contracts/             TypeScript bootstrap/API contracts

contracts не создаёт runtime singleton и не содержит React UI. В нём лежат только interface/type, которые одинаково видят host и remote.

Shared dependencies

React, React DOM, MobX и Query Layer должны быть singleton в одной странице. Иначе можно получить две React runtime, две MobX reactive graph или разные версии scoped protocol.

ts
// Общая часть Webpack/Rspack federation config.
export const shared = {
  react: {
    singleton: true,
    requiredVersion: "^19.0.0",
  },
  "react-dom": {
    singleton: true,
    requiredVersion: "^19.0.0",
  },
  mobx: {
    singleton: true,
    requiredVersion: "^7.0.3",
  },
  "mobx-react-lite": {
    singleton: true,
    requiredVersion: "^5.0.0",
  },
  "@dubium/query-layer": {
    singleton: true,
    // Текущий workspace — 1.0.0-rc.1; ^1.0.0 не включает prerelease.
    requiredVersion: "^1.0.0-rc.1",
  },
  axios: {
    singleton: true,
    requiredVersion: "^1.7.0",
  },
}

Точный синтаксис зависит от federation plugin. Инвариант один: host и remote должны согласовать совместимые версии. Для Query Layer 1.0 RC требуется MobX 7; mobx-react-lite 5 требует React 18 или новее. Не смешивайте MobX 6 и 7 в federation graph: singleton должен разрешиться в один экземпляр MobX 7.

Host config

ts
new ModuleFederationPlugin({
  name: "shell",

  // Alias billing будет использоваться в import("billing/bootstrap").
  remotes: {
    billing: "billing@https://billing.example.com/remoteEntry.js",
  },

  shared,
})

Remote URL берите из доверенной конфигурации окружения. Не разрешайте пользователю подменить origin через query string.

Remote config

ts
new ModuleFederationPlugin({
  name: "billing",
  filename: "remoteEntry.js",

  // Host видит только bootstrap boundary.
  exposes: {
    "./bootstrap": "./src/bootstrap.tsx",
  },

  shared,
})

Не публикуйте отдельными exposes внутренние stores, token provider и Axios client. Host должен зависеть только от bootstrap contract.

Type declaration динамического import

ts
declare module "billing/bootstrap" {
  import type { BillingRemoteModule } from "@portal/contracts"

  export const mount: BillingRemoteModule["mount"]
}

Так TypeScript проверит, что host передал все обязательные bootstrap options.

Локальные адреса

ЧастьURL
Hosthttp://127.0.0.1:3000
Billing remote entryhttp://127.0.0.1:3001/remoteEntry.js
Backendhttp://127.0.0.1:3100

CORS для remote chunks и CORS backend — разные настройки. Разрешение загрузить JavaScript remote не должно автоматически открывать API любому origin.

Deployment

  • remote chunks публикуются с content hash;
  • remoteEntry.js имеет контролируемый cache policy;
  • host знает фактическую версию remote;
  • rollback remote не требует пересборки host;
  • несовместимый protocol отклоняется до UI mount;
  • URL remote входит в allowlist host.

Что должно работать перед runtime

Проверьте:

  1. import("billing/bootstrap") завершается успешно;
  2. remote.mount({ container }) показывает UI;
  3. returned disposer удаляет React tree;
  4. повторный mount/unmount не оставляет listeners;
  5. shared React/MobX загружены в одном экземпляре.

Теперь можно создать root runtime в host: Runtime в host.