- Overview
- Prerequisites
- Installing & getting started
- How to import a remote module and use it
- How to inject the remote module store slices into the current store
- Available scripts
- Uses module federation plugin from webpack to inject remote modules.
- This app is the host of Micro frontend inner app
Note: This app uses live reloading for local development.
- nodeJS > 14.X.X or Docker
- Clone repo =>
git clone git@github.com:react-custom-projects/webpack-react-boilerplate.git
- Navigate to project directory
cd webpack-react-boilerplate
- Install dependencies =>
yarn install
- Start the development server =>
yarn start
- Clone repo =>
git clone git@github.com:react-custom-projects/webpack-react-boilerplate.git
- Navigate to project directory
cd webpack-react-boilerplate
- Install dependencies (required for prettier) =>
yarn install
- Start the development server =>
docker-compose up web-dev
- Update the production section of the Dockerfile to meet your needs
- Run the following command to build your image =>
docker-compose up web-prod
-
Open webpack.common.js file.
1- Import ModuleFederationPlugin:const { ModuleFederationPlugin } = require('webpack').container
2- Pass ModuleFederationPlugin to the plugins array:
new ModuleFederationPlugin({
3- Specify the name of the current app 678 in ModuleFederationPlugin:
name: 'app_container',
4- Add the link of the remote module in
remotes object
of the ModuleFederationPlugin, example:new ModuleFederationPlugin({ remotes: { inner_app: `inner_app@${isDevelopment ? remoteDevUrl : remoteProdUrl}/remoteEntry.js`, },
Notes:
- You must use the name of the remote module that you specified in the remote module webpack setup.
- You can add as many remote modules as you like by adding them to the
remotes object
- /buildTools/constants contains remoteDevUrl and remoteProdUrl of the remote module.
5- Add the shared dependencies in ModuleFederationPlugin:
new ModuleFederationPlugin({ shared: ['react', 'react-dom'], }),
6- Install external-remotes-plugin and add it below ModuleFederationPlugin in the plugins array:
//used to make sure that remote modules are loaded before the main bundle new ExternalTemplateRemotesPlugin(),
-
Import the remote module lazily in the required place, example:
const RemoteApp = lazy(() => import('inner_app/App'));
-
Use it inside ErrorBoundary component:
<ErrorBoundary FallbackComponent={RemoteEntryErrorBoundaryFallback} onReset={() => { //Reset the state of your app so the error doesn't happen again console.log('Try again clicked'); }} > <Suspense fallback={ <div className="loader-wrapper"> <LoadingIcon /> </div> } > <RemoteApp /> </Suspense> </ErrorBoundary>
-
Install
redux-dynamic-middlewares
package if the remote module has middle wares. -
Open
/src/js/store/store.js
file:1- Import
dynamicMiddlewares
fromredux-dynamic-middlewares
package:import dynamicMiddlewares from 'redux-dynamic-middlewares'
2- Import
configureStore
:import { configureStore } from '@reduxjs/toolkit';
3- Import your redux slices:
import { reducerSlices } from './reducerSlices';
4- Create your redux store and pass to it dynamicMiddlewares:
export default configureStore({ reducer: reducerSlices, devTools: isDevelopment, middleware: (getDefaultMiddleware) => { if (isDevelopment) { const { logger } = require('redux-logger'), middlewares = [logger, dynamicMiddlewares]; return getDefaultMiddleware().concat(middlewares); } return getDefaultMiddleware(); }, });
5- Add createReducer function:
//used to merge dynamic reducer slices into static reducer slices export const createReducer = (asyncReducers) => combineReducers({ ...reducerSlices, ...asyncReducers, });
-
Open the component in which you want to use the imported module:
1- Import
addMiddleware
fromredux-dynamic-middlewares
package:import { addMiddleware } from 'redux-dynamic-middlewares';
2- Import current app store and createReducer function:
import store, { createReducer } from '@/js/store/store';
3- Import the
remote module
lazily:const RemoteApp = lazy(() => import('inner_app/App'));
2- Create injectMiddleWares function in the component:
const injectMiddleWares = (middleWares) => { middleWares.forEach((el) => addMiddleware(el)); };
3- Create injectSlices function in the component:
const injectSlices = (asyncReducerSlices) => { let asyncReducers = {}; Object.entries(asyncReducerSlices).forEach((el) => (asyncReducers[el[0]] = el[1])); store.replaceReducer(createReducer(asyncReducers)); };
4- Pass
store
,injectSlices
andinjectMiddleWares
to theremote module
:<RemoteApp injectMiddleWares={injectMiddleWares} store={store} injectSlices={injectSlices} />
In the project directory, you can run:
Runs the app in the development mode.
It will open http://localhost:3000 automatically in the browser to see your app.
All changes will be injected automatically without reloading the page.
You will see in the console the following:
- All redux store related changes
- Any of the following errors:
- Linting errors.
- Code format errors (because of prettier)
Builds the app for production to the dist
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
Serves the app on http://localhost:8080 from the dist
folder to check the production version.
Note: Use this script only if you ran the build script yarn build
.
It allows you to analyze the bundle size.