DEV Community

Cover image for Webpack Module Federation for production environnement
ecyrbe
ecyrbe

Posted on

Webpack Module Federation for production environnement

Webpack Module federation is a really nice piece of technology for decoupling your micro frontends setups, with dynamic shared code resolution. All the pitfalls of webpack externals gone.

But i see a lot of problematic examples on how to setup ModuleFederation with toy setups that don't work for production environnement or even even worse, hacky solutions thats no one can understand without understanding webpack arkanes.
Here on dev.to, check this one. Even the tagged update with promise example from the MF author himself is a problematic setup.

It's problematic, because these setups are not Website URL agnostic or rely on runtime hacks to inject your integration / staging / production URLs. These setups don't scale even if they claim they do so.

Here i'm going to show a non problematic setup example, that do not need runtime hacks or configurations.

A simple configure once, build once, deploy everywhere setup.
Sounds like magic, doesn't it. Let's dive in.

Architecture

micro-frontend architecture

The first thing you should notice, is that everything is behind the same domain URL. So the fist recommendation of this setup is :

  • Put your website behind one and only one Domain URL.
    • No CORS configuration nightmare.
    • It hides your internal architecture from the end-user. your users should have no idea that your website is split into micro-frontends.
    • It simplifies your webpack configuration with module federation.

To hide your internal architecture from the user, use a reverse Proxy. It can be any technology, like Nginx, Kong, HaProxy, kubernetes ingress, ...

From one domain to URL agnostic setup

How does this setup simplifies webpack configuration with module federation ?

Some of you might already know this. It's the same recommandation you have always been told as frontend developpers. So here is the second recommandation for this setup :

  • Use relavite path URLs for your own website URLs. Only use domain URLs for external websites.
    • domain URL: https://domain/mfe-1
    • relavite URL: /mfe-1

So, it's really that simple. Module Federation is webpack, and webpack supports relative URL setup.
By using relative URL, you won't need to configure your website Domain anywhere and you'll be able to deploy it everywhere. The same build, deployed on your integration, staging and production environnments.

Webpack example config for Host

So here is a webpack.config.js example for your Host using only only relative URL. No harcoded Domain. The important parts are in:

  • 'publicPath' attribute that should use relative URL,
  • 'remotes' property in ModuleFederation setup that should also use relative URL
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;
const webpack = require('webpack');

module.exports = {
  mode: 'production',
  entry: '<path to your local host index.js>',
  cache: false,
  devtool: false,
  optimization: {
    minimize: true,
  },
  output: {
    // you could use 'auto', but 'auto' does not work with ie11, it's better to use relative url anyway.
    publicPath: '/',
    clean: true,
    pathinfo: false,
    path: buildPath,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        loader: 'swc-loader',
        options: {
          cacheDirectory: true,
        },
      },
    ],
  },
    : [
        new ModuleFederationPlugin({
          name: 'host',
          remotes: {
            // relative URL
            mfe_1: 'mfe_1@/mfe-1/remoteEntry.js',
            mfe_2: 'mfe_2@/mfe-2/remoteEntry.js',
          },
          shared: {
            ...deps,
          },
        }),
        new HtmlWebpackPlugin({
          template: 'index.html',
          inject: 'body',
          hash: true,
          minify: true,
        }),
      ],
};
Enter fullscreen mode Exit fullscreen mode

Webpack example config for a micro-frontend

So here is a webpack.config.js example for your Micro-frontend using only only relative URL. No harcoded Domain. The important parts are in:

  • 'publicPath' attribute that should use relative URL,
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('./package.json').dependencies;
const webpack = require('webpack');

module.exports = {
  mode: 'production',
  entry: '<path to your local mfe index.js>',
  cache: false,
  devtool: false,
  optimization: {
    minimize: true,
  },
  output: {
    // relative URL
    publicPath: '/mfe-1/',
    clean: true,
    pathinfo: false,
    path: buildPath,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        loader: 'swc-loader',
        options: {
          cacheDirectory: true,
        },
      },
    ],
  },
  plugins: [
        new ModuleFederationPlugin({
          name: 'mfe_1',
          filename: 'remoteEntry.js',
          library: { type: 'var', name: 'mfe_1' },
          remotes: {},
          exposes: {
            './view1': '<path to your local view js>',
          },
          shared: {
            ...deps,
          },
        }),
      ]
};
Enter fullscreen mode Exit fullscreen mode

Conclusion

You should not need to understand the arkanes of webpack to configure module federation for your production environnement.
Just remember these two rules :

  • Put your website behind one and only one Domain URL.
  • Use relavite path URLs for your own website URLs. Only use domain URLs for external websites.

Thanks for reading. Don't forget to like the article if it was usefull to you.

Top comments (1)

Collapse
 
venkatasaiteja_nalluri_ profile image
Venkata sai teja Nalluri

Hi I am also following similar structure in my project storing everything thing in s3 like this hostapp inside there will be separate folders with the name same as we point public path of mfs till here it’s ok … as I have host as a container for whole mfs .. host will have bunch of mfs though base url remains Same for all mfs out of context of this article I am concerned about the load time host app when they are too many mfs … second thing in host remotes of mfs which u mentioned mfe_1: 'mfe_1@/mfe-1/remoteEntry.js' as you placed relative url here after @ how would it capture base url that been hosted … I have got webpacks for different envs and placed base url like this mfe_1: 'mfe_1@/example.com/mfe_1/remoteEntry.js' for all mfs will ensure after base url before remote entry.js I will ensure that name should match with public path of different mfs when I mentioned is that gud to do …