Las fortalezas y beneficios de las microfrontends
Publicado: 2022-03-11La arquitectura de micro-frontend es un enfoque de diseño en el que una aplicación de front-end se descompone en "microaplicaciones" individuales, semiindependientes, que funcionan juntas de forma flexible. El concepto de micro-frontend está vagamente inspirado y recibe su nombre de los microservicios.
Los beneficios del patrón de micro-frontend incluyen:
- Las arquitecturas de micro-frontend pueden ser más simples y, por lo tanto, más fáciles de razonar y administrar.
- Los equipos de desarrollo independientes pueden colaborar en una aplicación front-end más fácilmente.
- Pueden proporcionar un medio para migrar desde una aplicación "antigua" al tener una aplicación "nueva" ejecutándose junto con ella.
Aunque las microfrontends han recibido mucha atención últimamente, hasta el momento no existe una única implementación dominante ni un "mejor" marco claro de micro-frontends. De hecho, existe una variedad de enfoques dependiendo de los objetivos y requisitos. Consulte la bibliografía para conocer algunas de las implementaciones más conocidas.
En este artículo, omitiremos gran parte de la teoría de las microfrontends. Esto es lo que no cubriremos:
- "Cortar" una aplicación en microaplicaciones
- Problemas de implementación, incluida la forma en que las microfrontends encajan en un modelo de CI/CD
- Pruebas
- Si las microaplicaciones deben estar alineadas uno a uno con los microservicios en el backend
- Críticas al concepto de micro-frontend
- La diferencia entre micro frontends y una arquitectura de componentes simple y antigua
En su lugar, presentaremos un tutorial de micro-frontend centrado en una implementación concreta, destacando los problemas importantes en la arquitectura de micro-frontend y sus posibles soluciones.
Nuestra implementación se llama Yumcha. El significado literal de "yum cha" en cantonés es "beber té", pero su significado cotidiano es "salir por dim sum". La idea aquí es que las microaplicaciones individuales dentro de una macroaplicación (como llamaremos a la aplicación compuesta de nivel superior) son análogas a las diversas canastas de porciones del tamaño de un bocado que se sirven en un almuerzo de dim sum.
A veces nos referiremos a Yumcha como un "marco de micro-frontend". En el mundo actual, el término "marco" generalmente se usa para referirse a Angular, React, Vue.js u otras superestructuras similares para aplicaciones web. No estamos hablando de un marco en ese sentido en absoluto. Llamamos a Yumcha un marco solo por conveniencia: en realidad es más un conjunto de herramientas y algunas capas delgadas para crear aplicaciones basadas en micro frontend.
Tutorial de micro-frontend Primeros pasos: marcado para una aplicación compuesta
Profundicemos pensando en cómo podríamos definir una macroaplicación y las microaplicaciones que la componen. El marcado siempre ha estado en el corazón de la web. Por lo tanto, nuestra macroaplicación se especificará con nada más complicado que este marcado:
<html> <head> <script src="/yumcha.js"></script> </head> <body> <h1>Hello, micro-frontend app.</h1> <!-- HERE ARE THE MICROAPPS! --> <yumcha-portal name="microapp1" src="https://microapp1.example.com"></yumcha-portal> <yumcha-portal name="microapp2" src="https://microapp2.example.com"></yumcha-portal> </body> </html>
Definir nuestra macroaplicación mediante el marcado nos brinda acceso completo al poder de HTML y CSS para diseñar y administrar nuestras microaplicaciones. Por ejemplo, una microaplicación podría sentarse encima de otra, o a su lado, o estar en la esquina de la página, o estar en un panel de un acordeón, o permanecer oculta hasta que suceda algo, o permanecer en segundo plano permanentemente. .
Hemos denominado al elemento personalizado utilizado para las microaplicaciones <yumcha-portal>
porque "portal" es un término prometedor para las microaplicaciones utilizadas en la propuesta del portal, un primer intento de definir un elemento HTML estándar para su uso en micro interfaces.
Implementación del elemento personalizado <yumcha-portal>
¿Cómo deberíamos implementar <yumcha-portal>
? Como es un elemento personalizado, como un componente web, ¡por supuesto! Podemos elegir entre una serie de fuertes contendientes para escribir y compilar componentes web micro-frontend; aquí usaremos LitElement, la última versión del Proyecto Polymer. LitElement es compatible con el azúcar sintáctico basado en TypeScript, que maneja la mayor parte del repetitivo de elementos personalizados para nosotros. Para que <yumcha-portal>
esté disponible en nuestra página, debemos incluir el código relevante como <script>
, como hicimos anteriormente.
Pero, ¿qué hace realmente <yumcha-portal>
? Una primera aproximación sería que simplemente creara un iframe
con la fuente especificada:
render() { return html`<iframe src=${this.src}></iframe>`; }
…donde render
es el gancho de renderizado estándar de LitElement, usando su literal de plantilla etiquetada html
. Esta funcionalidad mínima podría ser casi suficiente para algunos casos de uso triviales.
Incrustación de microaplicaciones en iframe
s
Los iframe
son el elemento HTML que a todos les encanta odiar, pero en realidad proporcionan un comportamiento de sandboxing extremadamente útil y sólido como una roca. Sin embargo, todavía hay una larga lista de problemas a tener en cuenta al usar iframe
, con un impacto potencial en el comportamiento y la funcionalidad de nuestra aplicación:
- En primer lugar, los
iframe
tienen peculiaridades bien conocidas en términos de cómo se dimensionan y se distribuyen. - Por supuesto, CSS estará completamente aislado del
iframe
, para bien o para mal. - El botón "atrás" del navegador funcionará razonablemente bien, aunque el estado de navegación actual del
iframe
no se reflejará en la URL de la página , por lo que no podríamos cortar y pegar URL para llegar al mismo estado de la aplicación compuesta, ni realizar un enlace profundo. a ellos - La comunicación con el
iframe
desde el exterior, según nuestra configuración de CORS, podría necesitar pasar por el protocolopostMessage
. - Se tendrán que hacer arreglos para la autenticación a través de los límites del
iframe
. - Algunos lectores de pantalla pueden tropezar con el límite del
iframe
o necesitar que eliframe
tenga un título que puedan anunciar al usuario.
Algunos de estos problemas pueden evitarse o mitigarse al no usar iframe
s, una alternativa que analizamos más adelante en este artículo.
En el lado positivo, el iframe
tendrá su propia Content-Security-Policy
(CSP) independiente. Además, si la microaplicación a la que apunta el iframe
utiliza un trabajador de servicio o implementa la representación del lado del servidor, todo funcionará como se esperaba. También podemos especificar varias opciones de espacio aislado para el iframe
para limitar sus capacidades, como poder navegar al marco superior.
Algunos navegadores han enviado o planean enviar un atributo loading=lazy
para iframe
s, que difiere la carga de iframe
en la parte inferior de la página hasta que el usuario se desplaza cerca de ellos, pero esto no proporciona el control detallado de la carga diferida que queremos.
El verdadero problema con los iframe
s es que el contenido del iframe
requerirá múltiples solicitudes de red para recuperarse. Se recibe el index.html
de nivel superior, se cargan sus secuencias de comandos y se analiza su HTML, pero luego el navegador debe iniciar otra solicitud para el HTML del iframe
, esperar a recibirlo, analizar y cargar sus secuencias de comandos y procesar el Contenido del iframe
. En muchos casos, el JavaScript del iframe
aún tendría que activarse, realizar sus propias llamadas a la API y mostrar datos significativos solo después de que esas llamadas a la API regresen y los datos se procesen para su visualización.
Es probable que esto genere retrasos no deseados y artefactos de representación, especialmente cuando hay varias microaplicaciones involucradas. Si la aplicación del iframe
implementa SSR, eso ayudará pero no evitará la necesidad de viajes de ida y vuelta adicionales.
Entonces, uno de los desafíos clave que enfrentamos al diseñar la implementación de nuestro portal es cómo lidiar con este problema de ida y vuelta. Nuestro objetivo es que una sola solicitud de red desactive toda la página con todas sus microaplicaciones, incluido cualquier contenido que cada una de ellas pueda rellenar previamente. La solución a este problema está en el servidor Yumcha.
El servidor Yumcha
Un elemento clave de la solución de micro-frontend que se presenta aquí es configurar un servidor dedicado para manejar la composición de microaplicaciones. Este servidor envía solicitudes a los servidores donde se aloja cada microaplicación. Por supuesto, requerirá un poco de esfuerzo configurar y administrar este servidor. Algunos enfoques de micro-frontend (por ejemplo, spa único) intentan prescindir de la necesidad de tales configuraciones de servidor especiales, en nombre de la facilidad de implementación y configuración.
Sin embargo, el costo de configurar este proxy inverso está más que compensado por los beneficios que obtenemos; de hecho, hay comportamientos importantes de las aplicaciones basadas en micro frontend que simplemente no podemos lograr sin ellas. Existen muchas alternativas comerciales y gratuitas para configurar dicho proxy inverso.
El proxy inverso, además de enrutar las solicitudes de microaplicaciones al servidor correspondiente, también enruta las solicitudes de macroaplicaciones a un servidor de macroaplicaciones. Ese servidor sirve el HTML para la aplicación compuesta de una manera especial. Al recibir una solicitud de index.html
del navegador a través del servidor proxy en una URL como http://macroapp.example.com
, recupera el index.html
y luego lo somete a una transformación simple pero crucial antes de regresar eso.
Específicamente, el HTML se analiza en busca de etiquetas <yumcha-portal>
, lo que se puede hacer fácilmente con uno de los analizadores de HTML competentes disponibles en el ecosistema de Node.js. Usando el atributo src
para <yumcha-portal>
, se contacta al servidor que ejecuta la microaplicación y se recupera su index.html
, incluido el contenido renderizado del lado del servidor, si lo hay. El resultado se inserta en la respuesta HTML como una etiqueta <script>
o <template>
, para que el navegador no lo ejecute.

