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

Integrating the Feature Hub

The @feature-hub/core package provides the following two major building blocks:

  • The FeatureServiceRegistry — A class for providing Feature Services to dependent consumers.
  • The FeatureAppManager — A class for managing the lifecycle of Feature Apps.

There are a few steps the integrator needs to follow to compose a web page of multiple Feature Apps that share state through Feature Services:

  1. Instantiate a FeatureServiceRegistry singleton instance.
  2. Register a set of Feature Services at the FeatureServiceRegistry.
  3. Instantiate a FeatureAppManager singleton instance using the FeatureServiceRegistry.
  4. Place Feature Apps on a web page, e.g. using React.

To simplify the first three steps, an integrator can use the createFeatureHub function that is also provided by the @feature-hub/core package:

import {createFeatureHub} from '@feature-hub/core';
import {someFeatureServiceDefinition1} from './some-feature-service-1';
import {someFeatureServiceDefinition2} from './some-feature-service-2';
const {featureAppManager, featureServiceRegistry} = createFeatureHub(
  'acme:integrator',
  {
    featureServiceDefinitions: [
      someFeatureServiceDefinition1,
      someFeatureServiceDefinition2,
    ],
  },
);

This creates the FeatureServiceRegistry singleton instance, registers all featureServiceDefinitions for the given integrator ID ('acme:integrator'), and instantiates a FeatureAppManager singleton instance using the FeatureServiceRegistry. Both singletons are returned as properties of the FeatureHub object created using the createFeatureHub function.

Note:
The integrator needs a self-selected but unique consumer ID to register or consume Feature Services (in the example above it is 'acme:integrator'). The featureServiceDefinitions are automatically sorted topologically before being registered, and therefore do not need to be passed in the correct order.

Choosing an Integrator Technology

The Feature Hub allows for different technology choices for the integrator as well as for Feature Apps supported by the integrator. While it is possible to build a custom solution tailored to the UI frameworks or libraries of choice using the primitives provided by the @feature-hub/core package, the @feature-hub/react and @feature-hub/dom package provide out-of-the-box solutions for building an integrator.

The @feature-hub/dom package uses Web Components as a basis. It wraps Feature Apps into a shadow DOM and doesn't rely on the presence of any big frontend frameworks, which makes it possible to build integrators that are lean in bundle size. Feature Apps can be build using any technology since they just have to render themselves into a provided DOM element.

The @feature-hub/react package on the other hand allows for building an integrator using React. It has the capability to render Feature Apps which are also build using React on the server as well as on the client, while it can still integrate Feature Apps that are built using other technologies on the client.

@feature-hub/react@feature-hub/dom
Feature App TypeReactFeatureAppDomFeatureAppDomFeatureApp
Universal SSR✅❌❌
Built-In Shadow DOM❌❌✅
Required Integrator UI Libraryreact@^16.3.0react@^16.3.0✅ None
Supported Feature App UI Librariesreact@^16.3.0✅ Any✅ Any

Module Loader

For the FeatureAppManager to be able to load Feature Apps from a remote location, it needs to be configured with an implementation of the ModuleLoader interface of the @feature-hub/core package by the integrator (e.g. the @feature-hub/module-loader-amd package, the @feature-hub/module-loader-federation, the @feature-hub/module-loader-commonjs package, or a custom loader).

The module loader can be provided with the moduleLoader option of the createFeatureHub function.

Client

AMD Module Loader

import {loadAmdModule} from '@feature-hub/module-loader-amd';
const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: loadAmdModule,
});

Webpack Module Federation Loader

import {loadFederatedModule} from '@feature-hub/module-loader-federation';
const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: loadFederatedModule,
});

Server

import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: loadCommonJsModule,
});

Custom Module Loader

The integrator can also provide a custom module loader that can handle multiple module types:

import {loadAmdModule} from '@feature-hub/module-loader-amd';
import {loadFederatedModule} from '@feature-hub/module-loader-federation';
const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: (url, moduleType) =>
    moduleType === 'federated' ? loadFederatedModule(url) : loadAmdModule(url),
});

In this example AMD is regarded as the default module type. If a Feature App uses a different module type than the default, it must be specified as the moduleType prop of the FeatureAppLoader, matching the usage in the custom module loader.

