Module Federation
Module Federation allows multiple webpack builds to work together.
- From the runtime environment's perspective, modules from multiple different builds will behave like a huge connected module graph.
- From the developer's perspective, we will be able to import modules from specific remote builds, and use them with minimal restriction.
Motivation
Imagine we want to implement a micro frontend Micro Frontend, which would have these qualities:
- It should take multiple separate builds to form a single application.
- These separate builds should not have dependencies between each other, so they can be developed and deployed individually
There is a distinction between local and remote modules
- Local modules are normal modules which are part of the current build.
- Remote modules are modules that are not part of the current build and loaded from a so-called container at the runtime.
- Loading remote modules is considered async (due to the network call involved). When using a remote module these asynchronous operations will be placed in the next chunk of loading operations that is between the remote module and the entrypoint. Chunk loading is necessary.
A container is created through a container entry, which exposes asynchronous access to the specific modules. The exposed access is separated into two steps:
- loading the module (asynchronous)
- done during the chunk loading
- evaluating the module (synchronous).
- done during the module evaluation interleaved with other local and remote modules
- This way, evaluation order is unaffected by converting a module from local to remote or the other way around.
- done during the module evaluation interleaved with other local and remote modules
High-level Overview
Each build acts as a container and also consumes other builds as containers. This way each build is able to access any other exposed module by loading it from its container.
Goals of the system
- It should be possible to expose and use any module type that webpack supports.
- Chunk loading should load everything needed in parallel (web: single round-trip to server).
- Control from consumer to container
- Overriding modules is a one-directional operation.
- Sibling containers cannot override each other's modules.
- Concept should be environment-independent.
- Usable in web, Node.js, etc.
- Relative and absolute request in shared:
- Will always be provided, even if not used.
- Will resolve relative to
config.context
. - Does not use a
requiredVersion
by default.
- Module requests in shared:
- Are only provided when they are used.
- Will match all used equal module requests in your build.
- Will provide all matching modules.
- Will extract
requiredVersion
from package.json at this position in the graph. - Could provide and consume multiple different versions when you have nested node_modules.
- Module requests with trailing
/
in shared will match all module requests with this prefix.
Use cases
- separate builds per page
- Each page of a Single Page Application is exposed from container build in a separate build. This way each page can be separately deployed
- Components library as container
- Many applications share a common components library which could be built as a container with each component exposed. Each application consumes components from the components library container.
- Changes to the components library can be separately deployed without the need to re-deploy all applications.