Practica compartir microfrontends

archivo

Este artículo se publicó por primera vez en: https://github.com/bigo-frontend/blog/ Bienvenido a seguirlo y volver a publicarlo.

Practica compartir microfrontends

escena de demanda

La plataforma de gestión de servicios Brpc quiere integrar las funciones del proyecto de código abierto Jaeger (sistema de seguimiento de enlaces distribuidos), construir su propia plataforma de cadena de llamadas y facilitar a los usuarios que utilizan el marco Brpc consultar sus propias cadenas de llamadas de servicios, y sobre esta base , desarrollo secundario, acceso Con la función del sistema de registro distribuido de la empresa, los usuarios pueden ver fácilmente rastros comerciales y registros comerciales en esta plataforma, captar información relevante y localizar problemas rápidamente.

Por qué microfrontends

¿Por qué no desarrollar el tuyo propio?

Los requisitos son básicamente los mismos que los de las funciones estándar de los proyectos de código abierto. Una simple estimación del tiempo de desarrollo muestra que nos llevará al menos un mes desarrollarlos todos nosotros mismos.

¿Por qué no marco flotante?

  1. Las URL no están sincronizadas. El navegador actualiza el estado de la URL del iframe y lo pierde, y los botones de avance y retroceso no se pueden utilizar.
  2. La interfaz de usuario no está sincronizada y la estructura DOM no se comparte. Imagine un cuadro de viñetas con una capa de máscara en el iframe en la esquina inferior derecha de la pantalla. Al mismo tiempo, requerimos que el navegador muestre el cuadro de viñetas en el centro y lo centre automáticamente cuando el navegador cambie de tamaño.
  3. El contexto global está completamente aislado y las variables de memoria no se comparten. Para los requisitos de comunicación y sincronización de datos de los sistemas internos y externos del iframe, la cookie de la aplicación principal debe transmitirse de forma transparente a las subaplicaciones con diferentes nombres de dominio raíz para lograr el efecto de evitar el inicio de sesión.
  4. lento. Cada entrada de subaplicación es un proceso de reconstrucción del contexto del navegador y recarga de recursos.

https://www.yuque.com/kuitos/gky7yw/gesexv

¿Por qué no simplemente mover el código?

El proyecto también está desarrollado en base a reaccionar y antd. Sin embargo, si el código se mueve directamente, el código es fácilmente inaceptable, incluido el uso de redux, el método de interceptación de api, etc., los dos sistemas son autónomos; por otro lado, no es conveniente para actualizaciones posteriores. , Suponiendo que el proyecto de código abierto haya realizado una actualización importante, y si necesitamos sus funciones nuevamente, debemos mover el código.

Utilice micro frontend-qiankun

Según los problemas anteriores, el micro-frontend es una solución relativamente buena. El concepto de micro-frontend es el siguiente:

  1. Alto aislamiento: la aplicación principal y las subaplicaciones se ejecutan en entornos sandbox sin afectarse entre sí, y las pilas de tecnología de las aplicaciones también pueden ser diferentes, de modo que las pilas de tecnología son independientes.
  2. Bajo acoplamiento: cada aplicación se puede desarrollar, implementar y acceder de forma independiente.
  3. Alta escalabilidad: las subaplicaciones son fáciles de conectar y desconectar y se pueden expandir de manera flexible.
  4. Baja intrusión: ya sea la aplicación principal o la subaplicación, la cantidad de código intrusivo es muy pequeña y el costo de acceso es bajo.

Yo uso qiankun , las ventajas de esta solución son las siguientes:

  1. La plataforma de gestión de servicios Jaeger y brpc se pueden desarrollar e implementar de forma independiente sin afectarse entre sí.
  2. Jaeger está integrado en la plataforma de gestión de servicios brpc como un subproyecto y puede compartir cas.
  3. Los problemas existentes en iframe pueden resolverse bien mediante microfrontends. Por ejemplo, comunicación de aplicaciones, qiankun tiene su propia API de comunicación de aplicaciones; almacenamiento en caché de recursos, los recursos solo deben cargarse una vez; el uso de las funciones de avance y retroceso del navegador no causará pérdida de estado, etc.
  4. Ahorre tiempo de desarrollo, utilice micro front-end, basado en desarrollo secundario de código abierto, desde el plan de investigación hasta la implementación, el tiempo total es de poco más de una semana.

