In this tutorial, you’ll learn the steps to create a micro frontend application leveraging the capabilities of Vite, Bit, and the modern browser.
Our Micro Frontend applications (MFEs) and their shared dependencies will be bundled into ES Modules.
In development, our MFEs and shared dependencies will be loaded from our local workspace. This allows us to develop and test the MFEs locally without having to deploy them.
In production, our MFEs will be loaded (in runtime) from their remote entry point according to the import map in the host app’s index.html. For example:
{
“imports“: {
“react“: “https://esm.sh/react@18.2.0“,
“@learnbit/react-es-mfe.my-mfe“: “https://bit-react-esm-mfe.netlify.app/v0.0.1.js“
}
}
</script>
Our micro frontend solution will consist of three Bit components:
A micro frontend: An app bundled as an ESM library that can be imported and rendered by the host app (at runtime).
A remote module list: A list of shared modules and micro frontends consumed at runtime by our host app and micro frontend.
A host app: A container application that imports and renders the micro frontends.
The dependency graph of our solution. The host application and the micro frontend both share the list of remote modules (to be excluded from their bundles and imported dynamically).
In this project, we’ll use Bit to manage different parts of our solution as Bit components. We’ll share the components on bit.cloud and deploy the apps (also Bit components) to their respective hosting services.
Explore this project by:
Reviewing the Bit components in their remote scope on bit.cloud
Forking (copying) the entire solution to your Bit workspace by running bit scope fork learnbit.react-es-mfe YOUR_ACCOUNT_AND_SCOPE_NAME (use your bit.cloud account and scope name)
Visiting the deployed application
Creating the micro frontend
To get started with our project, we’ll create a new Bit workspace (replace my-account.my-scope with your own bit.cloud account and scope name):
cd my-workspace
Since our solution is entirely component-based, our host app and micro frontend will also be maintained as independent Bit components.
To create a new React Vite app, we’ll use Bit’s out-of-the-box component template for React Vite apps:
See the micro frontend component in its scope
To make our MFE dynamically loadable as an ES Module, we’ll configure Vite to build it as a library with the ‘es’ format.
We’ll do this by adding the necessary configuration to the vite.config.js file at the root of our component’s directory:
import reactPlugin from ‘@vitejs/plugin-react‘;
import cssInjectedByJsPlugin from ‘vite-plugin-css-injected-by-js‘;
import { myRemoteModules } from ‘@learnbit/react-es-mfe.remote-modules‘;
export default defineConfig({
plugins: [
reactPlugin({
jsxRuntime: ‘classic‘, // it’s easier to exclude react from the bundle when not using the new jsx runtime
}),
cssInjectedByJsPlugin(), // this is to inject this MFE’s CSS, when it is loaded
],
define: {
‘process.env‘: ‘{}‘, // this is to avoid ‘process is undefined’ error in the browser
},
build: {
lib: {
formats: [‘es‘],
entry: ‘./my-mfe.tsx‘,
fileName: ‘v0.0.1‘, // it’s recommended to use a version for each MFE deployment
},
rollupOptions: {
external: myRemoteModules.listModules(), // the remote modules to exclude from the bundle
},
},
});
The remote modules component, used by this config, contains a list of modules to be loaded dynamically at runtime, and to be excluded from the MFE and host app bundles. This list contains shared dependencies like react, as well as micro frontends.
We’ll also exclude shared dependencies from our MFE’s bundle to keep our bundles small and avoid duplications.
Bit components are configured as “app components” when they include a *.bit-app.ts file in their component directory. This file configures the app’s build and deployment. In this example, we’ll deploy our app components (the MFE and host app) to Netlify.
Since this is an app, we can run it locally using the bit run command:
Run bit app list to list the apps available in your workspace
Creating the remote modules mapping
As mentioned earlier, our MFEs and host app will use a (shared) Bit component to manage the list of modules to be loaded dynamically at runtime.
We’ll create a new Bit component to manage this list. This time, we’ll use Bit’s out-of-the-box component template for a simple Node.js module:
See the remote module component in its scope
Our list of modules will include the shared dependencies and the MFEs. In this example, we’ll include react and the previously created MFE.
export const myRemoteModules = new RemoteModules([
{
name: ‘react‘,
path: ‘https://esm.sh/react@18.2.0‘,
},
{
name: ‘@learnbit/react-es-mfe.my-mfe‘,
path: ‘https://bit-react-esm-mfe.netlify.app/v0.0.1.js‘, // the MFE’s URL as defined by its bit-app.ts file.
},
]);
Creating the host app
To create our host application, we’ll, again, use Bit’s out-of-the-box component template for a React Vite app:
See the host application component in its remote scope
Our host app will be built as a regular Vite app. However, since it should dynamically load the MFEs, we’ll need to configure it to exclude shared dependencies and MFEs from its bundle.
We’ll, also inject an import map to the HTML file, to instruct the browser on how to resolve imports at runtime.
import reactPlugin from ‘@vitejs/plugin-react‘;
import { myRemoteModules } from ‘@learnbit/react-es-mfe.remote-modules‘; // the remote modules list
import importMapPlugin from ‘@learnbit/react-es-mfe.vite-import-map-plugin‘; // a custom Vite plugin to inject the import map
export default defineConfig({
plugins: [reactPlugin(),
// inject the import map (from the remote-modules component)
importMapPlugin(myRemoteModules.createImportMap())],
build: {
rollupOptions: {
// exclude remote modules from the app’s bundle
external: myRemoteModules.listModules(),
},
},
});
The custom plugin used by the host app replaces the <–importmaps–> placeholder in the HTML file with the import map generated by the remote modules list.
To run the host app locally, we can use the bit run command:
In development, our host app will consume the MFEs from the local node_modules directory in the workspace, and will not load them from their deployed URLs (as it would in production).
This allows us to develop and test the MFEs locally, without having to deploy them (when Bit components are maintained locally, they are symlinked from their source directory to the node_modules directory. Otherwise, they are installed from the registry).
Sharing the components and deploying the apps
Run the following to build your components, export (push) them to their remote scope on bit.cloud, and deploy the app components to their hosting (as configured in the .bit-app.ts file of each app component):
bit export
The components will be built on bit.cloud. Once the build is over, the components will be available in their remote scope (the remote scope was configured at the beginning of this tutorial when we initialized a new Bit workspace with the –default-scope property).