Gerenciamento de Cache para Microaplicativos Qiankun em Abas de Navegação

Este artigo detalha uma abordagem para implementar o cache de páginas de microaplicativos Qiankun quando eles são exibidos em abas de navegação, com o objetivo de melhorar a experiência do usuário e o desempenho em aplicações web complexas.

Contexto e Desafios

Em projetos que utilizam frameworks como Jeecg-Boot, a crescente base de código em módulos individuais pode levar a tempos de compilação lentos e dificuldades no gerenciamento de branches. A adoção de uma arquitetura de microfrontends com Qiankun surge como uma solução para isolar e gerenciar esses módulos como aplicações independentes. O Jeecg-Boot já integra o Qiankun, facilitando a transição. Inicialmente, a configuração via registerMicroApps foi utilizada para o registro automático.

No entanto, com o tempo, surgiu a necessidade de um comportamento específico: quando um usuário alterna entre abas de navegação, as páginas dos microaplicativos devem ser mantidas em cache. Ao fechar uma aba, o cache associado a essa aba deve ser removido. Se o usuário acessar a página novamente a partir do menu, ela deve ser recarregada.

Soluções encontradas online para implementar cache com registerMicroApps, como as descritas em [referência 1] e [referência 2], apresentaram limitações, especialmente quando um único microaplicativo precisava gerenciar o cache de múltiplas páginas. Isso levou à exploração de uma abordagem alternativa utilizando loadMicroApp.

Implementação com loadMicroApp