acceso qiankun

Al observar la documentación, en comparación con el método de acceso convencional, se utiliza un proyecto en blanco como aplicación principal, que a menudo se denomina aplicación base, y se activan diferentes subaplicaciones monitoreando el conmutador de enrutamiento.

Pero mi escenario de demanda es relativamente especial. Utilizo la plataforma de gestión de servicios Brpc como aplicación principal y Jaeger como microaplicación. Al monitorear el interruptor de enrutamiento, la plataforma de cadena de llamadas de Jaeger se activa e integra en el área de representación de contenido de La aplicación principal.

imagen-20210708205110957

API principal

// 注册微应用
registerMicroApps(apps, lifecycles);
// apps - Array<RegistrableApp> - 必选,微应用的一些注册信息
// lifeCycles - LifeCycles - 可选,全局的微应用生命周期钩子

// 添加全局异常捕获
addGlobalUncaughtErrorHandler(errHandle)

// 启动qiankun
start()

API detallada: qiankun-API

Configuración de la aplicación principal

  • Registre la microaplicación e inicie qiankun.
// 配置文件
import * as NProgress from "nprogress";

export const TRACE_JAEGER_ENTRY =
  process.env.NODE_ENV === "development"
    ? "http://localhost:3001"
    : `${window.location.origin}/trace`;

export const TRACE_JAEGER_NAME = "micro-app-jaeger";

export const MAIN_CONTENT_AREA_ID = "main-app-content";

export const MICRO_APPS = [
  {
    name: TRACE_JAEGER_NAME,
    entry: TRACE_JAEGER_ENTRY,
    container: `#${MAIN_CONTENT_AREA_ID}`,
    activeRule: "/jaeger",
  },
];

export const LIFE_CYCLES = {
  // qiankun 生命周期钩子 - 微应用加载前
  beforeLoad: () => {
    // 加载微应用前,加载进度条
    NProgress.start();
    return Promise.resolve();
  },
  // qiankun 生命周期钩子 - 微应用挂载后
  afterMount: () => {
    // 加载微应用前,进度条加载完成
    NProgress.done();
    return Promise.resolve();
  },
};


// index.tsx

// 注册微应用
registerMicroApps(MICRO_APPS, LIFE_CYCLES);

/**
 * 添加全局的未捕获异常处理器
 */
addGlobalUncaughtErrorHandler((event: Event | string) => {
  const { message: msg } = event as any;
  // 加载失败时提示
  if (msg && msg.includes("died in status LOADING_SOURCE_CODE")) {
    message.error("微应用加载失败,请检查应用是否可运行!");
  }
});

// 启动qiankun
start();
  • Se agregó un punto de montaje de microaplicación en el área de contenido.
// App.tsx
const App: React.FC<IProps> = ({ history }) => {
  return (
    <Layout style={
   
   { maxHeight: "100vh" }}>
      <Sider collapsed={collapsed}>
        <Menu
          theme="dark"
          selectedKeys={[menuKey]}
          defaultOpenKeys={menuOpenKeys}
          mode="inline"
          onClick={onClikcMenus}
        >
          主应用menu菜单栏
        </Menu>
      </Sider>
      <Layout className="site-layout">
        <Header className="site-layout-header">header</Header>
        <Content>
          {/** 组件渲染区域 */}
          <div className="site-layout-content">
            {/** 微前端挂载点 */}
            <div id={MAIN_CONTENT_AREA_ID} />
            <Switch>
              <Route exact path="/" component={Service} />
            </Switch>
          </div>
        </Content>
        <Footer className="site-layout-footer">
          {`BIGO © 2020~${new Date().getFullYear()} 基础架构团队`}
        </Footer>
      </Layout>
    </Layout>
  );
};
export default withRouter(App);
  • aislamiento estilo antd

Los estilos entre las microaplicaciones están aislados, pero de forma predeterminada, existe un conflicto entre la aplicación principal y la microaplicación, que debe resolverse manualmente. Solución: configure el prefijo prefixCls para el estilo de la aplicación principal.

El nombre de clase del nodo DOM del componente antd inserta el prefijo:

// index.tsx

//设置 Modal、Message、Notification rootPrefixCls。(4.13.0+)
ConfigProvider.config({
  prefixCls: "main-app",
});

