C3 AI Documentation Home

Module Federation in SDL

Module federation refers to separating code in modules that are independent but can also work together.

In C3's SDL UI Applications each C3 application package creates a federated module that exposes types, component metadata and tests independently from their dependency packages.

We chose this architecture for a variety of reasons:

  1. Packages can be bundled without all their dependencies. C3 application packages depend on other packages but their UI components may not require that code to be processed at the same time.
  2. Code can be shared between modules. If two packages use the same libraries, only one copy will be sent to the browser.
  3. Component metadata can be overwritten. The host package can always override a component from a dependency package to enhance it or adjust it to the needs of the host applications. Example: Changing a navigation menu.
  4. External applications, even ones using other rendering frameworks, can be embedded in SDL as long as they use Webpack and get externalized as federated modules too.
  5. SDL applications can be embedded in other applications that are bundled with Webpack.

How are packages bundled into federated modules?

All metadata is processed by Webpack and generated in multiple federated modules per package that include types, component instances and tests.

We automatically configure those packages to generate a remote entry file at /c3/MODULE_NAME/remoteEntry.js that can be loaded at runtime by the host application to dynamically import any of the exposed values.

Importing from federated modules

Our UI infrastructure code manages the imports for you but if you need to write your own host you'll have to load the remoteEntry.js file and retrieve the exposed value from the module.

Remember that each package creates multiple federated modules for itself, so you need to load the remoteEntry for the package that directly contains the type or value you want and to aid that process, we expose some files that contain the name of the federated module that contains a given type, component or test.

@c3/ui/typeToFederatedModuleMapping.ts @c3/ui/typeDataSpecsToFederatedModuleMapping.ts @c3/ui/testToFederatedModuleMapping.ts

If you already know which module to load from, you can follow an approach similar to the following code:

JavaScript
/* First load /c3/MODULE_NAME/remoteEntry.js, you can do it as an html `script`
 * tag or programmatically.
 */
...
// Then get the ES Module for your type, component instance, or test
let ModuleFactory = await window[MODULE_NAME].get('types/MyType');
// or
    ModuleFactory = await window[MODULE_NAME].get('components/MyComponent');
// or
    ModuleFactory = await window[MODULE_NAME].get('epics/MyEpic');
// or
    ModuleFactory = await window[MODULE_NAME].get('tests/test_MyComponent.tsx');

const Module = ModuleFactory();

// If type is exported as default:
const MyType = Module.default;
// Or if you are getting a named export, like for UiSdlEpic types:
const epic = Module.epic

Hosting SDL Components

For an example on how to load SDL components and render them in other applications, you can take a look at UiSdlFederatedComponent in uiStandardDesignLanguage and UiSdlFederatedComponent in the uiSdlReact package, it is a React component that can load an SDL component even when used in a React application that is not SDL.

In that case, we are allowing our legacy UI Framework that is not using Webpack to load pages from the new Webpack-based SDL framework.

For convenience, we also provide the UiSdlFederatedSite type as a drop-in replacement for UiSiteContainer. If you are migrating parts of an application to use the new Webpack-based SDL component library, UiFederatedSite will allow you to render a standalone route and its corresponding page inside a legacy application.

Types dynamically importing from federated modules

Some types employ module federation features to dynamically import components at runtime, for example:

  • UiRouterReact.tsx - Our router renderer needs to find the proper component depending on the visited url.

  • UiNestedComponentReact.tsx - Imports other components based on a component ID.

  • SpecHelper.ts - Imports Types and components to allow creating spies for their methods.

  • epicRegistry.ts - Imports UiSdlEpic Types dynamically as needed.

  • test.tsx - Imports the test file matching the file query parameter.

Was this page helpful?