Note:
Specifying the module type of a Feature App module is currently only supported by the React Feature App Loader.

Validating Externals

When using a module loader, it might make sense to validate external dependencies that are required by Feature Apps against the externals, e.g. shared npm dependencies, that are provided by the integrator. This makes it possible that an error is already thrown when creating a Feature App with incompatible external dependencies, and thus enables early feedback as to whether a Feature App is compatible with the integration environment.

To accomplish that, the integrator can pass the providedExternals option to the createFeatureHub function.

On the client:

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,
  providedExternals: {react: '16.7.0'},
});

On the server:

import {createFeatureHub} from '@feature-hub/core';
import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
const {featureAppManager} = createFeatureHub('acme:integrator', {
  moduleLoader: loadCommonJsModule,
  providedExternals: {react: '16.7.0'},
});

When the providedExternals option is passed to the createFeatureHub function, an ExternalsValidator is instantiated and passed to the FeatureAppManager which uses it to validate the external dependencies of a Feature App before creating it.

The same ExternalsValidator instance is also passed to the FeatureServiceRegistry to validate the external dependencies of Feature Services that are provided by Feature Apps which are loaded from a remote location, instead of being provided by the integrator.

Placing Feature Apps on a Web Page Using React

An integrator can use the FeatureAppLoader or the FeatureAppContainer (both from the @feature-hub/react package) to place Feature Apps on a web page that have been implemented using React. Each of them access the FeatureAppManager singleton instance through React context. To provide the context, the integrator must render a FeatureHubContextProvider:

import {FeatureHubContextProvider} from '@feature-hub/react';
<FeatureHubContextProvider value={{featureAppManager}}>
  {/* render Feature Apps here */}
</FeatureHubContextProvider>

React Feature App Loader

The FeatureAppLoader component allows the integrator to load Feature Apps from a remote location. It has two required props: featureAppId and src.

featureAppId

The Feature App ID is required to identify the Feature App instance. Multiple Feature App Loaders with the same featureAppId will render the same Feature app instance. The ID is also used as a consumer ID for dependent Feature Services. To render multiple instances of the same kind of Feature App, different IDs must be used:

<section>
  <div>
    <FeatureAppLoader
      featureAppId="some-feature-app:main"
      src="https://example.com/some-feature-app.js"
    />
  </div>
  <aside>
    <FeatureAppLoader
      featureAppId="some-feature-app:aside"
      src="https://example.com/some-feature-app.js"
    />
  </aside>
</section>

src

A Feature App can be loaded and integrated by defining a src which is the URL of its client module bundle:

import {FeatureAppLoader} from '@feature-hub/react';
<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
/>

Note:
If the integrator has configured the AMD module loader on the client, the Feature App to be loaded via src must be provided as an AMD module.

moduleType

The module type of the Feature App's client module bundle. It is passed to the module loader that was provided by the integrator. It can be omited if the provided module loader can only handle a single module type, or if it handles a default module type (see Custom Module Loader).

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-federated-feature-app.js"
  moduleType="federated"
/>

serverSrc

Additionally, when a Feature App needs to be rendered on the server, its serverSrc must be specified, which is the URL of its server module bundle:

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
  serverSrc="https://example.com/some-feature-app-node.js"
/>

Notes:

  • If the integrator has configured the CommonJS module loader on the server, the Feature App to be loaded via serverSrc must be provided as a CommonJS module.
  • If baseUrl is specified as well, it will be prepended if serverSrc is a relative URL. In this case baseUrl must be an absolute URL.

serverModuleType

The module type of the Feature App's server module. It is passed to the module loader that was provided by the integrator. It can be omited if the provided module loader can only handle a single module type, or if it handles a default module type (see Custom Module Loader).

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
  serverSrc="https://example.com/some-feature-app-node.mjs"
  serverModuleType="esm"
/>

css

You can also define a css prop to add stylesheets to the document:

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
  css={[
    {href: 'https://example.com/some-feature-app.css'},
    {href: 'https://example.com/some-feature-app-print.css', media: 'print'},
  ]}
/>

baseUrl