// 设置其余组件、icon 的rootPrefixCls。
<ConfigProvider
  prefixCls="main-app"
  iconPrefixCls="main-app"
  locale={zhCN}
>
  <App />
</ConfigProvider>

Al ejecutar o empaquetar, agregue un prefijo al nombre de clase en el archivo de estilo:

// craco.config.js,主应用使用 craco,注入webpack配置。
// 新增配置
const CracoLessPlugin = require("craco-less");
plugins: [
    {
    
    
      plugin: CracoLessPlugin,
      options: {
    
    
        lessLoaderOptions: {
    
    
          lessOptions: {
    
    
            javascriptEnabled: true,
            modifyVars: {
    
    
                "@ant-prefix": "main-app",
              	"@iconfont-css-prefix": "main-app"
            },
          },
        },
      },
    },
  ],

Configuración de subaplicaciones

  • Modifique la identificación del nodo raíz.
// index.html,修改root节点id,防止冲突
<div id="micro-app"></div>
  • Configure la ruta pública en tiempo de ejecución para garantizar que las direcciones de los scripts, estilos e imágenes cargadas dinámicamente por las microaplicaciones sean correctas.
// src目录下,新建 public-path.js 文件
/* eslint-disable camelcase */
if (window.__POWERED_BY_QIANKUN__) {
    
    
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  • Modifique el método de representación de la aplicación y agregue un ciclo de vida de microaplicación
// index.js

// 在微应用顶部引入publicPath
import './public-path';

import React from 'react';
import {
    
     BrowserRouter } from 'react-router-dom';
import ReactDOM from 'react-dom';

import JaegerUIApp from './components/App';

const UI_ROOT_ID = "#micro-app";

function render(props) {
    
    
  const {
    
     container } = props;
  ReactDOM.render(
    <BrowserRouter>
      <JaegerUIApp />
    </BrowserRouter>,
    container ? container.querySelector(UI_ROOT_ID) : document.querySelector(UI_ROOT_ID)
  );
}

// 支持独立访问
if (!window.__POWERED_BY_QIANKUN__) {
    
    
  render({
    
    });
}

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap() {
    
     }

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
    
    
  render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount(props) {
    
    
  const {
    
     container } = props;
  if(container){
    
    
    ReactDOM.unmountComponentAtNode(container.querySelector(UI_ROOT_ID));
  }
}

  • configuración del paquete web
// 微应用 webpack 配置// config-overrides.js,微应用使用的是customize-cra,注入webpack配置。// 新增配置function webpack(_config) {  let config = _config;  // 微应用包,`${packageName}-[name]`.func()调用微应用方法。  config.output.library = `${packageName}-[name]`;  //umd通用规范,将 library 暴露为所有的模块定义下都可运行的方式。它将在 CommonJS, AMD 环境下运行,或将模块导出到 global 下的变量。  config.output.libraryTarget = 'umd';  // 用于异步加载(async loading)chunk的JSONP函数  config.output.jsonpFunction = `webpackJsonp_${packageName}`;  // 当输出为 library 时,尤其是当 libraryTarget 为 'umd'时,此选项将决定使用哪个全局对象来挂载 library。  config.output.globalObject = 'window';  return config;}const devServerConfig = () => config => {  return {    ...config,    headers: {      // 开发环境跨域处理      'Access-Control-Allow-Origin': '*',    },  };};module.exports = {   webpack,  devServer: overrideDevServer(devServerConfig())};

desplegar

Nginx configura las rutas de la aplicación principal y de las subaplicaciones de la siguiente manera:

server {        
    listen   80;        
    server_name  domain.test.com;        
    location / {            
        root /path/service_fe;           
        try_files $uri $uri/ /index.html;           
        index index.html;        
    }        
    location /trace {           
        alias /path/jaeger_fe/;           
        try_files $uri $uri/ /index.html;           
        index index.html;        
    }
}

principio qiankun

Qiankun se desarrolla en base a single-spa , que estipula el ciclo de vida de aplicaciones y paquetes, y programa el proceso de rotación del ciclo de vida de aplicaciones y paquetes (mecanismo de coincidencia de enrutamiento). En cuanto a la función de carga de la aplicación y el paquete, la estrategia de coincidencia de enrutamiento y su función de ciclo de vida, el desarrollador la implementa manualmente. Sobre la base de un solo spa, qiankun optimiza la experiencia del usuario, amplía las funciones y proporciona una API lista para usar para facilitar el acceso.

Principio de acceso a la aplicación

Utilice import-html-entry, el marco principal puede obtener los recursos estáticos de la subaplicación a través de buscar html y, al mismo tiempo, insertar el documento HTML como un nodo secundario en el contenedor del marco principal. Cuando se activa la subaplicación, se llama al método importEntry:

const {
    
     template, execScripts, assetPublicPath } = await importEntry(  entry,  importEntryOpts);

que devuelve tres campos

  • plantilla: la cadena de plantilla html procesada, los archivos de estilo fuera de línea se reemplazan con estilos en línea y luego la plantilla se agrega a la aplicación principal mediante operaciones DOM.
  • execScripts: ejecute el método execScripts para obtener los métodos del ciclo de vida exportados por la microaplicación y, por cierto, también resuelva el problema de la contaminación global de JS, porque el contexto de ejecución de JS se puede especificar a través del parámetro proxy al ejecutar el método execScripts. . Cuando se ejecuta la función execScripts(scripts, fetch, error), obtiene el contenido de todos los scripts externos especificados, es decir, scripts, y establece el contexto de ejecución global de cada script, y luego lo ejecuta a través de la función eval.
  • activoPublicPath: URL base de recursos estáticos.

principio de aislamiento

aislamiento css

qiankun proporciona 3 modos para lograr aislamiento de estilo con diferentes efectos:

  1. Hoja de estilo de carga dinámica (predeterminada) : este modo es cargar directamente todos los estilos de la subaplicación en el nodo DOM montado por la subaplicación, de modo que cuando se desinstale la subaplicación, elimine el nodo DOM y pueda Elimina automáticamente el CSS utilizado por las subaplicaciones. De forma predeterminada, el entorno sandbox puede garantizar el aislamiento de estilo entre subaplicaciones en escenarios de instancia única, pero no puede garantizar el aislamiento de estilo entre la aplicación principal y las subaplicaciones, o subaplicaciones en escenarios de múltiples instancias.

  2. Aislamiento de estilo Shadow DOM : configuración sandbox.strictStyleIsolation = true, este modo significa habilitar el modo de aislamiento de estilo estricto. En este modo, qiankun envolverá un nodo Shadow Dom para cada contenedor de microaplicaciones , para garantizar que el estilo de la microaplicación no afecte la situación general.

  3. Aislamiento de estilo CSS con alcance (solución experimental) : la configuración en el código es sandbox.experimentalStyleIsolation = true. Principio básico: reescribir el estilo agregado por la subaplicación Agregue una regla de selección especial a todas las reglas de estilo para limitar su alcance de influencia, similar al ámbito de vue, la hoja de estilo de la aplicación aislada se reescribirá mediante reglas específicas en el siguiente modo : Supongamos que la
    aplicación se llama reaccionar16.

  app-main {
    
      font-size: 14px;}

  div[data-qiankun-react16] .app-main {
    
      font-size: 14px;}

Por qué qiankun utiliza de forma predeterminada la primera opción:

Si se utilizan la segunda y tercera opciones, algunos componentes pueden cruzar el límite de sombra hacia el árbol de documentos externo para insertar nodos, y los estilos de estos nodos se perderán; por ejemplo, antd representará los nodos en , lo que provocará que el Modalestilo ducument.bodysea perdido; pero otra biblioteca de componentes, o parte de su código, sufrirán el mismo problema y necesitarán procesamiento adicional.

Algunos efectos de comparación son los siguientes:

imagen-20210717143619476

imagen-20210717143921505

aislamiento js

Para lograr el aislamiento de js, el marco qiankun proporciona tres entornos sandbox para diferentes escenarios, a saber snapshotSandbox, legacySandbox, y proxySandbox.

legacySandbox, proxySandboxse implementan en base a ES6 Proxy.

  • Zona de pruebas de instantáneas (snapshotSandbox): el navegador IE utiliza esta zona de pruebas de forma predeterminada. Porque IE no lo admite Proxy. El principio de esta zona de pruebas es crear una instantánea de la ventana base cuando se inicia la subaplicación y almacenarla en una variable. La operación de ventana de la subaplicación es esencialmente una operación en esta variable. SnapshotSandboxTambién guardará la modificación durante la ejecución de la subaplicación en modifyPropsMap, para que pueda restaurarse cuando se cree y destruya la subaplicación. Ventajas y desventajas: Contaminará la ventana.
  • Proxy Sandbox (legacySandbox): legacySandboxse establecen tres parámetros para registrar variables globales, que son registrar nuevas variables globales en el sandbox addedPropsMapInSandbox, registrar variables globales actualizadas en el sandbox modifiedPropsOriginalValueMapInSandboxy registrar continuamente variables globales actualizadas (nuevas y modificadas). Se utiliza para tomar instantáneas. en cualquier momento currentUpdatedPropsValueMap. Ventajas y desventajas: también contaminará la ventana, pero el rendimiento es mejor que el entorno limitado de instantáneas y no es necesario atravesar el objeto de la ventana.
  • Proxy Sandbox (proxySandbox): después de activar el sandbox, cada windowvez que verifique el valor, primero lo buscará desde el interior de su propio entorno sandbox fakeWindow. Si no existe, lo buscará desde rawWindow(externo ); cuando Cuando se asigna el objeto, será operado directamente sin afectarlo . Ventajas y desventajas: no afectará a la ventana.windowwindowfakeWindowrawWindow

Principios de comunicación y enrutamiento

Principio de comunicación

Qiankun proporciona internamente initGlobalStateun método para registrar MicroAppStateActionsuna instancia para la comunicación, que tiene tres métodos, a saber:

  • setGlobalState: Al establecer globalStateun nuevo valor, se realizará una comparación superficial internamente y, si globalStatese detecta un cambio, se activará una notificación para notificar a todas las funciones del observador.
  • onGlobalStateChange(state, prev): Registre una función de observador, responda a globalStatelos cambios en y globalStateactive la función de observador cuando se produzcan cambios.
  • offGlobalStateChange: Cancele la función de observador, la instancia ya no responde a globalStatelos cambios y se llamará de forma predeterminada cuando se desmonte la microaplicación.
imagen-20210717150912156

globalStatePodemos ver en la figura anterior que primero podemos registrar observadores en el grupo de observadores y luego activar todas las funciones de observadores modificando para lograr el efecto de comunicación entre componentes.

principio de enrutamiento

La ruta del navegador será secuestrada dentro de single-spa, y todos los métodos de enrutamiento y eventos de enrutamiento deben ingresar primero a single-spa para una programación unificada. Para qiankun, el secuestro de rutas se realiza en un solo spa, y las capacidades proporcionadas por qiankun son principalmente la carga de subaplicaciones y el aislamiento de la zona de pruebas.

window.addEventListener("hashchange", urlReroute);
window.addEventListener("popstate", urlReroute);

Resumir los escenarios aplicables de microfrontends.

Desacoplamiento y división de aplicaciones

Divida la aplicación Jushi en varias aplicaciones que se puedan desarrollar, implementar y acceder de forma independiente.

agregación de aplicaciones

Agregue las entradas de aplicaciones que están asociadas con varias funciones, de modo que las funciones de la aplicación estén más cerca y el proceso de operación sea más fluido, sin tener que saltar hacia adelante y hacia atrás entre diferentes pestañas del navegador.

Aplicar refactorización incremental

Supongamos que hay una aplicación megalith y desea dividirla y refactorizarla de acuerdo con los módulos funcionales, puede desarrollar subaplicaciones de acuerdo con los módulos funcionales, insertarlas en la aplicación principal después del desarrollo y reemplazar los módulos originales.

cita

documento qiankun

El principio y la práctica de qiankun, un marco de micro-front-end

Texto largo de mil caracteres + imágenes y textos + análisis completo del código fuente de qiankun del marco de micro-front-end - artículos de qiankun

Arriba, si hay algún error, corríjame ~

Bienvenidos a todos a dejar un mensaje para discutir. ¡Les deseo un buen trabajo y una vida feliz!

Soy el front-end de bigo, nos vemos en el próximo número.

Supongo que te gusta

Origin blog.csdn.net/yeyeye0525/article/details/122672368
Recomendado
Clasificación