enhancementgood first issue
Description
Background
目前使用qiankun2.x的版本,业务提出需求在发布新的版本时候,期望可以不刷新页面(主应用暂时不考虑)进行该系统的热重载。类似于pc端的热更新,期望qiankun可以导出unload方法,完全销毁app的生命周期,业务系统再次将其重载。
Proposal
- 翻看源码发现不能热更新的原因是因为
import-html-entry中缓存了embedHTMLCache qiankun在importEntry时,如果已经获取过html资源,每次获取的都是内存中的html,以至于script & style也是缓存的- 我的解决方案是,在import-html-entry中导出根据app去清除缓存的钩子函数
- 在qiankun中包裹其方法,根据single-spa的appStatus进行卸载应用
Additional context
// import-html-entry
export async function clearCatchByUrl (app) {
const htmlCatch = embedHTMLCache[app.entry]
if (!htmlCatch) return
await htmlCatch.then(res => {
/**
* 因为 res.template里面的script && style是被注释掉的
* processTpl 拿不到真实的script & style
*/
// const { scripts, styles } = processTpl(res.template, defaultGetPublicPath(url));
// 清除该url下 script的缓存
Object.keys(scriptCache).map(scriptK => {
if(scriptK.startsWith(res.assetPublicPath)) {
delete scriptCache[scriptK]
}
})
// 清除该url下 style的缓存
Object.keys(styleCache).map(styleK => {
if(styleK.startsWith(res.assetPublicPath)) {
delete styleCache[styleK]
}
})
// 清除该html
delete embedHTMLCache[url]
/**
* 1. 清除execScripts、bootstrap执行之后对window产生的副作用(-app是因为业务系统打包的umd-name)
* 2. 业务代码中对window产生副作用的代码 也需要去除
*/
delete window[`${app.name}-app`]
})
}
import { clearCatchByUrl } from 'shsc-import-html-entry';
import { getAppStatus, unloadApplication } from 'single-spa';
import { AppMetadata } from './interfaces';
/**
* @description: 用于热重载app
* @param {Object} app 卸载微应用name, entry
* @returns false
*/
export async function unloadApp(app: AppMetadata) {
await clearCatchByUrl(app);
const appStatus = getAppStatus(app.name);
if (appStatus !== 'NOT_LOADED') {
unloadApplication(app.name);
// 调用unloadApplication时,Single-spa将执行以下步骤。
// 在要卸载的注册应用程序上调用卸载生命周期。
// 将应用程序状态设置为NOT_LOADED
// 触发重新路由,在此期间,单spa可能会挂载刚刚卸载的应用程序。
// 由于unloadApplication调用时可能会挂载已注册的应用程序,因此您可以指定是要立即卸载还是要等待直到不再挂载该应用程序。这是通过该waitForUnmount选项完成的。
}
}
reloadApp () {
/**
* 1. 根据soket返回的数据,判定此次更新了那个服务
* a: 将clearHtmlCatch() && unloadApplication() 合并为 unloadApp()
* a: 此服务为当前激活服务 unloadApp()
* b: 此服务为其他子服务 unloadApp()
*/
let app = ''
MicroApps.some(_app => {
if (_app.name === 'shsc-gaia-cs-web') app = _app
return _app.name === 'shsc-gaia-cs-web'
})
// 先清除因为子系统注册导致的副作用
delete window.func
unloadApp(app).then(() => {
// 重载完成
})
}