Obtención de datos
Por lo general, los módulos remotos quieren encargarse por sí mismos de obtener sus datos: el consumer solo es responsable de cargarlos y renderizarlos, sin tener que saber de qué datos depende el remote y sin que cada consumer tenga que reimplementar la misma lógica de obtención.
En escenarios CSR, un remote puede simplemente llamar a useEffect dentro del componente para lanzar la petición. En escenarios SSR, en cambio, useEffect no se ejecuta en el servidor, así que el remote no puede obtener los datos en el servidor antes de renderizar.
Los principales frameworks de SSR (Next.js, Remix, Modern.js, etc.) suelen ofrecer precarga de datos a nivel de ruta: cuando una ruta coincide, primero se ejecuta una función de carga de datos y esos datos se inyectan en el componente de la ruta correspondiente. Pero este mecanismo depende del router de cada framework, y los módulos expuestos por Module Federation no forman parte del árbol de rutas del host, así que no se puede reutilizar directamente.
Para resolverlo, Module Federation ofrece capacidades de obtención de datos a nivel de componente, de modo que los desarrolladores puedan obtener datos y renderizar componentes en escenarios SSR.
Los módulos expuestos mediante Module Federation se dividen en dos grandes categorías:
- Componentes: componentes de UI independientes, funciones de utilidad, etc., sin router propio.
- Aplicaciones: subaplicaciones con un router completo, que normalmente se exponen y consumen mediante Bridge.
La capacidad que se describe en este documento está pensada para la primera categoría: la obtención de datos "a nivel de componente". Consulta la demo para ver un recorrido detallado.
Cómo usarlo
La obtención de datos admite escenarios tanto SSR como CSR. Las siguientes secciones tratan el producer y el consumer por separado:
Producer
Convención de archivos para la obtención de datos
La obtención de datos usa una convención de archivos:
- Cada módulo expuesto puede emparejarse con un archivo
.datacon el mismo nombre. - La función que se exporta desde un archivo
.datase llama Data Loader, y el plugin de build reconoce esta convención. - Cuando se carga un componente expuesto, el runtime llama primero al Data Loader para obtener los datos, los inyecta en el componente y después lo renderiza.
Ejemplo de estructura de archivos:
El archivo de la convención debe exportar una función llamada fetchData, que se ejecuta antes de que se renderice el componente remoto:
La función se llama antes de que se renderice el componente, y el runtime inyecta el objeto de datos devuelto en las props del componente. La clave predeterminada es mfData:
Parámetros predeterminados de la función loader
De forma predeterminada, se pasan parámetros a la función loader. Su tipo es DataFetchParams, que incluye el siguiente campo:
isDowngrade: indica si el contexto de ejecución actual está en modo de fallback. Por ejemplo, si falla el renderizado en el servidor, el navegador envía una nueva petición al servidor para llamar a la función loader; en ese caso, el valor estrue.
Usar el Data Loader en distintos entornos
La función loader puede ejecutarse en el servidor o en el navegador. Una función loader que se ejecuta en el servidor se llama Server Loader, y una que se ejecuta en el navegador se llama Client Loader.
En aplicaciones CSR, la función loader se ejecuta en el navegador, así que, de forma predeterminada, todas son Client Loaders.
En aplicaciones SSR, la función loader solo se ejecuta en el servidor, así que, de forma predeterminada, todas son Server Loaders. En SSR, Module Federation llama directamente a la función loader correspondiente en el servidor. Al cambiar de ruta en el navegador, Module Federation envía una petición HTTP al servicio de SSR, que también ejecuta la función loader en el servidor.
- Uso simplificado: garantiza que la forma de obtener datos en las aplicaciones SSR sea isomórfica, de modo que los desarrolladores no necesitan diferenciar la ejecución del código según el entorno.
- Bundle del navegador más pequeño: el código de lógica y sus dependencias se trasladan del navegador al servidor.
- Mejor mantenibilidad: trasladar el código de lógica al servidor reduce el impacto directo de la lógica de datos en la UI del frontend. También evita incluir por error dependencias del servidor en el bundle del navegador o viceversa.
Usar un Client Loader en aplicaciones SSR
De forma predeterminada, en las aplicaciones SSR la función loader solo se ejecuta en el servidor. Sin embargo, en algunos escenarios los desarrolladores pueden querer que las peticiones del navegador vayan directamente a la fuente de datos sin pasar por el servicio de SSR. Por ejemplo:
- Para reducir el consumo de red en el navegador solicitando directamente a la fuente de datos.
- La aplicación tiene una caché de datos en el navegador y no quiere solicitar datos al servicio de SSR.
Module Federation permite añadir un archivo .data.client adicional en las aplicaciones SSR, que exporta la función con nombre de la misma manera. En ese caso, si el Data Loader del servidor falla y se recurre al fallback, o al cambiar de ruta en el navegador, la aplicación ejecutará esta función en el navegador como una aplicación CSR, en lugar de enviar otra petición de datos al servicio de SSR.
Para usar un Client Loader, debe existir un Server Loader correspondiente, y el Server Loader debe estar definido en un archivo .data.
Producer que consume los datos de su propia aplicación
Un producer también puede visitarse como una página independiente. En ese caso, debe poder obtener datos en ambos escenarios:
- Cuando lo carga un consumer, los datos se inyectan mediante el Data Loader.
- Cuando se visita directamente, los datos se obtienen mediante el mecanismo propio del framework del producer.
Por ejemplo, si el producer usa Modern.js, debe admitir tanto que lo cargue un consumer como que se visite directamente como página del producer. Puedes hacerlo así:
- Crea un archivo
page.data.tsen el directorio de la página del producer y exporta una función llamadaloader:
La convención de Modern.js es exportar una función loader desde page.data.ts para obtener datos.
- Consume estos datos en la
pagedel producer:
Consumer
Actualmente, solo Modern.js admite la obtención de datos en entornos SSR.
En el consumer, debes usar la API createLazyComponent para cargar el componente remoto y obtener sus datos.
Pasar parámetros personalizados
Además de la estructura de datos que el runtime inyecta de forma predeterminada, el consumer puede pasar parámetros personalizados a la función loader mediante el campo dataFetchParams de createLazyComponent; por ejemplo, contexto del lado del host como el identificador de usuario, el idioma o el tenant.
Este campo se combina con los parámetros predeterminados y se pasa al loader.
Preguntas frecuentes
¿Obtención de datos a nivel de aplicación?
Para los módulos a nivel de aplicación, preferimos usar RSC (React Server Components) para que la funcionalidad sea más completa. Esta función está actualmente en fase de exploración, así que mantente atento.
¿Se admiten producers anidados?
No, no se admiten.
¿Hay otros plugins para producers además del plugin de Rslib y el de Modern.js?
Actualmente, solo los plugins de Rslib y Modern.js pueden crear un Data Loader.