Optionally, a relative or absolute baseUrl can be specified for two purposes:

  1. as a common base URL for relative src, serverSrc, and css hrefs
  2. to provide the Feature App with a base URL with which it can refer to its own resources
<FeatureAppLoader
  featureAppId="some-feature-app"
  baseUrl="https://example.com/some-feature-app"
  src="main.js"
  serverSrc="main-node.js"
  css={[{href: 'styles.css'}]}
/>

Note:
Only relative URLs are prepended with the baseUrl. Absolute URLs are used unchanged.

config

With the config prop, a config object for a specific Feature App instance can be provided:

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
  config={{someConfig: 'foo'}}
/>

For more details please refer to the the "Feature App Configs" section.

featureAppName

The featureAppName is used as a consumer name for dependent Feature Services that can use it for display purposes, logging, looking up Feature App configuration meta data, etc. In contrast to the featureAppId, the featureAppName must not be unique, e.g.:

<section>
  <div>
    <FeatureAppLoader
      featureAppId="some-feature-app:main"
      featureAppName="some-feature-app"
      src="https://example.com/some-feature-app.js"
    />
  </div>
  <aside>
    <FeatureAppLoader
      featureAppId="some-feature-app:aside"
      featureAppName="some-feature-app"
      src="https://example.com/some-feature-app.js"
    />
  </aside>
</section>

done

For a short-lived Feature App a done callback can be defined, which the Feature App can call when it has completed its task. For example, if the Feature App was opened in a layer, the layer could be closed when done() is called.

function FeatureAppInALayerExample() {
  const [isOpen, setIsOpen] = React.useState(false);

  return (
    <div>
      {isOpen && (
        <Layer>
          <FeatureAppLoader
            featureAppId="some-feature-app"
            src="https://example.com/some-feature-app.js"
            done={() => setIsOpen(false)}
          />
        </Layer>
      )}
      <button onClick={() => setIsOpen(true)}>Open</button>
    </div>
  );
}

children

One can pass a rendering function as the React Children (i.e. the children prop) that allows custom rendering of the Feature App during loading and error states.

For more details please refer to the the "Custom Loading and Error UI" section.

React Feature App Container

The FeatureAppContainer component allows the integrator to bundle Feature Apps instead of loading them from a remote location. It has two required props: featureAppId and featureAppDefinition.

featureAppDefinition

A Feature App can be integrated by directly providing its featureAppDefinition:

import {FeatureAppContainer} from '@feature-hub/react';
import {someFeatureAppDefinition} from './some-feature-app';
<FeatureAppContainer
  featureAppId="some-feature-app"
  featureAppDefinition={someFeatureAppDefinition}
/>

featureAppId

The Feature App ID is required to identify the Feature App instance. Multiple Feature App Containers with the same featureAppId will render the same Feature app instance. The ID is also used as a consumer ID for dependent Feature Services. To render multiple instances of the same kind of Feature App, different IDs must be used:

<section>
  <div>
    <FeatureAppContainer
      featureAppId="some-feature-app:main"
      featureAppDefinition={someFeatureAppDefinition}
    />
  </div>
  <aside>
    <FeatureAppContainer
      featureAppId="some-feature-app:aside"
      featureAppDefinition={someFeatureAppDefinition}
    />
  </aside>
</section>

baseUrl

Optionally, a baseUrl can be specified to provide the Feature App with a base URL that it can use to reference its own resources:

<FeatureAppContainer
  featureAppId="some-feature-app"
  featureAppDefinition={someFeatureAppDefinition}
  baseUrl="https://example.com/some-feature-app"
/>

config

With the config prop, a config object for a specific Feature App instance can be provided:

<FeatureAppContainer
  featureAppId="some-feature-app"
  featureAppDefinition={someFeatureAppDefinition}
  config={{someConfig: 'foo'}}
/>

For more details please refer to the the "Feature App Configs" section.

featureAppName

The featureAppName is used as a consumer name for dependent Feature Services that can use it for display purposes, logging, looking up Feature App configuration meta data, etc. In contrast to the featureAppId, the featureAppName must not be unique, e.g.:

