# Patternslib Module Federation

## Introduction

For a general introduction see: https://webpack.js.org/concepts/module-federation/

Module Federation allows to share dependencies between bundles.
Each bundle includes the whole set of dependencies.
If multiple bundles have the same dependencies they are only loaded once.

For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, bundle B can just reuse the already loaded jQuery file.
But if only bundle B is loaded, it uses its own bundled version of the jQuery library.

There needs to be __one host bundle__ - the main bundle of your application.
This one is included by using the generated webpack entry point, normally named ``bundle.min.js``.

All other bundles are __remote bundles__.
Remotes are included using the file generated by the ``WebpackModuleFederation`` plugin, normally named ``remote.min.js``.

## How to use it

This is an exmple with a host bundle ``bundle.min.js`` for which also a remote bundle ``remote.min.js`` is created.
The name ``remote.min.js`` is the default from the Patternslib ``webpack.mf.js`` config factory.

We also create a second bundle for the jQuery library ``jquery.min.js`` which has the only purpose to make jQuery available via module federation.
For jQuery the remote bundle is named ``jquery-remote.min.js``.

1) For module federation we need new entry points. For the main bundle ``bundle.min.js`` we create the entry point ``index.js``. It imports the module federation initalization code from Patternslib and imports the normal entry point which initialized the app:

```
import "@patternslib/patternslib/webpack/module_federation";
// Please not the parentheses for the next import.
// Kepp them, otherwise we get this error:
// "Shared module is not available for eager consumption."
import("./src/patterns");
```

For the jQuery bundle which we will use as remote we create: ``index-jquery.js``:

```
import "@patternslib/patternslib/webpack/module_federation";
// Please not the parentheses for the next import.
// Kepp them, otherwise we get this error:
// "Shared module is not available for eager consumption."
import("@patternslib/patternslib/src/globals");
```


2) Add the module federation plugin in webpack using the configuration factory method from Patternslib:

```
const package_json = require("./package.json");
const path = require("path");
const patternslib_config = require("@patternslib/patternslib/webpack/webpack.config");
const mf_config = require("@patternslib/patternslib/webpack/webpack.mf");

module.exports = (env, argv) => {
    let config = {
        entry: {
            "bundle.min": path.resolve(__dirname, "src/index.js"),
            "jquery.min": path.resolve(__dirname, "src/index-jquery.js"),
        },
    };

    config = patternslib_config(env, argv, config);

    // ...

    config.plugins.push(
        mf_config({ // name is used from package.json, filename is the default ``remote.min.js``.
            package_json: package_json,
            remote_entry: config.entry["bundle.min"],
        })
    );

    config.plugins.push(
        mf_config({
            name: "jquery",
            filename: "jquery-remote.min.js",
            remote_entry: config.entry["jquery.min"],
            shared: { // shared dependencies are normally automatically used from the package.json. Here we are explicitly defining them.
                jquery: {
                    singleton: true,
                    requiredVersion: package_json.dependencies["jquery"],
                },
            },
        })
    );

    return config;
};
```

3) You now can include the generated host and remote entry points:

```
<!DOCTYPE html>
<html>
    <head>
        <!-- ... -->
        <script src="/dist/bundle.min.js"></script>
        <script src="/dist/jquery-remote.min.js"></script>
    </head>
    <body class="component-index">
        <!-- ... -->
```

That's basically it.

For more information look at the source code at ``@patternslib/webpack/module_federation`` and ``@patternslib/webpack/webpack.mf.js``.

