微前端之实践应用间的全局状态管理、应用缓存和预加载子应用
一、微前端之实践应用间的全局状态管理、应用缓存和预加载子应用
- 全局状态管理,应用间的全局
store
,如下所示:
- 在
micro
下的store
中index.js
,对外暴露createStore
,使用store
管理initData
,observers
管理所有的订阅者和依赖,通过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,}
})()
- 在主应用
main
的util
中index.js
,通过createStore
创建全局状态管理,以getStore
获取到存的所有store
数据。通过window.store
将store
挂载到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 = '';}
}
- 提高加载性能,应用缓存,如下所示:
- 在
micro
下的loader
中index.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];
}
- 提高加载性能,预加载子应用,如下所示:
- 在
micro
下的loader
中prefetch.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();
}
微前端之实践应用间的全局状态管理、应用缓存和预加载子应用
一、微前端之实践应用间的全局状态管理、应用缓存和预加载子应用
- 全局状态管理,应用间的全局
store
,如下所示:
- 在
micro
下的store
中index.js
,对外暴露createStore
,使用store
管理initData
,observers
管理所有的订阅者和依赖,通过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,}
})()
- 在主应用
main
的util
中index.js
,通过createStore
创建全局状态管理,以getStore
获取到存的所有store
数据。通过window.store
将store
挂载到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 = '';}
}
- 提高加载性能,应用缓存,如下所示:
- 在
micro
下的loader
中index.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];
}
- 提高加载性能,预加载子应用,如下所示:
- 在
micro
下的loader
中prefetch.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();
}
发布评论