<section>
  <div>
    <FeatureAppContainer
      featureAppId="some-feature-app:main"
      featureAppName="some-feature-app"
      featureAppDefinition={someFeatureAppDefinition}
    />
  </div>
  <aside>
    <FeatureAppContainer
      featureAppId="some-feature-app:aside"
      featureAppName="some-feature-app"
      featureAppDefinition={someFeatureAppDefinition}
    />
  </aside>
</section>

done

For a short-lived Feature App a done callback can be defined, which the Feature App can call when it has completed its task. For example, if the Feature App was opened in a layer, the layer could be closed when done() is called.

function FeatureAppInALayerExample() {
  const [isOpen, setIsOpen] = React.useState(false);

  return (
    <div>
      {isOpen && (
        <Layer>
          <FeatureAppContainer
            featureAppId="some-feature-app"
            featureAppDefinition={someFeatureAppDefinition}
            done={() => setIsOpen(false)}
          />
        </Layer>
      )}
      <button onClick={() => setIsOpen(true)}>Open</button>
    </div>
  );
}

children

One can pass a rendering function as the React Children (i.e. the children prop) that allows custom rendering of the Feature App during loading and error states.

For more details please refer to the the "Custom Loading and Error UI" section.

Error Handling

When a Feature App throws an error while rendering or, in the case of a ReactFeatureApp, throws an error in a lifecycle method, the FeatureAppContainer and FeatureAppLoader render null. On the server, however, rendering errors are not caught and must therefore be handled by the integrator.

Custom Loading and Error UI

An integrator can customize the rendering of Loading states and Errors, using the children "render prop" in FeatureAppContainer or FeatureAppLoader.

The children prop is a function that receives parameters in form of an object and returns rendered React children (a React Node).

Please look at the API reference, to learn more about the passed params:

  • error
  • loading
  • featureAppNode

This API allows full control over the rendering output, and must therefore abide a set of rules that need to be followed carefully:

  • The featureAppNode might be passed and has to be rendered, even when loading=true.
    A Feature App might depend on being rendered, before resolving its loading promise. To not show the Feature App in favour of a loading UI, it must be hidden visually (e.g. via display: none;).
  • The featureAppNode should always be rendered into the same position of the returned tree.
    Otherwise it could occur, that React re-mounts the Feature App, which is resource-expensive and can break DOM Feature Apps.

Custom UI Example

The following example can also be seen with more context in the "React Loading And Error UI" demo.

<FeatureAppContainer
  featureAppId="some-feature-app"
  featureAppDefinition={someFeatureAppDefinition}
>
  {({ error, loading, featureAppNode }) => {
    if (error) {
      return <ErrorUi error={error}>
    }

    return (
      <div>
        <div style={{display: loading ? 'none' : 'initial'}}>
          {featureAppNode}
        </div>
        {loading && <Spinner />}
      </div>
    );
  }}
</FeatureAppContainer>

Placing Feature Apps on a Web Page Using Web Components

An integrator can use the feature-app-loader or the feature-app-container custom elements (both from the @feature-hub/dom package) to place Feature Apps on a web page. Both of them need to be defined by the integrator to make them available:

import {
  defineFeatureAppContainer,
  defineFeatureAppLoader,
} from '@feature-hub/dom';
defineFeatureAppContainer(featureAppManager);
defineFeatureAppLoader(featureAppManager);

feature-app-loader

The feature-app-loader custom element allows the integrator to load Feature Apps from a remote location.

featureAppId

The Feature App ID is required to identify the Feature App instance. Multiple feature-app-loader custom elements with the same featureAppId will render the same Feature app instance. The ID is also used as a consumer ID for dependent Feature Services. To render multiple instances of the same kind of Feature App, different IDs must be used:

<section>
  <div>
    <feature-app-loader
      featureAppId="some-feature-app:main"
      src="https://example.com/some-feature-app.js"
    ></feature-app-loader>
  </div>
  <aside>
    <feature-app-loader
      featureAppId="some-feature-app:aside"
      src="https://example.com/some-feature-app.js"
    ></feature-app-loader>
  </aside>
</section>

src

A Feature App can be loaded and integrated by defining a src attribute which is the URL of its module bundle:

<feature-app-loader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
></feature-app-loader>

Note:
If the integrator has configured the AMD module loader, the Feature App to be loaded via src must be provided as an AMD module.

baseUrl