Las ventajas de esta configuración incluyen, ante todo, que en la primera solicitud de index.html
para la página compuesta, el servidor puede recuperar las páginas individuales de los servidores de microaplicaciones individuales en su totalidad, incluido el contenido procesado por SSR, si any—y entregue una sola página completa al navegador, incluido el contenido que se puede usar para completar el iframe
sin viajes de ida y vuelta adicionales al servidor (usando el atributo srcdoc
infrautilizado). El servidor proxy también garantiza que cualquier detalle sobre el origen de las microaplicaciones esté oculto a miradas indiscretas. Finalmente, simplifica los problemas de CORS, ya que todas las solicitudes de aplicaciones se realizan al mismo origen.
De vuelta en el cliente, la etiqueta <yumcha-portal>
se instancia y encuentra el contenido donde el servidor lo colocó en el documento de respuesta, y en el momento adecuado representa el iframe
y asigna el contenido a su atributo srcdoc
. Si no estamos usando iframe
s (ver más abajo), entonces el contenido correspondiente a esa etiqueta <yumcha-portal>
se inserta en el shadow DOM del elemento personalizado, si lo estamos usando, o directamente en línea en el documento.
En este punto, ya tenemos una aplicación basada en micro frontend que funciona parcialmente.
Esta es solo la punta del iceberg en términos de funcionalidad interesante para el servidor Yumcha. Por ejemplo, nos gustaría agregar funciones para controlar cómo se manejan las respuestas de error HTTP de los servidores de microaplicaciones, o cómo manejar las microaplicaciones que responden muy lentamente; no queremos esperar para siempre para servir la página si una microaplicación no es respondiendo! Estos y otros temas los dejaremos para otro post.
La lógica de transformación de Yumcha macroapp index.html
podría implementarse fácilmente en forma de función lambda sin servidor, o como middleware para marcos de servidor como Express o Koa.
Control de microaplicaciones basado en stubs
Volviendo al lado del cliente, hay otro aspecto de cómo implementamos las microaplicaciones que es importante para la eficiencia, la carga diferida y el renderizado sin bloqueos. Podríamos generar la etiqueta iframe
para cada microaplicación, ya sea con un atributo src
, que hace otra solicitud de red, o con el atributo srcdoc
completado con el contenido que nos proporcionó el servidor. Pero en ambos casos, el código en ese iframe
se iniciará de inmediato, incluida la carga de todas sus secuencias de comandos y etiquetas de enlace, el arranque y cualquier llamada API inicial y procesamiento de datos relacionado, incluso si el usuario ni siquiera accede a la microaplicación en cuestión.
Nuestra solución a este problema es representar inicialmente las microaplicaciones en la página como pequeños stubs inactivos, que luego se pueden activar. La activación puede ser impulsada por la región de la microaplicación que aparece a la vista, utilizando la API IntersectionObserver
infrautilizada o, más comúnmente, por notificaciones previas enviadas desde el exterior. Por supuesto, también podemos especificar que la microapp se active inmediatamente.
En cualquier caso, cuando y solo cuando se activa la microaplicación, el iframe
se procesa y su código se carga y ejecuta. En términos de nuestra implementación usando LitElement, y asumiendo que el estado de activación está representado por una variable de instancia activated
, tendríamos algo como:
render() { if (!this.activated) return html`{this.placeholder}`; else return html` <iframe srcdoc="${this.content}" @load="${this.markLoaded}"></iframe>`; }
Comunicación entre microaplicaciones
Aunque las microaplicaciones que componen una macroaplicación están, por definición, poco acopladas, aún necesitan poder comunicarse entre sí. Por ejemplo, una microaplicación de navegación necesitaría enviar una notificación de que se debe activar otra microaplicación que acaba de seleccionar el usuario, y la aplicación que se va a activar necesita recibir dichas notificaciones.
De acuerdo con nuestra mentalidad minimalista, queremos evitar la introducción de una gran cantidad de maquinaria de transmisión de mensajes. En su lugar, en el espíritu de los componentes web, utilizaremos eventos DOM. Proporcionamos una API de transmisión trivial que notifica previamente todos los stubs de un evento inminente, espera a que se active cualquiera de los que hayan solicitado que se active ese tipo de evento y luego envía el evento contra el documento, en el que cualquier microaplicación puede escuchar eso. Dado que todos nuestros iframe
s tienen el mismo origen, podemos llegar desde el iframe
a la página y viceversa para encontrar elementos contra los cuales disparar eventos.
Enrutamiento
Hoy en día, todos esperamos que la barra de direcciones URL en los SPA represente el estado de visualización de la aplicación, de modo que podamos cortar, pegar, enviar mensajes de texto y vincularlos para saltar directamente a una página dentro de la aplicación. Sin embargo, en una aplicación de microinterfaz, el estado de la aplicación es en realidad una combinación de estados, uno para cada microaplicación. ¿Cómo vamos a representar y controlar esto?
La solución es codificar el estado de cada microaplicación en una sola URL compuesta y usar un pequeño enrutador de macroaplicaciones que sepa cómo juntar esa URL compuesta y separarla. Desafortunadamente, esto requiere una lógica específica de Yumcha en cada microaplicación: recibir mensajes del enrutador de la macroaplicación y actualizar el estado de la microaplicación y, a la inversa, informar al enrutador de la macroaplicación sobre los cambios en ese estado para que se pueda actualizar la URL compuesta. Por ejemplo, uno podría imaginar una YumchaLocationStrategy
para Angular o un elemento <YumchaRouter>
para React.
El caso sin iframe
Como se mencionó anteriormente, alojar microaplicaciones en iframe
tiene algunas desventajas. Hay dos alternativas: incluirlos directamente en línea en el HTML de la página o colocarlos en el shadow DOM. Ambas alternativas reflejan un poco los pros y los contras de iframe
s, pero a veces de diferentes maneras.
Por ejemplo, las políticas de CSP de microaplicaciones individuales tendrían que fusionarse de alguna manera. Las tecnologías de asistencia, como los lectores de pantalla, deberían funcionar mejor que con iframe
s, suponiendo que admitan el shadow DOM (que no todos lo hacen todavía). Debería ser sencillo organizar el registro de los trabajadores de servicio de una microaplicación mediante el concepto de trabajador de servicio de "ámbito", aunque la aplicación debería asegurarse de que su trabajador de servicio esté registrado con el nombre de la aplicación, no con "/"
. Ninguno de los problemas de diseño asociados con iframe
se aplica a los métodos DOM en línea o en la sombra.
Sin embargo, es probable que las aplicaciones creadas con marcos como Angular y React no estén felices de vivir en línea o en la sombra DOM. Para esos, es probable que queramos usar iframe
s.
Los métodos DOM en línea y en la sombra difieren cuando se trata de CSS. CSS se encapsulará limpiamente en el shadow DOM. Si por alguna razón quisiéramos compartir CSS externo con el shadow DOM, tendríamos que usar hojas de estilo construibles o algo similar. Con las microaplicaciones integradas, todo el CSS se compartiría en toda la página.
Al final, implementar la lógica para las microaplicaciones DOM en línea y en la sombra en <yumcha-portal>
es sencillo. Recuperamos el contenido de una microaplicación dada desde donde la lógica del servidor lo insertó en la página como un elemento HTML <template>
, lo clonamos y luego lo agregamos a lo que LitElement llama renderRoot
, que normalmente es el DOM oculto del elemento, pero puede también se establecerá en el elemento en sí ( this
) para el caso en línea (DOM sin sombra).
¡Pero espera! El contenido que ofrece el servidor de microaplicaciones es una página HTML completa. No podemos insertar la página HTML para la microaplicación, completa con las etiquetas html
, head
y body
, en el medio de la macroaplicación, ¿o sí?
Resolvemos este problema aprovechando una peculiaridad de la etiqueta de template
en la que se envuelve el contenido de la microaplicación recuperado del servidor de microaplicaciones. Resulta que cuando los navegadores modernos encuentran una etiqueta de template
, aunque no la "ejecutan", la analizan y, al hacerlo, eliminan el contenido no válido, como las etiquetas <html>
, <head>
y <body>
, preservando su contenido interno. Por lo tanto, se conservan las etiquetas <script>
y <link>
en <head>
, así como el contenido de <body>
. Esto es precisamente lo que queremos para insertar contenido de microaplicaciones en nuestra página.
Arquitectura de micro-frontend: el diablo está en los detalles
Los micro frontends se arraigarán en el ecosistema de las aplicaciones web si (a) resultan ser un mejor enfoque arquitectónico y (b) podemos descubrir cómo implementarlos de manera que satisfagan los innumerables requisitos prácticos de la web actual.
En cuanto a la primera pregunta, nadie afirma que las microfrontends sean la arquitectura adecuada para todos los casos de uso. En particular, habría pocas razones para que un solo equipo realice un desarrollo totalmente nuevo para adoptar micro interfaces. Dejaré la pregunta de qué tipos de aplicaciones en qué tipos de contextos podrían beneficiarse más de un patrón de micro-frontend para otros comentaristas.
En términos de implementación y viabilidad, hemos visto que hay muchos detalles de los que preocuparse, incluidos varios que ni siquiera se mencionan en este artículo, en particular, autenticación y seguridad, duplicación de código y SEO. No obstante, espero que este artículo presente un enfoque de implementación básico para micro frontends que, con más refinamiento, pueda hacer frente a los requisitos del mundo real.
Bibliografía
- Micro extremos delanteros — Haciéndolo estilo angular — Parte 1
- Micro extremos delanteros — Haciéndolo estilo angular — Parte 2
- Evolución de una aplicación AngularJS usando microfrontends
- Micro-frontends
- Microservicios de interfaz de usuario: invertir el antipatrón (micro frontends)
- Microservicios de interfaz de usuario: ¿un antipatrón?
- La creación de páginas con Micro-Frontends adopta un enfoque similar al de Yumcha de proxy inverso y SSI, que recomiendo encarecidamente.
- Recursos de micro-frontends
- Podio
- No entiendo los micro-frontends. Esta es una descripción general bastante buena de los tipos de arquitecturas de micro-frontend y casos de uso.
- Micro-frontends sin servidor usando Vue.js, AWS Lambda e Hypernova
- Micro Frontends: una excelente y completa descripción general.