Dynamic Module Loading
The extension architecture leverages Webpack's Module Federation to enable dynamic loading of frontend assets at runtime. This sophisticated mechanism involves several key concepts:
Module Federation allows extensions to be built and deployed independently while sharing dependencies with the host application. Extensions expose their entry points through the federation configuration:
new ModuleFederationPlugin({
name: 'my_extension',
filename: 'remoteEntry.[contenthash].js',
exposes: {
'./index': './src/index.tsx',
},
externalsType: 'window',
externals: {
'@apache-superset/core': 'superset',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
'antd-v5': { singleton: true }
}
})
externals
and externalsType
ensure that extensions use the host's implementation of shared packages rather than bundling their own copies.
shared
dependencies prevent duplication of common libraries like React and Ant Design avoiding version conflicts and reducing bundle size.
This configuration tells Webpack that when the extension imports from @apache-superset/core
, it should resolve to window.superset
at runtime, where the host application provides the actual implementation. The following diagram illustrates how this works in practice:
During extension registration, the host application fetches the remote entry file and dynamically loads the extension's modules without requiring a rebuild or restart of Superset.
On the host application side, the @apache-superset/core
package will be mapped to the corresponding implementations during bootstrap in the setupExtensionsAPI
function.
import * as supersetCore from '@apache-superset/core';
import {
authentication,
core,
commands,
environment,
extensions,
sqlLab,
} from 'src/extensions';
export default function setupExtensionsAPI() {
window.superset = {
...supersetCore,
authentication,
core,
commands,
environment,
extensions,
sqlLab,
};
}