Skip to main content

Plugin-Host Composition Patterns

Framework M supports a highly flexible, multi-package UI architecture. This guide explains how to compose independently developed applications into a unified user experience, using a reference example of a business suite.

The Reference Suite (Example)

In this guide, we use the following example structure. Note that these are independent repositories/packages, not part of the framework core:

  • business-m: The "Host Shell". Provides the main layout, navigation, and workspace.
  • wms, finance, people: "Plugins". Provide specific business logic and UI modules.

Zero-Cliff Progression

You can start simple and scale up to complex micro-frontends (MFEs) as your project grows.

1. The Default (Level 0)

When you build a basic app like wms, you don't need to build a custom UI host.

  • Action: Install framework-m-standard.
  • Result: Your app contributes DocTypes and backend logic. The UI is served by the default Desk shell bundled with Framework M.

2. Custom Branding & Shell (The business-m Pattern)

If you need a custom brand, sidebar, or global navigation (like business-m), you override the host shell.

  • Backend: Register a framework_m.shell entry point.
  • Frontend: Create a standalone React application that provides the shell.
# business-m: pyproject.toml
[project.entry-points."framework_m.shell"]
business_m = "business_m.frontend:shell"

The framework will now serve the static/ content from business-m as the main entry point (/desk/) instead of the default Desk.

3. Progressive MFE Scaffolding

As the suite grows, individual modules (wms, finance) can be scaffolded to contribute to the business-m shell without being part of the same repository.

  • Action: Use m new:app --with-frontend for each plugin.
  • Scaffolding: This creates a "Universal" structure:
    • src/plugin.config.ts: Defines routes, menus, and components contributed to the shell.
    • vite.config.mfe.ts: Configures the app to build as a Module Federation remote.

Pattern Replicated: Backend to Frontend

The relationship in the UI mirrors the backend exactly:

LayerBackend PatternUI Pattern
Hostbusiness-m (litestar app + shell EP)Main React App (MFE Host)
Pluginwms (DocTypes + frontend EP)MFE Remote (Federated into Host)

4. Discovery & Composition

The "Glue" is the discovery API. The host shell (e.g., business-m) does not hardcode its plugins. On load, it calls:

GET /api/v1/frontend/remotes

The framework scans for all framework_m.frontend entry points (from wms, finance, etc.) and tells the shell where to find their remoteEntry.js.

CI/CD Pattern for App Developers

To ensure your MFE remotes are built correctly and compatible with the host, use the following CI/CD pattern in your application repository.

Template: build-mfe-assets (GitLab CI)

build-mfe-assets:
stage: build
image: node:20 # Use appropriate node version
script:
- cd frontend
- pnpm install
- pnpm build:mfe
artifacts:
paths:
- src/{{app_name}}/static/mfe/
expire_in: 1 week

verify-mfe-remote:
stage: test
needs: [build-mfe-assets]
script:
- pip install framework-m-studio # Install CLI
- m verify:mfe {{app_name}} --path src/{{app_name}}/static/mfe/

Building the Wheel

When building your Python wheel, ensure the static/mfe directory is included. Using hatchling (default):

# pyproject.toml
[tool.hatch.build.targets.wheel.force-include]
"src/{{app_name}}/static/mfe" = "{{app_name}}/static/mfe"

This pattern ensures that your app can be served via the Level 3 (PyPI) deployment method immediately upon installation, while still being ready for Level 5 (CDN) by syncing the static/mfe directory to your CDN.