The Wayback Machine - https://web.archive.org/web/20201021202156/https://github.com/umijs/qiankun/issues/830
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] 关于子系统的热重载问题 #830

Open
dengBox opened this issue Aug 6, 2020 · 3 comments
Open

[Feature Request] 关于子系统的热重载问题 #830

dengBox opened this issue Aug 6, 2020 · 3 comments

Comments

@dengBox
Copy link

@dengBox dengBox commented Aug 6, 2020

Background

目前使用qiankun2.x的版本,业务提出需求在发布新的版本时候,期望可以不刷新页面(主应用暂时不考虑)进行该系统的热重载。类似于pc端的热更新,期望qiankun可以导出unload方法,完全销毁app的生命周期,业务系统再次将其重载。

Proposal

  1. 翻看源码发现不能热更新的原因是因为import-html-entry中缓存了 embedHTMLCache
  2. qiankunimportEntry时,如果已经获取过html资源,每次获取的都是内存中的html,以至于script & style也是缓存的
  3. 我的解决方案是,在import-html-entry中导出根据app去清除缓存的钩子函数
  4. 在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(() => {
        // 重载完成
      })
}
@dengBox dengBox changed the title [Feature Request] say something [Feature Request] 关于子系统的热重载问题 Aug 6, 2020
@poryzhao
Copy link

@poryzhao poryzhao commented Aug 6, 2020

我也遇到了类似的问题:

两个子应用:一个是用nextjs做的ssr,一个是正常的spa应用。

切换时两个子应用因为都被embedHTMLCache,所以前一个子应用只能渲染出来html结构,所有的js不再重复加载,js对应的点击操作都丢失了。

因为需要一个手动卸载方法,在切换子应用后将前一个子应用完全卸载掉。

楼主给的方案可以满足目前的需求。

@dengBox
Copy link
Author

@dengBox dengBox commented Aug 10, 2020

我也遇到了类似的问题:

两个子应用:一个是用nextjs做的ssr,一个是正常的spa应用。

切换时两个子应用因为都被embedHTMLCache,所以前一个子应用只能渲染出来html结构,所有的js不再重复加载,js对应的点击操作都丢失了。

因为需要一个手动卸载方法,在切换子应用后将前一个子应用完全卸载掉。

楼主给的方案可以满足目前的需求。

我目前是将qiankunimport-html-entry自己进行fix,希望作者能采纳一下意见,自己维护还是挺辛苦的(手动狗头)

@yutingzhao1991
Copy link

@yutingzhao1991 yutingzhao1991 commented Aug 15, 2020

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants
You can’t perform that action at this time.