Skip to content

Основные понятия Module Federation

Эта страница собирает термины после того, как понятны bootstrap, host runtime и передача scope.

QueryRuntime

Root-контейнер server state, которым владеет host:

ts
const runtime = createQueryRuntime(config)
await runtime.initialize()

Он содержит общий QueryClient, request executor, browser lifecycle и реестр participants. Remote root runtime не получает.

Participant

Participant — один подключённый consumer runtime:

  • host application;
  • standalone application;
  • один mount remote.

Один и тот же remote, смонтированный два раза, создаёт два participants.

Participant registration

Registration — объект, которым host описывает participant до создания scope:

ts
const registration = {
    participantId: "billing-remote",
    participantType: "remote",
    version: "1.6.0",
    minimumRuntimeVersion: "3.2.0",
    requiredRuntimeCapabilities: ["query", "mutation"],
    tenantId: session.tenantId,
    userId: session.userId,
    capabilities: {
        queryNamespaces: [["billing"]],
        mutationNamespaces: ["billing"],
    },
} as const

Host, а не remote, формирует final registration. Особенно это относится к tenantId, userId и namespace permissions.

Scope

scope — произвольное имя локальной переменной:

ts
const scope = runtime.createParticipantScope(registration)

Можно назвать её billingScope или participantRuntime. Тип — IScopedQueryRuntime.

Scope:

  • создаёт MobX stores на общей инфраструктуре host;
  • автоматически добавляет owner/tenant/user partition;
  • проверяет query и mutation namespaces;
  • отслеживает созданные stores;
  • освобождает их одним scope.dispose().

Scope не является:

  • Axios client;
  • React context;
  • MobX-store бизнес-модели;
  • root QueryRuntime;
  • глобальной переменной;
  • механизмом загрузки remote.

Identity scope

После создания доступно scope.identity:

ПолеИсточникСмысл
participantIdregistrationСтабильное имя модуля.
participantTyperegistrationapplication, host или remote.
versionregistrationВерсия модуля.
tenantId, userIdhost sessionData partition.
instanceIdruntime или registrationУникальный id конкретного mount.
protocolVersionruntimeСогласованная версия protocol.

participantId может совпадать у двух mount. instanceId должен отличаться.

Логический и физический queryKey

Remote пишет логический ключ:

ts
;["billing", "invoices"]

Runtime добавляет физический prefix, который концептуально содержит:

text
runtime application + tenant + user + private/shared owner + logical key

Remote не должен строить этот prefix вручную. Поэтому одинаковые логические ключи разных users и private mount не сталкиваются.

Namespace

Namespace — разрешённый префикс логического key.

ts
queryNamespaces: [["billing"], ["shared", "currency"]]

Ключ ["billing", "invoices"] разрешён. Ключ ["support", "tickets"] запрещён.

Mutation namespace — строковый prefix:

ts
mutationNamespaces: ["billing"]

Разрешены billing.pay и billing.cancel, запрещён support.close.

Private query

По умолчанию query принадлежит конкретному instanceId. Два mount billing remote с одинаковым логическим ключом получают разные cache entries.

Это безопасный default для screen state и персональных данных одного mount.

Shared query

Host может явно разрешить префикс в sharedQueryNamespaces:

ts
sharedQueryNamespaces: [["shared", "currency"]]

Тогда participants одной application/tenant/user partition используют одну cache entry. Shared query обязана иметь definitionId:

ts
scope.query.createStore({
    definitionId: "currency.dictionary.v1",
    queryKey: () => ["shared", "currency", "list"],
    queryFn: ({ signal }) => api.currency({ signal }),
})

definitionId задаёт стабильный id такого договора. Runtime требует его наличие для shared query. FetchStore, QueryStore и InfiniteQueryStore передают id в query definition/observer, поэтому несовместимый definitionId для того же физического cache slot приводит к QueryDefinitionConflictError.

Runtime capabilities и participant capabilities

Это два разных понятия:

ВидПримерВопрос
Runtime capabilitiesquery, mutationКакие части scoped API host вообще умеет предоставить?
Participant capabilitiesquery/mutation namespacesС какими данными конкретному remote разрешено работать?

Полная страница: Capabilities.

Data partition

Комбинация application, tenant и user определяет логический раздел данных. Shared query разделяется только внутри одной partition. Query пользователя A не становится доступной пользователю B.

Подробнее: Кэш, разделы и sharing.

Ownership и dispose

Store, созданный через scope, регистрируется как ресурс participant:

ts
const invoices = scope.query.createStore(...)

Можно вызвать invoices.dispose() локально. При unmount host всё равно вызывает scope.dispose(), чтобы освободить оставшиеся stores и owned requests.

Root runtime.dispose() закрывает все ещё живые scopes. Правильный порядок: Lifecycle.