Vue Storefront is now Alokai! Learn More
Inheritance Best Practices

Inheritance Best Practices

This guide covers best practices for managing inheritance in Alokai multistore projects.

What You'll Learn

  • How to break down large files into smaller, more manageable components
  • How to use template stores for shared code
  • How to handle special files in multistore projects
  • How to override types and interfaces in multistore projects
  • How to use the Alokai Plugin for VS Code, Cursor and Windsurf

For a detailed explanation of how inheritance works in Alokai multistore projects, see File-based inheritance guide in the Tooling and Concepts section.

Easy Overriding

When working with multistore projects, it's crucial to structure your code in a way that makes it easy to override specific parts in individual stores. One of the best practices is to break down large files into smaller, more manageable components.

For example, instead of having a single large language file:

apps/storefront-unified-nextjs/lang/en/en.json
// ❌ Avoid large monolithic files
{
  "AddToCartButton": {
    "label": "Add to cart"
  },
  // ... other base translations
  "RegisterPage": {
    "heading": "Create Account",
    "metaTitle": "Create Account",
    "toLoginAlert": "Already have an account? Switch to <login>Log in</login>."
  }
  // ... other register translations
  "Footer": {
    "bottomLinks": {
      "privacyPolicy": "Privacy policy",
      "terms": "Terms"
    },
  },
  // ... other footer translations
}

Break it down into smaller, focused modules:

apps/storefront-unified-nextjs/lang/en/index.ts
// ✅ Split into smaller, focused modules
import base from "@/lang/en/base.json";
import register from "@/lang/en/register.json";
import Footer from "@/lang/en/footer.json";

export default () => ({
  ...base,
  ...register,
  Footer,
});

This approach makes it much easier to override specific parts of the language files in individual stores, as you can import and modify only the components you need.

Using Template Stores for Shared Code

Template Stores are a powerful pattern for managing shared code between stores that have significant overlap in functionality and design. They serve as a base implementation that other stores can extend and customize. Whenever you add a new code, check what part of it is shareable and can be added to the parent store - think about code reusability first.

When to use template stores

Template Stores are particularly useful when:

  • Multiple brands share the same business logic and UI components
  • You have a group of stores with similar requirements and features
  • You need to maintain consistency across multiple brands
  • You want to reduce code duplication between similar stores

Trade-offs to consider

While Template Stores offer significant benefits, they come with some trade-offs. The main challenges with Template Stores are:

  • The project structure becomes more complex as you need to manage multiple levels of inheritance and understand how changes propagate through the system
  • Changes to the template store can have far-reaching effects on all dependent stores, requiring careful updates and robust testing
  • While template stores provide consistency, they can make it harder to implement store-specific features that deviate from the template

To mitigate these challenges, consider:

  • Keeping the template as generic as possible
  • Documenting which parts are meant to be overridden
  • Creating a process for testing changes across all dependent stores
  • Avoid deep inheritance chains (more than 3 levels)
  • Consider flattening the structure if maintenance becomes difficult

Special file handling

Certain configuration files require special handling in multistore projects due to how the inheritance system works and how the CLI manages them.

package.json

  • Do not create this file within store directories
  • The CLI automatically generates it in the .out directory during build
  • Add all dependencies to the root app's package.json (e.g., apps/storefront-unified-nextjs/package.json)
  • This ensures consistent dependency management across all stores

tsconfig.json

  • Do not modify this file within store directories
  • The CLI automatically generates and manages it
  • Manual changes may break the inheritance system
  • TypeScript configuration is handled centrally to maintain consistency

eslint.config.mjs

  • Every app in every store has its own ESLint config file
  • By default, it uses the shared ESLint config rules present in the packages/eslint-config
  • It is recommended to use the shared ESLint config to avoid duplication and ensure consistency across the project
  • You can extend or override specific rules in individual stores if needed

prettier.config.mjs

  • Same as ESLint config
  • Every app in every store has its own Prettier config file
  • Use the shared Prettier config from packages/prettier-config for consistency
  • Override only when store-specific formatting rules are required

tailwind.config.ts

  • Same as ESLint config
  • Every app in every store has its own Tailwind config file
  • Use the shared Tailwind config from packages/tailwind-config for consistency
  • Override only when store-specific styling requirements differ

Type and Interface overriding

When overriding types and interfaces in multistore projects, it's crucial to follow specific patterns to maintain compatibility with the rest of the application.

When overriding types or interfaces, always extend them with optional parameters rather than replacing or removing existing ones. This ensures that other parts of the application that depend on these types continue to work correctly.

// ❌ Avoid replacing or removing existing properties
interface Product {
  id: string;
  name: string;
  // Removed price property that other components might depend on
}

// ✅ Extend with optional properties
interface Product {
  id: string;
  name: string;
  price: number;
  // Add store-specific optional properties
  storeSpecificField?: string;
  customAttribute?: boolean;
}

Always ensure that your type extensions maintain backward compatibility:

  • Never remove required properties from base types
  • Only add optional properties unless absolutely necessary
  • Use union types when you need to support multiple variants
  • Document any breaking changes if they cannot be avoided

This approach prevents runtime errors and ensures that components from parent stores continue to function correctly in child stores.

Alokai Plugin for VS Code, Cursor and Windsurf

To enhance your development experience when working with Alokai multistore projects, you can use the Alokai Plugin for Visual Studio Code and its forks (Cursor, Windsurf).

Features

The extension provides powerful tools for managing multistore projects:

  • Visual Store Tree: Browse and manage your Alokai stores in a dedicated sidebar
  • Drag & Drop: Reorganize stores by dragging them to change their parent structure
  • Build Management: Build individual stores with one click
  • Dev Server Control: Start and stop development servers with visual status indicators
  • File Operations: Override files in the apps folder with context menu actions
  • Source Navigation: Navigate between source files and their .out counterparts
  • Diff Comparison: Compare files with their parent versions

Key Benefits for Multistore Development

The extension significantly improves the multistore development workflow by:

  • Simplifying Store Management: Visual interface for managing store hierarchy
  • Streamlining File Operations: Easy file overriding and navigation between source and generated files
  • Enhancing Development Workflow: One-click build and dev server management
  • Improving Navigation: Quick access to parent files and diff comparisons

This tool is particularly valuable when working with complex inheritance structures, as it provides clear visual feedback about store relationships and makes it easier to manage file overrides across multiple stores.