Navigate back to the homepage

Webpack module federation

Pablo Ifrán
November 2nd, 2020 · 3 min read

Intro

Module federation is a new feature that come with webpack 5 and it allows developers to use components from other builds (this might be know as micro-frontend). It could also enable other possibilities like have an isolated team that works on reusable components that can be shared across different projects without paying the price of installing a whole library. In addition if a bug is found on one component that bug could be solved once and all teams that use that component will see the benefit immediately.

Getting Started

Create a project that will hold our example application, to do that just open a terminal and go to the desired path then type the following commands:

1mkdir my-awesome-example
2cd my-awesome-example
3npm init

Answer all the question prompted and then is time to install webpack, the following command could be used for that task:

1npm install --save-dev webpack

or if you are using yarn you can do this

1yarn add webpack --dev

The example is going to based on React but it could be used with any other library or framework. For reference and example you can take a look at the following repository.

In this example we are going to build a component that is going to be used later by another application, so once we have webpack installed we need to install React to do that just type the following commands

1npm install --save react react-dom
2npm install --save-dev @babel/core @babel/preset-react babel-loader bundle-loader \
3 html-webpack-plugin serve webpack-cli webpack-dev-server

Those dev dependencies are used to build the react application, if you are interested in what each of those does take a look at the Additional section at the end of the post

The next step is to replace the scripts on the package.json with the following scripts, those scripts are going to be used to serve the application on development mode, and also create a build that can be used on production.

File: package.json

1{
2 # ... content
3 "scripts": {
4 "start": "webpack-cli serve",
5 "build": "webpack --mode production",
6 "serve": "serve dist -p 3000",
7 "clean": "rm -rf dist"
8 }
9 # ... more content
10}

Configure webpack & build React app

The next thing that we need to do is to configure webpack to serve the application we are going to build. To do that just create a file named webpack.config.js on the root of the project, that file should have the following content

1const HtmlWebpackPlugin = require('html-webpack-plugin')
2const path = require('path')
3
4module.exports = {
5 entry: './src/index',
6 mode: 'development',
7 devServer: {
8 contentBase: path.join(__dirname, 'dist'),
9 port: 3000,
10 },
11 output: {
12 publicPath: 'auto',
13 },
14 module: {
15 rules: [
16 {
17 test: /bootstrap\.js$/,
18 loader: 'bundle-loader',
19 options: {
20 lazy: true,
21 },
22 },
23 {
24 test: /\.jsx?$/,
25 loader: 'babel-loader',
26 exclude: /node_modules/,
27 options: {
28 presets: ['@babel/preset-react'],
29 },
30 },
31 ],
32 },
33 plugins: [
34 new HtmlWebpackPlugin({
35 template: './public/index.html',
36 }),
37 ],
38}

Something interesting to notice is that the bootstrap.js file is going to be loaded with bundle-loader and it’s going to be loaded lazy

1import bootstrap from './bootstrap'
2bootstrap()

Then a file named bootstrap.js needs to be created

1import React from 'react'
2import ReactDOM from 'react-dom'
3import App from './App'
4
5ReactDOM.render(<App />, document.getElementById('root'))

And finally App.js

1import React from 'react'
2
3const App = () => (
4 <div>
5 <h1>Hello from App 1</h1>
6 </div>
7)
8
9export default App

Additionally we need to create the following file public/index.html with this content

1<html>
2 <head> </head>
3 <body>
4 <div id="root"></div>
5 </body>
6</html>

This file is going to be used by webpack to generate the html and inject the different components of the application.

Configure application that will hold our components

So far we have a normal React application, now we are going to configure that application to hold our components and share them with other applications to do that we need to use the new plugin from webpack called ModuleFederationPlugin. Open webpack.config.js and add the following content

1// ... Other content
2const { ModuleFederationPlugin } = require("webpack").container;
3
4module.exports = {
5 // ... webpack config
6 plugins: [
7 new ModuleFederationPlugin({
8 name: "awesome",
9 library: { type: "var", name: "awesome" },
10 filename: "remoteEntry.js",
11 exposes: {
12 "./HomePage": "./src/HomePage",
13 },
14 shared: { react: { singleton: true }, "react-dom": { singleton: true } },
15 }),
16 // ... other plugins
17 ],
18};

This configuration says that we are going to create a shared module that it’s name is ‘awesome’ and that module is going to contain (or expose) a component named HomePage, and react and react-dom are going to be shared by both so there is no need to include that on the build.

Lets create the component that we are going to share, create a file named HomePage.js under the src folder and add the following content to it:

1import React from 'react'
2
3const HomePage = ({ title }) => (
4 <h1>Hello {title}, from awesome</h1>
5)
6
7export default HomePage

Create app that will use shared components

On the same way that we create the app that is going to share the components we need to create the other app that is going to use the shared components (you can also copy the current project folder and use it as an starting point cp -r ../my-awesome-example ../use-my-awesome-example from the project root). If you don’t copy the folder follow the steps from Getting Started until Configure application that will hold our components

Then we need to configure the app to use the components from the other project

Once again lets go to the webpack config and modify or add (modify if you copy the project) the ModuleFederationPlugin under the plugins section like this:

1// ... Other content
2const { ModuleFederationPlugin } = require("webpack").container;
3
4module.exports = {
5 // ... webpack config
6 plugins: [
7 new ModuleFederationPlugin({
8 name: "use-remote-components",
9 remotes: {
10 awesome: "awesome@http://localhost:3002/remoteEntry.js",
11 },
12 shared: { react: { singleton: true }, "react-dom": { singleton: true } },
13 }),
14 // ... other plugins
15 ],
16};

Make sure to start the project on the port 3002 (npm run start -- --port 3002)

Then we need to create a new component on the new application, open src/App.js and add the following content

1import React from 'react'
2
3const RemoteHomePage = React.lazy(() => import("awesome/HomePage"));
4
5const App = () => (
6 <div>
7 <React.Suspense fallback="Loading ...">
8 <RemoteHomePage title="Awesome component" />
9 </React.Suspense>
10 </div>
11)
12
13export default App

Make sure to add the Suspense otherwise the RemoteHomePage is not going to work. Start the project and you will see the component from the awesome app rendered in the app we just created.

Additional

More articles from pablitohub

Deploy using AWS Code Build

Deploy automatically after building your docker image using AWS Code Build

October 11th, 2020 · 1 min read

AWS Code Build

Build docker images automatically in AWS using code build

September 29th, 2020 · 2 min read
© 2020 pablitohub
Link to $https://twitter.com/elneopicLink to $https://github.com/elpicLink to $https://www.linkedin.com/in/pabloifran