<!DOCTYPE html>
Complete Module Federation Example with Rspack
Complete Module Federation Example with Rspack
Introduction
Module Federation is a revolutionary feature introduced in Webpack 5 that allows you to share code between different applications and build microservices-based front-end architectures. Rspack, a high-performance JavaScript bundler developed by Alibaba, offers excellent support for Module Federation. In this comprehensive guide, we'll explore how to leverage Module Federation with Rspack to build modular and scalable web applications.
Understanding Module Federation
Imagine having multiple independent front-end applications, each with its own codebase and dependencies. Module Federation enables you to seamlessly share components, functions, and even entire modules between these applications. This allows for:
-
Code Reuse:
Eliminate duplicate code and maintain a single source of truth for shared components. -
Improved Scalability:
Break down large applications into smaller, more manageable modules. -
Enhanced Development Speed:
Enable parallel development and deployment of different modules. -
Dynamic Loading:
Load only the necessary modules at runtime, improving application performance.
Setting Up the Project
We'll demonstrate Module Federation with Rspack using a simple example of two applications:
-
Shell Application:
The main application that hosts and loads modules from other applications. -
Remote Application:
The application providing the shared modules.
- Project Initialization
Start by creating two new directories: "shell" and "remote." Inside each directory, initialize an npm project:
mkdir shell remote
cd shell && npm init -y
cd ../remote && npm init -y
Install the necessary dependencies for both applications:
# In shell/
npm install rspack react react-dom
# In remote/
npm install rspack react react-dom
- Create Basic React Components
Create two simple React components:
- Header Component (shared):
// remote/src/Header.js
import React from 'react';
const Header = () => (
Welcome to Our Application
);
export default Header;
-
Content Component (specific to the shell application):
// shell/src/Content.js
import React from 'react';
const Content = () => (
This is the content section of the shell application.
);
export default Content;
Configuring Rspack for Module Federation
- Shell Application Configuration
Modify the "rspack.config.js" file in the "shell" directory:
// shell/rspack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
experiments: {
outputModule: true,
moduleFederation: {
name: 'shellApp',
remotes: {
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true, requiredVersion: false },
'react-dom': { singleton: true, requiredVersion: false },
},
},
},
resolve: {
fallback: {
fs: false,
net: false,
tls: false,
http: false,
https: false,
stream: false,
crypto: false,
zlib: false,
buffer: false,
path: false,
},
},
};
Explanation:
-
: Enables outputting modules in the bundle, necessary for Module Federation.
outputModule: true
-
:
moduleFederation
-
: Unique identifier for the shell application (e.g., "shellApp").
name
-
: Specifies the remote applications and their access points (URLs).
remotes
-
: Defines the remote application name ("remoteApp") and its entry point ("remoteEntry.js").
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
-
-
: Defines the shared dependencies between the shell and remote applications.
shared
-
and
react
: Specify shared dependencies, ensuring both applications use the same versions.
react-dom
-
-
- Remote Application Configuration
Modify the "rspack.config.js" file in the "remote" directory:
// remote/rspack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'remoteEntry.js',
library: {
type: 'var',
name: 'remoteApp',
},
publicPath: 'auto',
},
experiments: {
outputModule: true,
moduleFederation: {
name: 'remoteApp',
exposes: {
'./Header': './src/Header',
},
shared: {
react: { singleton: true, requiredVersion: false },
'react-dom': { singleton: true, requiredVersion: false },
},
},
},
resolve: {
fallback: {
fs: false,
net: false,
tls: false,
http: false,
https: false,
stream: false,
crypto: false,
zlib: false,
buffer: false,
path: false,
},
},
};
Explanation:
-
: Specifies the library name ("remoteApp") and its type ("var"). This determines how the module will be exposed.
output.library
-
:
moduleFederation
-
: Unique identifier for the remote application (e.g., "remoteApp").
name
-
: Defines the modules to be shared with other applications.
exposes
-
: Exposes the "Header" component from the "src/Header.js" file.
'./Header': './src/Header'
-
-
: Similar to the shell application, defines shared dependencies.
shared
-
Building and Running the Applications
Now that we've configured both applications for Module Federation, let's build and run them:
- Build the Remote Application
cd remote
rspack build
rspack serve --port 3001
cd ../shell
rspack build
rspack serve
Open your browser and navigate to "http://localhost:8080". You should see the shell application running with the "Header" component dynamically loaded from the remote application.
Code Walkthrough
Shell Application (index.js)
// shell/src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import Content from './Content';
// Import the shared Header component from the remote application
const remoteHeader = import('remoteApp/Header');
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
{/* Dynamically load the Header component */}
Loading Header...}>
{remoteHeader.then(Header => )}
<content></content>
</react.strictmode>
);
In the shell application, we use the
import('remoteApp/Header')
syntax to dynamically load the "Header" component from the remote application. The
Suspense
component provides a loading indicator while the remote module is being fetched.
Conclusion
Module Federation with Rspack provides a powerful and efficient way to build modular and scalable front-end applications. By leveraging shared dependencies and dynamically loading modules, you can enhance development speed, improve code reuse, and create more flexible and maintainable architectures.
Best Practices
-
Maintain clear naming conventions
for remote applications and exposed modules. -
Consider using a centralized module registry
for managing remote applications and their versions. -
Implement proper error handling
for failed module loads. -
Optimize module sizes
to minimize loading times.
This guide has provided a comprehensive introduction to Module Federation with Rspack. As you explore more complex applications, you can experiment with advanced features like dynamic module loading, nested remote applications, and custom configurations.