微前端之实践应用间的全局状态管理、应用缓存和预加载子应用

一、微前端之实践应用间的全局状态管理、应用缓存和预加载子应用

  1. 全局状态管理,应用间的全局 store,如下所示:
  • micro 下的 storeindex.js,对外暴露 createStore,使用 store 管理 initDataobservers 管理所有的订阅者和依赖,通过 getStore 获取 store,通过 update 更新 store。当 store 发生变化,通知订阅者,执行 store 的操作,进行缓存,将 store 更新为 value,通知所有的订阅者,监听 store 的变化。subscribe 是添加订阅者,index.js,代码如下:
export const createStore = (initData = {}) => (() => { 
  let store = initData; 
  const observers = []; 

  const getStore = () => store;
  const update = (value) => {
    if (value !== store) {
      const oldValue = store;
      store = value;
      observers.forEach(async item => await item(store, oldValue));
    }
  }
  const subscribe = (fn) => {
    observers.push(fn);
  }

  return {
    getStore,
    update,
    subscribe,
  }
})()
  • 在主应用 mainutilindex.js,通过 createStore 创建全局状态管理,以 getStore 获取到存的所有 store 数据。通过 window.storestore 挂载到 window 上,通过 store.subscribe 添加订阅者。通过 store.update 更新 store 数据,将之前的 store 数据和所要修改的数据进行合并修改,index.js,代码如下:
import { registerMicroApps, start, createStore } from '../../micro'
import { loading } from '../store'

const store = createStore();
const storeData = store.getStore();
window.store = store;
store.subscribe((newValue, oldValue) => {
  console.log(newValue, oldValue, '---')
})
store.update({ ...storeData, a: 1 });

export const registerApp = (list) => {
  registerMicroApps(list, {
    beforeLoad: [
      () => {
        loading.changeLoading(true)
        console.log('开始加载')
      }
    ],
    mounted: [
      () => {
        loading.changeLoading(false)
        console.log('渲染完成')
      }
    ],
    destoryed: [
      () => {
        console.log('卸载完成')
      }
    ]
  })
  start()
}
  • vue3 子应用中的 main.js,在 mount 生命周期中,通过 window.store.getStore 获取到 store 里面的数据,通过 window.store.update 修改 store 里面的数据,main.js,代码如下:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { setMain } from './utils/global'

let instance = null; 
function render() {
  instance = createApp(App);
  instance
    .use(router)
    .mount('#app');
}

if (!window.__MICRO_WEB__) {
  render();
}
export async function bootstrap() {
  console.log('vue3.0 app bootstrap');
}

export async function mount(app) {
  setMain(app);
  // window.custom.emit('test1', {a: 1});
  // window.custom.on('test1', () => {
  //   window.custom.emit('test2', { b: 2 });
  // });
  const storeData = window.store.getStore();
  window.store.update({ ...storeData, a: 11 });
  render();
}

export async function unmount(ctx) {
  instance.unmount();
  instance = null;
  const { container } = ctx;
  if (container) {
    document.querySelector(container).innerHTML = '';
  }
}
  1. 提高加载性能,应用缓存,如下所示:
  • micro 下的 loaderindex.js,在 parseHtml 解析 html 时,使用 cache,根据子应用的 name 来做缓存。通过 cache[name] 判断是否命中 name,使用缓存,返回对应的内容。同时,将 dom、allScript 直接缓存,后面可以直接使用 cache,获取到对应的子应用,代码如下:
const cache = {}; 
export const parseHtml = async (entry, name) => {
  if (cache[name]) {
    return cache[name];
  }
  const html = await fetchResource(entry);
  let allScript = [];
  const div = document.createElement('div');
  div.innerHTML = html;
  const [dom, scriptUrl, script] = await getResources(div, entry);
  const fetchedScripts = await Promise.all(scriptUrl.map(async item => fetchResource(item)));

  allScript = script.concat(fetchedScripts);
  cache[name] = [dom, allScript];
  return [dom, allScript];
}
  1. 提高加载性能,预加载子应用,如下所示:
  • micro 下的 loaderprefetch.js,在 prefetch 中,先获取到所有子应用列表,不包括当前正在显示的。然后,通过 Promise.all 预加载剩下的所有子应用,prefetch.js,代码如下:
import { getList } from '../const/subApps';
import { parseHtml } from './index';

export const prefetch = async () => {
  const list = getList().filter(item => !window.location.pathname.startsWith(item.activeRule));
  await Promise.all(list.map(async item => await parseHtml(item.entry, item.name)));
}
  • micro 下的 start.js 中,通过 currentApp 渲染要加载的子应用,然后通过 prefetch 预加载剩下的所有子应用,但是不显示,代码如下:
import { setList, getList } from './const/subApps'
import { currentApp } from './utils'
import { rewriteRouter } from './router/rewriteRouter'
import { setMainLifecycle } from './const/mainLifeCycle'
import { prefetch } from './loader/prefetch'
import { Custom } from './customevent'

const custom = new Custom();
custom.on('test', (data) => {
  console.log(data);
});
window.custom = custom;

rewriteRouter();
export const registerMicroApps = (appList, lifeCycle) => {
  setList(appList);
  setMainLifecycle(lifeCycle);
  // window.appList = appList;
}

export const start = () => {
  const apps = getList();
  if (!apps.length) {
    throw Error('子应用列表为空, 请正确注册');
  }
  const app = currentApp();
  const { pathname, hash } = window.location;

  if (!hash) {
    window.history.pushState(null, null, '/vue3#/index');
  }

  if (app && hash) {
    const url = pathname + hash;
    window.__CURRENT_SUB_APP__ = app.activeRule;
    window.history.pushState('', '', url);
  }

  prefetch();
}

你可能感兴趣的:(Vue,微前端,应用间的全局状态管理,应用缓存和预加载子应用)