Aplicação Principal

  1. Modificação em apps.js:

    A configuração das aplicações é ajustada para definir entradas e contêineres específicos para cada microaplicativo.

    
    const microAppsConfig = [
     {
       name: 'appOne',
       entry: process.env.NODE_ENV === 'development' ? 'http://localhost:8081/' : document.querySelector('html').dataset.appOneUrl,
       container: '#microAppContainerOne',
       activeRule: '/appOne', // Regra de roteamento para ativar o microapp
       sandbox: {
         strictStyleIsolation: true // Habilita isolamento de estilo
       }
     },
     {
       name: 'appTwo',
       entry: process.env.env === 'development' ? 'http://localhost:8082/' : document.querySelector('html').dataset.appTwoUrl,
       container: '#microAppContainerTwo',
       activeRule: '/appTwo', // Regra de roteamento para ativar o microapp
       sandbox: {
         strictStyleIsolation: true // Habilita isolamento de estilo
       }
     }
    ];
    
    
  2. Modificação em index.js:

    A função para carregar os microaplicativos é adaptada para usar loadMicroApp, permitindo um controle mais granular.

    
    import { loadMicroApp } from 'qiankun';
    import { microAppsConfig } from './apps';
    import { getSharedProps, initializeGlobalState } from './stateManager';
    import { prefetchMicroApps } from 'qiankun';
    
    // Pré-carrega os microaplicativos para otimização
    prefetchMicroApps(microAppsConfig);
    
    /**
    * Carrega e inicializa um microaplicativo.
    * @param {object} appConfig - Configuração do microaplicativo.
    * @returns {object} O objeto loader do microaplicativo.
    */
    function initializeMicroApp(appConfig) {
     const microAppLoader = loadMicroApp({
       ...appConfig,
       props: {
         ...getSharedProps(),
       }
     }, {
       sandbox: {
         experimentalStyleIsolation: true, // Modo sandbox experimental
       }
     });
     // Inicializa o estado global para comunicação
     initializeGlobalState();
     return microAppLoader;
    }
    
    export default initializeMicroApp;
    
    
  3. Modificação em stateManager.js:

    Gerencia o estado global e a comunicação entre a aplicação principal e os microaplicativos.

    
    import { initGlobalState } from 'qiankun';
    import appStore from '../store'; // Assumindo que 'store' é o Vuex store
    import Vue from 'vue';
    import { TOKEN_KEY, USERNAME_KEY } from '@/store/mutationTypes'; // Constantes de mutação
    
    // Dados públicos a serem passados para os microaplicativos
    export function getSharedProps() {
     return {
       publicData: {
         basePath: process.env.BASE_URL,
         authToken: Vue.ls.get(TOKEN_KEY)
       }
     };
    }
    
    /**
    * Configura o estado global e os mecanismos de comunicação.
    */
    export function initializeGlobalState() {
     const initialState = {
       currentUser: Vue.ls.get(USERNAME_KEY),
       isLoggedIn: true,
       closeCurrentTab: false,
       tabUpdateTrigger: 0,
       approvalDetails: '',
     };
    
     const actions = initGlobalState(initialState);
    
     actions.setGlobalState(initialState);
    
     actions.onGlobalStateChange((newState, previousState) => {
       if (!newState.isLoggedIn) {
         appStore.dispatch('userLogout').then(() => {
           window.location.reload();
         });
       }
       if (newState.closeCurrentTab) {
         appStore.dispatch('setTabCloseAction', true);
         actions.setGlobalState({ closeCurrentTab: false });
       }
     });
    
     // Disponibiliza as ações de comunicação globalmente via $actions
     Vue.prototype.$actions = actions;
    }
    
    
  4. Modificação em main.js:

    Controla o ciclo de vida dos microaplicativos com base nas mudanças de rota e gerencia o cache das abas.

    
    import { unmountMicroApps } from 'qiankun'; // Importa a função de desmontar
    import initializeMicroApp from './index'; // Assumindo que initializeMicroApp está exportado de index.js
    import { microAppsConfig } from './apps';
    import appStore from '../store';
    import Vue from 'vue';
    import { CACHED_ROUTES_KEY, SUB_APP_ROUTES_MAP_KEY } from '@/utils/cacheConstants'; // Constantes para cache
    
    let activeMicroApps = {}; // Objeto para rastrear os microaplicativos ativos
    
    router.beforeEach((to, from, next) => {
     const matchedAppConfig = microAppsConfig.find(app => to.path.startsWith(app.activeRule));
    
     if (matchedAppConfig) {
       appStore.dispatch('setQiankunActiveState', true);
       const cachedMicroApp = activeMicroApps[matchedAppConfig.name];
    
       if (cachedMicroApp) {
         // Microaplicativo já está carregado e em cache
         next();
         return;
       }
    
       // Carrega o microaplicativo se não estiver em cache
       activeMicroApps[matchedAppConfig.name] = initializeMicroApp({ ...matchedAppConfig });
       next();
     } else {
       // Desmonta todos os microaplicativos se a rota não corresponder a nenhum
       performMicroAppUnmount();
       appStore.dispatch('setQiankunActiveState', false);
       next();
     }
    });
    
    /**
    * Desmonta microaplicativos com base nas configurações de cache das abas.
    */
    export function performMicroAppUnmount () {
     const cachedIncludedRoutes = Vue.ls.get(CACHED_ROUTES_KEY) || [];
     const subAppRoutesMap = Vue.ls.get(SUB_APP_ROUTES_MAP_KEY) || {};
    
     for (const appName in activeMicroApps) {
       const routesForApp = subAppRoutesMap[appName] || [];
       let isAnyRouteCached = false;
       cachedIncludedRoutes.forEach(cachedRoute => {
         if (routesForApp.includes(cachedRoute)) {
           isAnyRouteCached = true;
         }
       });
    
       // Se nenhuma rota deste subaplicativo estiver marcada para cache, desmonte-o
       if (!isAnyRouteCached) {
         activeMicroApps[appName].unmount();
         delete activeMicroApps[appName];
       }
     }
    }
    
    
  5. Gerenciamento de Fechamento de Abas:

    Quando uma aba é fechada, a função performMicroAppUnmount deve ser invocada para remover o cache do microaplicativo correspondente, a menos que outras abas desse mesmo microaplicativo permaneçam abertas e em cache.

Microaplicativo

  1. Resolução de Conflitos de Rota:

    No ponto de entrada de cada microaplicativo (por exemplo, main.js do subaplicativo), adicione código para garantir que o roteamento do microaplicativo não entre em conflito com o da aplicação principal. Isso geralmente envolve configurar o prefixo de roteamento do microaplicativo para corresponder à sua regra de ativação na aplicação principal.

Essas modificações permitem um cnotrole mais refinado sobre o carregamento e o descarregamento de microaplicativos, habilitando o cache seletivo de páginas em abas e a limpeza adequada quando as abas são fechadas.

Tags: qiankun microfrontends javascript Vue.js cache

Publicado em 9-24 21:13