@mfe-orchestrator-hub/client-vue

Vue bindings for @mfe-orchestrator-hub/client: plugin and composables over the MFE Orchestrator client
1,023
Install
npm install @mfe-orchestrator-hub/client-vue
Latest Version:0.3.0
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm

@mfe-orchestrator-hub/client-vue

Part of MFE Orchestrator — the control plane for your microfrontends. The site is the short version; the documentation is where this package sits in context: environments, deployments, canary releases.

Vue 3 bindings for @mfe-orchestrator-hub/client.

Ergonomics only. Every decision — which version is served, how the manifest is fetched, how the identities are kept — lives in the core. This package is a plugin and two composables.

Install

pnpm add @mfe-orchestrator-hub/client-vue

@mfe-orchestrator-hub/client comes along as a dependency. vue is a peer dependency (3.3 or later).

Usage

import { createApp } from "vue"
import { createOrchestrator } from "@mfe-orchestrator-hub/client-vue"
import App from "./App.vue"

createApp(App)
    .use(
        createOrchestrator({
            backendUrl: import.meta.env.VITE_MFE_BACKEND_URL,
            projectId: import.meta.env.VITE_MFE_PROJECT_ID,
            environment: import.meta.env.VITE_MFE_ENVIRONMENT
        })
    )
    .mount("#app")

The plugin calls configure() on install, and configure() is idempotent, so installing twice is harmless.

It stays a convenience. The recommended place is still the very top of the entry point, because a bundler may import a remote before the app is created:

import { configure } from "@mfe-orchestrator-hub/client"

configure({ backendUrl: "…", projectId: "…", environment: "…" })

environment is optional

Leave it out and the backend picks the environment from the domain the host page is served on:

createApp(App)
    .use(
        createOrchestrator({
            backendUrl: import.meta.env.VITE_MFE_BACKEND_URL,
            projectId: import.meta.env.VITE_MFE_PROJECT_ID
        })
    )
    .mount("#app")

One build then serves every environment, and there is no VITE_MFE_ENVIRONMENT to keep in sync with the domain it is deployed to. The price is that the environment has to be mapped to a domain in the console: an unmapped domain has no environment to resolve to and the manifest request fails.

Passing environment keeps the old behaviour and always wins over the domain. Nothing changes for an app that already sets it.

This adapter never reads the field. It re-exports the core's OrchestratorConfig and hands the configuration over untouched, so which of the two the backend is asked for is decided entirely in the core.

useRemoteUrl(slug)

<script setup lang="ts">
import { useRemoteUrl } from "@mfe-orchestrator-hub/client-vue"

const { data: url, error, loading } = useRemoteUrl("checkout-new")
</script>

<template>
    <Spinner v-if="loading" />
    <p v-else-if="error">{{ error.message }}</p>
    <p v-else>{{ url }}</p>
</template>

slug accepts a value, a ref, or a getter. When it changes the URL is resolved again, and a late answer from the previous slug can never overwrite the newer one.

The URL is already pinned to the version the backend resolved. Use it verbatim: never rebuild it and never strip the _v/<version>/ segment.

useGlobalVariables()

const { data: variables } = useGlobalVariables()
// { API_URL: "https://…" }

Both composables return the same shape, as refs:

interface AsyncState<TValue> {
    data: Ref<TValue | undefined>
    error: Ref<Error | undefined>
    loading: Ref<boolean>
}

They read the one memoized manifest of the core, so N composables across N components still cost a single network request.

setUserId(userId)

The logged-in user is what a User canary is decided on, and it is the one thing that changes while the page is alive. A second configure() is ignored on purpose, so it has its own call:

import { setUserId } from "@mfe-orchestrator-hub/client-vue"

watch(() => auth.user?.id, id => setUserId(id))  // undefined on logout: back to the stable version

It drops the memoized manifest, so the next useRemoteUrl() is answered for the new user. Remotes already imported keep the version drawn for the previous one — the federation runtime holds the container it loaded — so resolve them behind your own navigation guard, or reload the page after the switch.

Needs a @mfe-orchestrator-hub/client that exposes setUserId(). On an older core the call warns and does nothing rather than crashing.

With module federation

The composables are for the app's own logic. The remote itself is wired in the bundler config, which talks to the core directly — see the core README.

Development

pnpm install
pnpm test        # vitest
pnpm build       # tsup, ESM + CJS + types
pnpm typecheck

License

MIT © Lorenzo De Francesco

Related Packages

tanstack-router-remote

Attach remote route trees to a TanStack Router host at runtime — React, Solid an...

526 4
@module-federation/nuxt

Nuxt module for Module Federation using Vite or Rspack

1,161 22
@module-federation/vite

Vite plugin for Module Federation

22,863,016 889
@fmfe/genesis-core

Vue SSR Microfront

15,867 680
@fulgurjs/federation

Vite Module Federation for Vue and React: remote modules, shared dependencies an...

21,909 0

Version History

Version Released Vue License
0.3.0 ^3.3.0 MIT
0.2.1 ^3.3.0 MIT
0.2.0 ^3.3.0 MIT
0.1.2 ^3.3.0 MIT
0.1.1 ^3.3.0 MIT