Optionally, a baseUrl can be specified for two purposes:

  1. as a common base URL for a relative src
  2. to provide the Feature App with a base URL with which it can refer to its own resources
<feature-app-loader
  featureAppId="some-feature-app"
  baseUrl="https://example.com/some-feature-app"
  src="main.js"
></feature-app-loader>

config

With the config property, a config object for a specific Feature App instance can be provided:

const featureAppLoader = document.createElement('feature-app-loader');

featureAppLoader.setAttribute('featureAppId', 'some-feature-app');
featureAppLoader.setAttribute('src', 'https://example.com/some-feature-app.js');
featureAppLoader.config = {someConfig: 'foo'};

document.querySelector('#app').appendChild(featureAppLoader);

For more details please refer to the the "Feature App Configs" section.

featureAppName

The featureAppName is used as a consumer name for dependent Feature Services that can use it for display purposes, logging, looking up Feature App configuration meta data, etc. In contrast to the featureAppId, the featureAppName must not be unique, e.g.:

<section>
  <div>
    <feature-app-loader
      featureAppId="some-feature-app:main"
      featureAppName="some-feature-app"
      src="https://example.com/some-feature-app.js"
    ></feature-app-loader>
  </div>
  <aside>
    <feature-app-loader
      featureAppId="some-feature-app:aside"
      featureAppName="some-feature-app"
      src="https://example.com/some-feature-app.js"
    ></feature-app-loader>
  </aside>
</section>

loading Slot

The feature-app-loader custom element renders a slot named loading while the Feature App module is loaded.

<feature-app-loader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
>
  <p slot="loading">Loading...</p>
</feature-app-loader>

error Slot

The feature-app-loader custom element renders a slot named error if the Feature App module could not be loaded. It also passes the slot to the underlying feature-app-container.

<feature-app-loader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
>
  <p slot="error">Sorry, we messed up.</p>
</feature-app-loader>

feature-app-container

The feature-app-container custom element allows the integrator to bundle Feature Apps instead of loading them from a remote location.

featureAppDefinition

A Feature App can be integrated by directly providing its featureAppDefinition:

import {someFeatureAppDefinition} from './some-feature-app';
const featureAppContainer = document.createElement('feature-app-container');

featureAppLoader.setAttribute('featureAppId', 'some-feature-app');
featureAppContainer.featureAppDefinition = someFeatureAppDefinition;

document.querySelector('#app').appendChild(featureAppContainer);

featureAppId

The Feature App ID is required to identify the Feature App instance. Multiple feature-app-loader custom elements with the same featureAppId will render the same Feature app instance. The ID is also used as a consumer ID for dependent Feature Services. To render multiple instances of the same kind of Feature App, different IDs must be used:

const mainFeatureAppContainer = document.createElement('feature-app-container');

mainFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app:main');
mainFeatureAppContainer.featureAppDefinition = someFeatureAppDefinition;

document.querySelector('main').appendChild(mainFeatureAppContainer);

const asideFeatureAppContainer = document.createElement(
  'feature-app-container',
);

asideFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app:aside');
asideFeatureAppContainer.featureAppDefinition = someFeatureAppDefinition;

document.querySelector('aside').appendChild(asideFeatureAppContainer);

baseUrl

Optionally, a baseUrl can be specified to provide the Feature App with a base URL that it can use to reference its own resources:

const featureAppContainer = document.createElement('feature-app-container');

mainFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app');
featureAppContainer.featureAppDefinition = someFeatureAppDefinition;

featureAppContainer.setAttribute(
  'baseUrl',
  'https://example.com/some-feature-app',
);

document.querySelector('#app').appendChild(featureAppContainer);

config

With the config property, a config object for a specific Feature App instance can be provided:

const featureAppContainer = document.createElement('feature-app-container');

mainFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app');
featureAppContainer.featureAppDefinition = someFeatureAppDefinition;
featureAppLoader.config = {someConfig: 'foo'};

document.querySelector('#app').appendChild(featureAppContainer);

For more details please refer to the the "Feature App Configs" section.

featureAppName

The featureAppName is used as a consumer name for dependent Feature Services that can use it for display purposes, logging, looking up Feature App configuration meta data, etc. In contrast to the featureAppId, the featureAppName must not be unique, e.g.:

