@ecommerce-platform/shared-layout
v1.0.3
Published
Shared layout components for ecommerce micro-frontends - provides Navbar, Footer, and Layout with intelligent navigation for standalone and MFE modes
Maintainers
Readme
@ecommerce-platform/shared-layout
Shared layout components for ecommerce micro-frontends. Provides Navbar, Footer, and Layout components with intelligent navigation that works in both standalone and MFE (Module Federation) modes.
Features
- Intelligent Navigation: Automatically detects standalone vs MFE mode and redirects users appropriately
- Host Fallback: In standalone mode, tries to navigate to host app first, then falls back to standalone MFE if host is unavailable
- Consistent UI: Same layout and styling across all micro-frontends
- Flexible Props: Accepts external data (basket, categories) for maximum flexibility
Installation
npm install @ecommerce-platform/shared-layoutUsage
Basic Setup
import { Layout, configureNavigation } from '@ecommerce-platform/shared-layout';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// Configure navigation (optional, defaults work for most cases)
configureNavigation({
hostUrl: 'http://localhost:4200',
currentAppName: 'store', // e.g., 'store', 'checkout', 'account'
standalonePorts: {
store: 4201,
checkout: 4202,
account: 4203,
},
});
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout appName="store" />}>
<Route index element={<YourComponent />} />
</Route>
</Routes>
</BrowserRouter>
);
}With Basket Data
import { Layout } from '@ecommerce-platform/shared-layout';
import { useBasket } from './services/basket';
function App() {
const { items, itemCount, isLoading } = useBasket();
// Map your basket items to CartItem format
const cartItems = items.map(item => ({
id: item.productId,
name: item.productName,
price: item.price,
quantity: item.quantity,
image: item.imageFile || '',
}));
return (
<Layout
appName="store"
basketCount={itemCount}
cartItems={cartItems}
isLoading={isLoading}
onRemoveCartItem={(id) => {
// Handle remove cart item
}}
>
<YourRoutes />
</Layout>
);
}With Categories
import { Layout } from '@ecommerce-platform/shared-layout';
import { useCategories } from './services/categories';
function App() {
const { categories, isLoading } = useCategories();
return (
<Layout
appName="store"
categories={categories.map(cat => ({
id: cat.id,
name: cat.name,
icon: cat.icon,
path: cat.path,
}))}
categoriesLoading={isLoading}
>
<YourRoutes />
</Layout>
);
}Standalone Mode Detection
The package automatically detects if it's running in standalone mode by checking:
- If
window.__MFE_HOST__is defined (set by host when loading MFE) - If the current port matches a standalone MFE port
Navigation Behavior
- In MFE mode (loaded by host): Uses React Router navigation normally
- In standalone mode:
- First tries to navigate to host app (e.g.,
http://localhost:4200/checkout) - If host is unavailable, falls back to standalone MFE (e.g.,
http://localhost:4202/checkout)
- First tries to navigate to host app (e.g.,
Custom Navigation
import { useNavigate } from '@ecommerce-platform/shared-layout';
function MyComponent() {
const navigate = useNavigate('store'); // Pass app name for fallback
const handleClick = () => {
// Will try host first, then fallback to standalone if needed
navigate('/checkout');
};
return <button onClick={handleClick}>Go to Checkout</button>;
}Theme Configuration
The package includes a complete Ant Design theme configuration that matches the host app:
import { themeConfig } from '@ecommerce-platform/shared-layout';
import { ConfigProvider } from 'antd';
function App() {
return (
<ConfigProvider theme={themeConfig}>
<YourApp />
</ConfigProvider>
);
}The theme includes:
- Brand colors (primary gradient: #667eea to #764ba2)
- Typography (Poppins font family)
- Spacing, shadows, and border radius
- Component-specific styles (Button, Input, Card, Layout, Typography)
API Reference
Layout
Main layout component that wraps your application.
Props:
appName?: string- Current app name for navigation fallbackbasketCount?: number- Number of items in basketcartItems?: CartItem[]- Cart items for previewisLoading?: boolean- Loading state for cart dataonRemoveCartItem?: (id: string) => void- Callback when removing itemcategories?: Array<{id: string; name: string; icon?: string; path: string}>- Categories for dropdowncategoriesLoading?: boolean- Loading state for categorieshideNavbar?: boolean- Hide navbar (default: false)hideFooter?: boolean- Hide footer (default: false)
Navbar
Standalone navbar component.
Props: Same as Layout (except hideNavbar and hideFooter)
Footer
Standalone footer component.
Props:
appName?: string- Current app name for navigation fallback
configureNavigation(config)
Configure navigation settings.
Config:
hostUrl?: string- Host app URL (default:http://localhost:4200)currentAppName?: string- Current MFE app namestandalonePorts?: Record<string, number>- Map of app names to ports
useNavigate(appName?)
Custom navigation hook that handles redirects intelligently.
isStandaloneMode()
Check if running in standalone mode.
Examples
Store App (Standalone)
// store/src/app.tsx
import { Layout, configureNavigation } from '@ecommerce-platform/shared-layout';
configureNavigation({
currentAppName: 'store',
});
export function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout appName="store" />}>
<Route path="*" element={<StoreRoutes />} />
</Route>
</Routes>
</BrowserRouter>
);
}Checkout App (Standalone)
// checkout/src/app.tsx
import { Layout, configureNavigation } from '@ecommerce-platform/shared-layout';
configureNavigation({
currentAppName: 'checkout',
});
export function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout appName="checkout" />}>
<Route path="*" element={<CheckoutRoutes />} />
</Route>
</Routes>
</BrowserRouter>
);
}License
MIT