Sub-path Routing Implementation
This guide provides step-by-step instructions for implementing sub-path routing in your Alokai application.
Prerequisites
Before starting, ensure you've read the overview and made your architectural decision using the choosing approach guide.
Prerequisites
Before implementing sub-path routing, you need to configure your Middleware to support different configurations using the Config Switcher extension.
Config Switcher Setup Required
Follow the complete Config Switcher installation guide to set up your middleware with multiple configurations. For sub-path routing, you'll want to configure different settings for each path segment (e.g., apparel
, electronics
) in your Config Switcher setup.
Setting Up the Storefront
Configure your Storefront to send the appropriate config ID to the Middleware based on the current URL path.
In your Next.js SDK utils, implement the getConfigSwitcherHeader
function:
// apps/storefront-unified-nextjs/sdk/modules/utils.ts
import { defineGetConfigSwitcherHeader } from '@vue-storefront/next';
export const defaultConfigId = 'apparel';
export const configIds = ['apparel', 'electronics'];
export const getConfigSwitcherHeader = defineGetConfigSwitcherHeader(
({ pathname }) => configIds.find((configId) => pathname.startsWith(`/${configId}`)) ?? defaultConfigId,
);
Updating the Routing Strategy
To enable path-based routing, you need to restructure your application to include a dynamic [configId]
parameter in the route. You can choose one of two strategies:
[configId]
as second parameter -/de/electronics/category
(Recommended)[configId]
as first parameter -/electronics/de/category
[configId]
as Second Path Parameter (Recommended)
For Next.js apps using the App Router, update your file structure:
apps/storefront-unified-nextjs/app/
├── [locale]/ # Locale parameter
│ ├── [configId]/ # Store identifier parameter
│ │ ├── (default)/ # Routes for all stores
│ │ │ ├── page.tsx # Home page
│ │ │ ├── cart/ # Cart pages
│ │ │ ├── checkout/ # Checkout pages
│ │ │ └── products/ # Product pages
│ │ ├── (electronics)/ # Electronics-specific routes
│ │ │ └── some-page/ # Page name
│ │ ├── (apparel)/ # Apparel-specific routes
│ │ │ └── another-page/ # Apparel-specific home
│ │ └── layout.tsx # Apply store-specific class
│ ├── favicon.ico
[configId]
as First Path Parameter
This approach places the configId as the first parameter in the URL structure. Note that this impacts i18n
packages and requires additional configuration changes to maintain proper internationalization.
Not Recommended
This approach is not recommended as it impacts the i18n
packages and requires additional configuration changes to maintain proper internationalization. Consider using the second path parameter approach unless you have specific requirements that necessitate this structure. If you really need such option, contact our support.
This structure enables routes like:
/en/electronics
- Electronics store home/en/apparel
- Apparel store home/en/electronics/category
- PLP in the electronics store/en/apparel/category
- PLP in the apparel store
Updating Internal Links
Update Internal Links
After setting up the path routing structure, you must update all internal links in your application to include the appropriate configId parameter. This is crucial to maintain proper navigation within each store and prevent users from accidentally switching between stores when clicking links.
Make sure that all your internal links and navigation components preserve the store context by including the current configId in the URLs.
Store-Specific Styling
Implement configuration-specific styling through CSS variables and Tailwind variants:
1. Applying Store Identifier Class
Apply the configId as a CSS class to enable different styles for each configuration:
In your Next.js layout, apply the configId as a class to the root layout element:
// apps/storefront-unified-nextjs/app/[locale]/[configId]/layout.tsx
import { PropsWithChildren } from 'react';
interface LayoutProps extends PropsWithChildren {
params: {
configId: string;
};
}
export default function Layout({ children, params: { configId } }: LayoutProps) {
return (
<div className={configId}>
{children}
</div>
);
}
2. Defining Store-Specific CSS Variables
Define CSS variables that change based on the store:
// apps/storefront-unified-nextjs/app/[locale]/globals.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
// Electronics store theme
.electronics {
--colors-primary-50: 45 249 255;
--colors-primary-100: 233 243 255;
--colors-primary-500: 51 117 255;
// ... other variables
}
// Apparel store theme (different color scheme)
.apparel {
--colors-primary-50: 243 254 249;
--colors-primary-100: 224 247 235;
--colors-primary-500: 45 165 116;
// ... other variables
}
3. Using Store-Specific Styles
Update your Tailwind config and use variants in your components:
// packages-end-user/tailwind-config/src/nextjs.ts
import plugin from "tailwindcss/plugin";
const config: Config = {
plugins: [
plugin(({ addVariant }) => {
addVariant("electronics", ".electronics &");
addVariant("apparel", ".apparel &");
}),
],
};
Then use these variants in your components:
export default function NavbarTop({ children, className }: NavbarTopProps) {
return (
<header
className={classNames(
'sticky top-0 z-40 flex h-14 bg-primary-800',
'electronics:!bg-primary-600',
'apparel:!bg-primary-400',
'md:-top-5 md:h-20 md:pt-2.5',
className
)}
>
{children}
</header>
);
}
Conditional Components
Handle store-specific components using two main approaches:
Approach 1: Different Versions of the Same Component
Useful when you need different variations of a component based on the store:
// apps/storefront-unified-nextjs/components/announcement-bar.tsx
import { ApparelAnnouncementBar } from '@/components/store-apparel/announcement-bar';
import { ElectronicsAnnouncementBar } from '@/components/store-electronics/announcement-bar';
interface AnnouncementBarProps {
configId: string;
}
function AnnouncementBar({ configId }: AnnouncementBarProps) {
const StoreComponent = {
apparel: ApparelAnnouncementBar,
electronics: ElectronicsAnnouncementBar,
}[configId];
return StoreComponent ? <StoreComponent /> : null;
}
Approach 2: Conditional Rendering Based on Store
Useful when certain components should only appear in specific stores:
export default function HomePage({ params: { configId } }: HomePageProps) {
return (
<div>
<h1>Welcome to our store</h1>
{configId === 'electronics' && (
<ElectronicsPromo />
)}
<div>
{/* Common content for all stores */}
</div>
</div>
);
}
Creating Store-Specific Pages
Some pages might only exist for specific stores:
For Next.js, use route groups with the store name, and check the configId parameter:
// apps/storefront-unified-nextjs/app/[locale]/[configId]/(electronics)/layout.tsx
import { notFound } from 'next/navigation';
export default function ElectronicsLayout({ children, params }: ElectronicsLayoutProps) {
if (params.configId !== 'electronics') {
notFound();
}
return <div>{children}</div>;
}
Summary
Sub-path routing implementation involves:
- Config Switcher Setup: Configure your middleware with multiple integration configurations
- Storefront Configuration: Set up header functions to send the appropriate config ID
- Routing Structure: Implement dynamic
[configId]
parameters in your routes - Styling System: Use CSS variables and Tailwind variants for configuration-specific styles
- Conditional Logic: Implement component and page variations based on the active configuration
This approach provides a powerful single-deployment solution for serving multiple configurations while maintaining unified user experience and shared functionality.