const mainFeatureAppContainer = document.createElement('feature-app-container');

mainFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app:main');
mainFeatureAppContainer.setAttribute('featureAppName', 'some-feature-app');
mainFeatureAppContainer.featureAppDefinition = someFeatureAppDefinition;

document.querySelector('main').appendChild(mainFeatureAppContainer);

const asideFeatureAppContainer = document.createElement(
  'feature-app-container',
);

asideFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app:aside');
asideFeatureAppContainer.setAttribute('featureAppName', 'some-feature-app');
asideFeatureAppContainer.featureAppDefinition = someFeatureAppDefinition;

document.querySelector('aside').appendChild(asideFeatureAppContainer);

error Slot

The feature-app-container custom element renders a slot named error if the Feature App could not be created or if the Feature App throws in its attachTo method.

const featureAppContainer = document.createElement('feature-app-container');

mainFeatureAppContainer.setAttribute('featureAppId', 'some-feature-app');
featureAppContainer.featureAppDefinition = someFeatureAppDefinition;
featureAppContainer.innerHtml = '<p slot="error">Sorry, we messed up.</p>';

document.querySelector('#app').appendChild(featureAppContainer);

Providing Configs

Feature Service Configs

If a Feature Service must be configurable, it must export a factory function that accepts some options and returns a Feature Service definition, e.g.:

export function defineSomeFeatureService(options = {}) {
  return {
    id: 'acme:some-feature-service',

    create: () => {
      return {
        '1.0.0': () => ({
          featureService: {
            foo() {
              return 42 + options.someConfig;
            },
          },
        }),
      };
    },
  };
}

The integrator can then pass the configuration to the Feature Service when creating the Feature Service definiton for the featureServiceDefinitions option of createFeatureHub (see above).

Feature App Configs

When a Feature App needs a configuration, the config prop can be set on the React FeatureAppLoader, feature-app-loader custom element, React FeatureAppContainer, or the feature-app-container custom element for a given Feature App instance, e.g.:

<FeatureAppLoader
  featureAppId="some-feature-app"
  src="https://example.com/some-feature-app.js"
  config={{someConfig: 'foo'}}
/>

The config will be passed to the Feature App's create method via the env argument:

const someFeatureAppDefinition = {
  create(env) {
    const {someConfig} = env.config; // someConfig is 'foo'

    // ...
  },
};

Note:
The config must be completely static, since it is only evaluated when a Feature App is mounted. Changing the config after a Feature App has been loaded, will have no effect! Therefore, it is not suitable to exchange dynamic state between a Feature App and its outer boundary. In this case a Feature Service should be used instead.

Consuming Feature Services

Just like Feature Apps or Feature Services, the integrator itself can consume its own registered Feature Services. To do this, the integrator needs to pass the featureServiceDependencies option to the createFeatureHub function. This will bind those Feature Services to the integrator and return them as featureServices property of the FeatureHub object created:

import {createFeatureHub} from '@feature-hub/core';
import {someFeatureServiceDefinition1} from './some-feature-service-1';
import {someFeatureServiceDefinition2} from './some-feature-service-2';
const {featureServices} = createFeatureHub('acme:integrator', {
  featureServiceDefinitions: [
    someFeatureServiceDefinition1,
    someFeatureServiceDefinition2,
  ],
  featureServiceDependencies: {
    [someFeatureServiceDefinition2.id]: '^1.0.0',
  },
});

const someFeatureService2 = featureServices[someFeatureServiceDefinition2.id];

someFeatureService2.foo(42);
Last updated on 1/27/2025 by Feature Hub CI
← DemosWriting a Feature App →
  • Choosing an Integrator Technology
  • Module Loader
    • Client
    • Server
    • Custom Module Loader
    • Validating Externals
  • Placing Feature Apps on a Web Page Using React
    • React Feature App Loader
    • React Feature App Container
    • Error Handling
    • Custom Loading and Error UI
  • Placing Feature Apps on a Web Page Using Web Components
    • feature-app-loader
    • feature-app-container
  • Providing Configs
    • Feature Service Configs
    • Feature App Configs
  • Consuming Feature Services
Copyright (c) 2018-2025 Accenture Song Build Germany GmbH