Feature Hub

Feature Hub

  • API
  • GitHub

›Guides

Getting Started

  • Introduction
  • Motivation
  • Demos

Guides

  • Integrating the Feature Hub
  • Writing a Feature App
  • Writing a Feature Service
  • Sharing the Browser History
  • Sharing npm Dependencies
  • Custom Logging
  • Server-Side Rendering
  • Feature App in Feature App
  • Reducing the Bundle Size

Help

  • FAQ
Edit

Sharing npm Dependencies

The integrator might want to share commonly used libraries with Feature Apps for two reasons.

  1. Reduce the bundle size of the Feature Apps by omitting shared dependencies from their bundle.
  2. Ensure that a library that can only exist once on a page is provided as a singleton.

How dependencies are shared depends on the provided module loaders of the integrator.

AMD

The feature described in this section is also demonstrated in the "AMD Module Loader" demo.

Integrator

When using the @feature-hub/module-loader-amd package, the integrator can provide shared npm dependencies to Feature Apps using the defineExternals function:

import {createFeatureHub} from '@feature-hub/core';
import {defineExternals, loadAmdModule} from '@feature-hub/module-loader-amd';
import * as React from 'react';
defineExternals({react: React});

const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: loadAmdModule,
});

Feature Apps

Feature Apps should define these externals in their build config. For example, defining react as external in a Webpack config would look like this:

module.exports = {
  // ...
  externals: {
    react: 'react',
  },
};

Webpack Module Federation

The feature described in this section is also demonstrated in the "Webpack Module Federation Loader" demo.

Integrator

When using the @feature-hub/module-loader-federation package, the integrator's client module must be bundled with Webpack. The integrator can share npm dependencies to Feature Apps using the shared property of its ModuleFederationPlugin:

module.exports = {
  // ...
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      shared: {
        react: {singleton: true, eager: true},
      },
    }),
  ],
};

If the integrator wants to provide a shared module:

  • It must be eager if the integrator itself consumes it synchronously.
  • It does not need to be eager if the integrator consumes it asynchronously (dynamic import).
  • It must be a singleton if the module is stateful.
  • It must be a singleton if the module can not exist more than once on a page.

There is no need for the integrator to share a module that it does not consume itself. In this case, those Feature Apps that need it can provide the shared module instead (see below).

Feature Apps

If Feature Apps want to use shared dependencies, they must define them in the shared property of their ModuleFederationPlugin.

module.exports = {
  // ...
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      // ...
      shared: {
        react: {singleton: true},
      },
    }),
  ],
};

A dependency that the integrator has provided as singleton must also be a singleton in the Feature App's Webpack config. But here, it should not be eager, otherwise it will always be loaded, regardless of whether the integrator has already provided it. Version mismatches of singletons are generally ignored, and a warning is logged, unless strictVersion is set to true, in which case a runtime error is thrown.

The biggest benefit of using the Module Federation Loader over the AMD Module Loader (or in addition), is that Feature Apps can also share npm dependencies with each other, without the need to involve the integrator.

module.exports = {
  // ...
  plugins: [
    new webpack.container.ModuleFederationPlugin({
      // ...
      shared: {
        '@apollo/client': {},
      },
    }),
  ],
};

If a Feature App wants to provide a shared module, it should not be eager. In case of a version mismatch (defined by the semver ranges in the package.json files of the Feature Apps) the module is loaded multiple times, and available to other Feature Apps in each loaded version.

Note:
A large library of which only a small portion is used, might not be a good candidate to provide as a shared module. In this case it might be more efficient to include the library in each Feature App bundle, while making use of Webpack's tree shaking capabilities. Furthermore, the loading of a library can also be deferred by using dynamic code splitting.

CommonJS

The feature described in this section is also demonstrated in the "CommonJS Module Loader" demo.

Integrator

On the server, when Feature Apps are bundled as CommonJS modules, the integrator either

  1. needs to make sure that the externals are provided as node modules that can be loaded with require(), or

  2. if the integrator code is bundled and no node modules are available during runtime, the integrator can provide shared npm dependencies to Feature Apps using the createCommonJsModuleLoader function of the @feature-hub/module-loader-commonjs package:

    import {createFeatureHub} from '@feature-hub/core';
    import {createCommonJsModuleLoader} from '@feature-hub/module-loader-commonjs';
    import * as React from 'react';
    
    const {featureAppManager} = createFeatureHub('acme:integrator', {
      moduleLoader: createCommonJsModuleLoader({react: React}),
    });
    

Feature Apps

Feature Apps should define these externals in their build config. For example, defining react as external in a Webpack config would look like this:

module.exports = {
  // ...
  externals: {
    react: 'react',
  },
};

Validating Externals

To validate the external dependencies that are required by Feature Apps against the shared npm dependencies that are provided by the integrator, the ExternalsValidator can be used.

Last updated on 1/27/2025 by Feature Hub CI
← Sharing the Browser HistoryCustom Logging →
  • AMD
    • Integrator
    • Feature Apps
  • Webpack Module Federation
    • Integrator
    • Feature Apps
  • CommonJS
    • Integrator
    • Feature Apps
  • Validating Externals
Copyright (c) 2018-2025 Accenture Song Build Germany GmbH