Nuestro team de expertos pasados ciertos días de trabajo y de recopilar de información, han obtenido los datos necesarios, nuestro deseo es que te resulte útil en tu proyecto.
Motivación
Varias compilaciones independientes deben formar una sola aplicación. Estas compilaciones independientes no deben tener dependencias entre sí, por lo que pueden desarrollarse e implementarse individualmente.
Esto a menudo se conoce como Micro-Frontends, pero no se limita a eso.
Conceptos de bajo nivel
Distinguimos entre módulos locales y remotos. Los módulos locales son módulos normales que forman parte de la construcción actual. Los módulos remotos son módulos que no forman parte de la compilación actual y se cargan desde un llamado contenedor en el tiempo de ejecución.
La carga de módulos remotos se considera una operación asincrónica. Cuando se utiliza un módulo remoto, estas operaciones asincrónicas se colocarán en las siguientes operaciones de carga de fragmentos que se encuentran entre el módulo remoto y el punto de entrada. No es posible utilizar un módulo remoto sin una operación de carga de fragmentos.
Una operación de carga de fragmentos suele ser una import()
llamar, pero construcciones más antiguas como require.ensure
o require([...])
también son compatibles.
Un contenedor se crea a través de una entrada de contenedor, que expone el acceso asincrónico a los módulos específicos. El acceso expuesto se divide en dos pasos:
- cargando el módulo (asincrónico)
- evaluación del módulo (síncrono).
El paso 1 se realizará durante la carga de fragmentos. El paso 2 se realizará durante la evaluación del módulo intercalado con otros módulos (locales y remotos). De esta forma, el orden de evaluación no se ve afectado al convertir un módulo de local a remoto o al revés.
Es posible anidar un contenedor. Los contenedores pueden utilizar módulos de otros contenedores. También son posibles las dependencias circulares entre contenedores.
Primordial
Un contenedor puede marcar módulos locales seleccionados como “reemplazables”. Un consumidor del contenedor puede proporcionar “anulaciones”, que son módulos que reemplazan uno de los módulos anulables del contenedor. Todos los módulos del contenedor usarán el módulo de reemplazo en lugar del módulo local cuando el consumidor proporcione uno. Cuando el consumidor no proporciona un módulo de reemplazo, todos los módulos del contenedor usarán el local.
El contenedor administrará los módulos reemplazables de manera que no sea necesario descargarlos cuando el consumidor los haya reemplazado. Esto suele suceder colocándolos en trozos separados.
Por otro lado, el proveedor de los módulos de reemplazo solo proporcionará funciones de carga asincrónica. Permite que el contenedor cargue módulos de reemplazo solo cuando son necesarios. El proveedor gestionará los módulos de sustitución de forma que no sea necesario descargarlos cuando el contenedor no los solicite. Esto suele suceder colocándolos en trozos separados.
Se utiliza un “nombre” para identificar módulos reemplazables del contenedor.
Las anulaciones se proporcionan de forma similar a como el contenedor expone los módulos, separados en dos pasos:
- Cargando (asincrónico)
- evaluar (asincrónico)
Se deben proporcionar anulaciones antes de que se carguen los módulos del contenedor. Las invalidables que se usan en el fragmento inicial, solo se pueden invalidar mediante una invalidación de módulo síncrono que no usa Promesas. Una vez evaluados, los reemplazables ya no son reemplazables.
Conceptos de alto nivel
Cada compilación actúa como un contenedor y también consume otras compilaciones como contenedores. De esta manera, cada compilación puede acceder a cualquier otro módulo expuesto cargándolo desde su contenedor.
Los módulos compartidos son módulos que se pueden anular y se proporcionan como anulaciones del contenedor anidado. Por lo general, apuntan al mismo módulo en cada compilación, por ejemplo, la misma biblioteca.
los packageName
La opción permite configurar un nombre de paquete para buscar un requiredVersion
. Se infiere automáticamente para las solicitudes de módulo de forma predeterminada, establezca requiredVersion
para false
cuando la inferencia automática debe estar deshabilitada.
Bloques de construcción
OverridablesPlugin
(nivel bajo)
Este complemento hace que módulos específicos sean “reemplazables”. Una API local (__webpack_override__
) permite proporcionar anulaciones.
webpack.config.js
const OverridablesPlugin =require('webpack/lib/container/OverridablesPlugin'); module.exports = plugins:[newOverridablesPlugin([// we define an overridable module with OverridablesPlugin test1:'./src/test1.js',,]),],;
src / index.js
__webpack_override__(// here we override test1 moduletest1:()=>'I will override test1 module under src',);
ContainerPlugin
(nivel bajo)
Este complemento crea una entrada de contenedor adicional con los módulos expuestos especificados. También utiliza el OverridablesPlugin
internamente y expone el override
API al consumidor del contenedor.
ContainerReferencePlugin
(nivel bajo)
Este complemento agrega referencias específicas a contenedores como externos y permite importar módulos remotos desde estos contenedores. También llama al override
API de estos contenedores para proporcionarles anulaciones. Anulaciones locales (a través de __webpack_override__
o override
API cuando la compilación también es un contenedor) y se proporcionan anulaciones especificadas a todos los contenedores referenciados.
ModuleFederationPlugin
(nivel alto)
Este complemento combina ContainerPlugin
y ContainerReferencePlugin
. Las invalidaciones y las invalidables se combinan en una única lista de módulos compartidos especificados.
Metas del concepto
- Debería ser posible exponer y utilizar cualquier tipo de módulo compatible con webpack.
- La carga de fragmentos debe cargar todo lo necesario en paralelo (web: ida y vuelta única al servidor).
- Control del consumidor al contenedor
- La anulación de módulos es una operación unidireccional.
- Los contenedores hermanos no pueden anular los módulos de los demás.
- El concepto debe ser independiente del medio ambiente.
- Utilizable en web, Node.js, etc.
- Solicitud relativa y absoluta en compartido:
- Siempre se proporcionará, incluso si no se utiliza.
- Resolverá en relación con
config.context
. - No usa un
requiredVersion
por defecto.
- Solicitudes de módulo en compartido:
- Solo se proporcionan cuando se utilizan.
- Coincidirá con todas las solicitudes de módulos iguales utilizadas en su compilación.
- Proporcionará todos los módulos correspondientes.
- Extraerá
requiredVersion
de package.json en esta posición del gráfico. - Podría proporcionar y consumir varias versiones diferentes cuando haya anidado node_modules.
- Solicitudes de módulo con seguimiento
/
en compartido coincidirá con todas las solicitudes de módulo con este prefix.
Casos de uso
Compilaciones separadas por página
Cada página de una aplicación de página única se expone desde la compilación del contenedor en una compilación separada. El shell de la aplicación también es una compilación independiente que hace referencia a todas las páginas como módulos remotos. De esta forma, cada página se puede implementar por separado. El shell de la aplicación se implementa cuando se actualizan las rutas o se agregan nuevas rutas. El shell de la aplicación define las bibliotecas de uso común como módulos compartidos para evitar su duplicación en las compilaciones de la página.
Biblioteca de componentes como contenedor
Muchas aplicaciones comparten una biblioteca de componentes común que podría construirse como un contenedor con cada componente expuesto. Cada aplicación consume componentes del contenedor de la biblioteca de componentes. Los cambios en la biblioteca de componentes se pueden implementar por separado sin la necesidad de volver a implementar todas las aplicaciones. La aplicación utiliza automáticamente la versión actualizada de la biblioteca de componentes.
Contenedores remotos dinámicos
La interfaz del contenedor admite get
y init
métodos. init
es un async
método compatible que se llama con un argumento: el objeto de alcance compartido. Este objeto se utiliza como ámbito compartido en el contenedor remoto y se llena con los módulos proporcionados desde un host. Se puede aprovechar para conectar contenedores remotos a un contenedor de host de forma dinámica en tiempo de ejecución.
init.js
(async()=>// Initializes the shared scope. Fills it with known provided modules from this build and all remotesawait__webpack_init_sharing__('default');const container = window.someContainer;// or get the container somewhere else// Initialize the container, it may provide shared modulesawait container.init(__webpack_share_scopes__.default);const module =await container.get('./module');)();
El contenedor intenta proporcionar módulos compartidos, pero si el módulo compartido ya se ha utilizado, se ignorará una advertencia y el módulo compartido proporcionado. Es posible que el contenedor aún lo use como respaldo.
De esta manera, podría cargar dinámicamente una prueba A / B que proporciona una versión diferente de un módulo compartido.
Ejemplo:
init.js
functionloadComponent(scope, module)returnasync()=>// Initializes the shared scope. Fills it with known provided modules from this build and all remotesawait__webpack_init_sharing__('default');const container = window[scope];// or get the container somewhere else// Initialize the container, it may provide shared modulesawait container.init(__webpack_share_scopes__.default);const factory =await window[scope].get(module);const Module =factory();return Module;;loadComponent('abtests','test123');
Solución de problemas
Uncaught Error: Shared module is not available for eager consumption
La aplicación está ejecutando con entusiasmo una aplicación que funciona como un host omnidireccional. Hay opciones para elegir:
Puede configurar la dependencia como ansiosa dentro de la API avanzada de Module Federation, que no coloca los módulos en un fragmento asíncrono, sino que los proporciona de forma síncrona. Esto nos permite usar estos módulos compartidos en el fragmento inicial. Pero tenga cuidado, ya que siempre se descargarán todos los módulos proporcionados y de respaldo. Se recomienda proporcionarlo solo en un punto de su aplicación, por ejemplo, el shell.
Recomendamos encarecidamente utilizar un límite asincrónico. Dividirá el código de inicialización de un fragmento más grande para evitar viajes de ida y vuelta adicionales y mejorar el rendimiento en general.
Por ejemplo, su entrada se ve así:
index.js
import React from'react';import ReactDOM from'react-dom';import App from'./App'; ReactDOM.render(<App />, document.getElementById('root'));
Vamos a crear bootstrap.js
archivo y mueva el contenido de la entrada en él, e importe ese bootstrap en la entrada:
index.js
+ import('./bootstrap'); - import React from 'react'; - import ReactDOM from 'react-dom'; - import App from './App'; - ReactDOM.render(, document.getElementById('root'));
bootstrap.js
+ import React from 'react';
+ import ReactDOM from 'react-dom';
+ import App from './App';
+ ReactDOM.render( , document.getElementById('root'));
Este método funciona pero puede tener limitaciones o inconvenientes.
Configuración eager: true
para la dependencia a través del ModuleFederationPlugin
webpack.config.js
// ...newModuleFederationPlugin( shared:...deps, react: eager:true,,,);
Uncaught Error: Module "./Button" does not exist in container.
Probablemente no diga "./Button"
, pero el mensaje de error será similar. Este problema suele aparecer si está actualizando desde webpack beta.16 a webpack beta.17.
Dentro de ModuleFederationPlugin. Cambie las exposiciones de:
new ModuleFederationPlugin( exposes: - 'Button': './src/Button' + './Button':'./src/Button' );
Uncaught TypeError: fn is not a function
Es probable que le falte el contenedor remoto, asegúrese de que esté agregado. Si tiene el contenedor cargado para el control remoto que está intentando consumir, pero aún ve este error, agregue también el archivo contenedor remoto del contenedor del host al HTML.
Otras lecturas
- Webpack 5 Module Federation: un cambio de juego en la arquitectura JavaScript
- Explicaciones y ejemplos
- Lista de reproducción de YouTube de la federación de módulos
valoraciones y reseñas
Si haces scroll puedes encontrar las explicaciones de otros gestores de proyectos, tú de igual forma tienes la opción de dejar el tuyo si te gusta.