Package Exports
- @pawells/react-federation-core
- @pawells/react-federation-core/client
- @pawells/react-federation-core/components
- @pawells/react-federation-core/context
- @pawells/react-federation-core/errors
- @pawells/react-federation-core/hooks
- @pawells/react-federation-core/loaders
Readme
@pawells/react-federation-core
React client library for consuming a Module Federation registry service. Provides a context provider, hooks, and components for discovering, loading, and rendering federated remote modules inside a React application.
Installation
yarn add @pawells/react-federation-coreSetup
Wrap your application with FederationProvider and supply a FederationConfig.
import { FederationProvider, ScriptInjectionLoader } from '@pawells/react-federation-core';
function Root() {
return (
<FederationProvider
config={{
serviceUrl: 'https://api.example.com/api/v1',
auth: { bearerTokenFn: () => getAccessToken() },
}}
>
<App />
</FederationProvider>
);
}FederationConfig
| Option | Type | Default | Description |
|---|---|---|---|
serviceUrl |
string |
— | Required. Base URL of the federation service including version path, e.g. https://api.example.com/api/v1 |
auth |
FederationAuthConfig |
— | Authentication credentials (see below) |
requestTimeout |
number |
10000 |
HTTP request timeout in milliseconds |
loader |
ModuleLoader |
ScriptInjectionLoader |
Module loader strategy (see Loaders section) |
FederationAuthConfig — exactly one of:
{ bearerToken: string } // static token
{ bearerTokenFn: () => string | Promise<string> } // dynamic token (e.g. from useAuth)
{ apiKey: string } // API key headerLoaders
The loader determines how remote entry files are fetched and how modules are extracted from the container.
| Loader | Use when |
|---|---|
ScriptInjectionLoader |
Remote is built with Webpack 5 Module Federation (default). Injects a <script> tag and reads the container from window[scope]. |
ViteModuleLoader |
Remote is built with Vite + vite-plugin-federation. Polls window[scope] after script injection. |
NativeEsmLoader |
Remote is a plain ES module with no Webpack or Vite federation runtime. Uses native import(). |
import { FederationProvider, ViteModuleLoader } from '@pawells/react-federation-core';
<FederationProvider config={{ serviceUrl: '...', loader: new ViteModuleLoader() }}>
<App />
</FederationProvider>ScriptInjectionLoader accepts an optional { scriptLoadTimeout?: number } (default 10000 ms).
Components
RemoteComponent
Convenience component that loads and renders a federated module with built-in Suspense and error boundary handling.
import { RemoteComponent } from '@pawells/react-federation-core';
<RemoteComponent
moduleId="ui-module@1.0.0"
exposedPath="./Button"
componentProps={{ label: 'Click me' }}
fallback={<Spinner />}
errorFallback={<p>Failed to load module</p>}
/>| Prop | Type | Default | Description |
|---|---|---|---|
moduleId |
string |
— | Required. Module ID ("name@version") or module name for the latest version |
exposedPath |
string |
— | Required. Exposed path, e.g. "./Button" |
componentProps |
Record<string, unknown> |
— | Props forwarded to the loaded component |
fallback |
React.ReactNode |
null |
Rendered while the module is loading (Suspense fallback) |
errorFallback |
ReactNode | (error, reset) => ReactNode |
'Failed to load remote module' |
Rendered when loading fails |
onError |
(error, info) => void |
— | Called when an error is caught by the boundary |
RemoteErrorBoundary
Class-based error boundary for remotely-loaded modules. Place it outside the Suspense boundary that wraps lazy remote components. Supports a render-function fallback that receives the error and a reset callback.
import { RemoteErrorBoundary } from '@pawells/react-federation-core';
<RemoteErrorBoundary
fallback={(error, reset) => (
<div>
<p>Error: {error.message}</p>
<button onClick={reset}>Retry</button>
</div>
)}
>
<Suspense fallback={<Spinner />}>
<LazyRemoteButton />
</Suspense>
</RemoteErrorBoundary>Hooks
useFederatedModule
Loads a federated module and returns a stable React.lazy component reference. Metadata and component references are cached in the FederationContext to prevent duplicate requests and Suspense resets.
import { useFederatedModule } from '@pawells/react-federation-core';
function RemoteButtonWrapper() {
const LazyButton = useFederatedModule('ui-module@1.0.0', './Button');
return (
<Suspense fallback={<Spinner />}>
<LazyButton label="Click me" />
</Suspense>
);
}useFederationRegistry
Searches and lists modules in the federation registry. Supports filtering, pagination, and manual re-fetching.
import { useFederationRegistry } from '@pawells/react-federation-core';
const { modules, total, isLoading, error, refetch, stats, fetchStats } =
useFederationRegistry({ query: 'header', limit: 20 });| Option | Type | Description |
|---|---|---|
query |
string |
Full-text search query |
type |
string |
Filter by module type |
limit |
number |
Max results per page |
offset |
number |
Pagination offset |
immediate |
boolean |
Fetch on mount. Defaults to true |
useFederationContext
Returns the raw FederationContextValue (client, loader, caches) from the nearest FederationProvider. Throws if called outside a provider. Useful when building custom loader or registry integrations.
Error handling
All errors thrown by the library extend FederationError and carry a machine-readable code property.
| Class | When thrown |
|---|---|
FederationError |
Base class for all library errors |
ModuleLoadError |
The remote entry loaded but the exposed module could not be retrieved |
ModuleNotFoundError |
The module ID was not found in the registry or has no remoteEntry |
ServiceConnectionError |
The federation service is unreachable or returned a non-2xx response |
import { ModuleLoadError, ModuleNotFoundError } from '@pawells/react-federation-core';
try {
// ...
} catch (error) {
if (error instanceof ModuleNotFoundError) {
console.warn('Module not registered:', error.message);
} else if (error instanceof ModuleLoadError) {
console.error('Load failed:', error.message, error.cause);
}
}Failed module entries are automatically removed from the component cache so the next render retries the load.