From 4814b308cd5076a7330ccc8aae6f2c78642320c0 Mon Sep 17 00:00:00 2001 From: bailicangdu <1264889788@qq.com> Date: Fri, 28 Jun 2024 20:37:18 +0800 Subject: [PATCH] feat(1.0.0-rc.6): Improve router system of naitve mode --- docs/zh-cn/changelog.md | 1 + docs/zh-cn/configure.md | 20 +++++++++++--------- src/sandbox/router/core.ts | 11 +++++++++-- src/sandbox/router/event.ts | 20 ++++++++++---------- src/sandbox/router/history.ts | 7 ++++--- typings/global.d.ts | 5 +++++ 6 files changed, 40 insertions(+), 24 deletions(-) diff --git a/docs/zh-cn/changelog.md b/docs/zh-cn/changelog.md index 07413940..0176dc45 100644 --- a/docs/zh-cn/changelog.md +++ b/docs/zh-cn/changelog.md @@ -26,6 +26,7 @@ - 🐞 修复 当官网文档页面内容含有tab时,跳转或刷新后标题锚点定为不准确的问题。 - 🐞 修复 火狐浏览器下子应用`favicon.ico`将主应用图标替换的问题。 - 🐞 修复 循环嵌套时,中间层子应用为iframe沙箱时通过data属性传递初始化数据失败的问题。 + - 🐞 修复 native路由模式下vue3按需加载页面在部分场景下点击浏览器前进后退按钮时浏览器地址错误。 - **Update** - 🚀 优化 沙箱架构设计。 diff --git a/docs/zh-cn/configure.md b/docs/zh-cn/configure.md index 849a842d..f21ed709 100644 --- a/docs/zh-cn/configure.md +++ b/docs/zh-cn/configure.md @@ -43,15 +43,6 @@ MicroApp有两种沙箱方案:`with沙箱`和`iframe沙箱`。 开启inline模式后,script元素会被保留,方便查看和调试代码,但会稍微损耗性能,建议只在开发环境中使用。 -## destroy -- Desc: `卸载时强制删除缓存资源` -- Default: `false` -- 使用方式: `` - -默认情况下,子应用被卸载后不会删除缓存的静态资源和数据,以便在重新渲染时获得更好的性能。 - -开启destroy,子应用在卸载后会清空缓存资源和数据,当重新渲染时将和初次渲染的行为保持一致。 - ## clear-data - Desc: `卸载时清空数据通讯中的缓存数据` - Default: `false` @@ -63,6 +54,17 @@ MicroApp有两种沙箱方案:`with沙箱`和`iframe沙箱`。 [destroy](/zh-cn/configure?id=destroy)也有同样的效果。 +## destroy +- Desc: `卸载时删除缓存资源` +- Default: `false` +- 使用方式: `` + +默认情况下,子应用被卸载后不会删除缓存的静态资源和沙箱数据,以便在重新渲染时获得更好的性能。 + +开启destroy,子应用在卸载后会清空缓存的静态资源和沙箱数据。 + +但destroy只适合一次性渲染的子应用,由于子应用每次初始化都可能会增加一些无法释放的内存,如果频繁渲染和卸载,设置destroy反而会增加内存消耗,请谨慎使用。 + ## disable-scopecss - Desc: `关闭样式隔离` diff --git a/src/sandbox/router/core.ts b/src/sandbox/router/core.ts index c935d6bb..b802b292 100644 --- a/src/sandbox/router/core.ts +++ b/src/sandbox/router/core.ts @@ -1,6 +1,7 @@ import type { MicroLocation, MicroState, + MicroRouterInfoState, LocationQuery, HandleMicroPathResult, } from '@micro-app/types' @@ -35,14 +36,14 @@ export function setMicroState ( ): MicroState { // TODO: 验证native模式下修改state nextjs路由是否正常 const rawState = globalEnv.rawWindow.history.state - const additionalState: Record = { + const additionalState: Record<'__MICRO_APP_STATE__', Record> = { __MICRO_APP_STATE__: assign({}, rawState?.__MICRO_APP_STATE__, { [appName]: { fullPath: targetLocation ? targetLocation.pathname + targetLocation.search + targetLocation.hash : null, state: microState ?? null, mode: getRouterMode(appName), } - }) + }), } // create new state object @@ -69,6 +70,12 @@ export function getMicroState (appName: string): MicroState { return rawState?.__MICRO_APP_STATE__?.[appName]?.state || null } +// get micro app router info state form origin state +export function getMicroRouterInfoState (appName: string): MicroRouterInfoState | null { + const rawState = globalEnv.rawWindow.history.state + return rawState?.__MICRO_APP_STATE__?.[appName] || null +} + const ENC_AD_RE = /&/g // %M1 const ENC_EQ_RE = /=/g // %M2 const DEC_AD_RE = /%M1/g // & diff --git a/src/sandbox/router/event.ts b/src/sandbox/router/event.ts index 4f9a1fdd..16b8fc25 100644 --- a/src/sandbox/router/event.ts +++ b/src/sandbox/router/event.ts @@ -14,6 +14,7 @@ import { import { getMicroPathFromURL, getMicroState, + getMicroRouterInfoState, isEffectiveApp, isRouterModeCustom, } from './core' @@ -51,22 +52,21 @@ export function addHistoryListener (appName: string): CallableFunction { !e.onlyForBrowser ) { /** - * main app maybe navigate async when receive popstateEvent, but child may respond to popstateEvent immediately(vue2, react), so when go back throw browser child will not unmount sync, and will respond to popstateEvent before base app, this will cause some problems - */ - /** - * NOTE: + * base app may respond to popstateEvent async(lazy load page & browser back/forward), but child app will respond to popstateEvent immediately(vue2, react), this will cause some problems + * 2 solutions: + * 1. child app respond to popstateEvent async -- router-event-delay + * 2. child app will not respond to popstateEvent in some scenarios (history.state===null || history.state?__MICRO_APP_STATE__[appName]) + * NOTE 1: * 1. browser back/forward * 2. location.hash/search/pathname = xxx * 3. , * 4. history.back/go/forward * 5. history.pushState/replaceState + * + * NOTE2: + * react16 hash mode navigate by location.hash = xxx, history.state is always null, but react16 respond to popstateEvent sync */ - // 1、其它模式要不要也过滤关键在于history.state存在时__MICRO_APP_STATE__有没有可能不存在 - // 如果history.state存在而__MICRO_APP_STATE__不存在在非native模式下存在,那就不能过滤,比如pure模式? - // 不对啊,location.hash=xxx,确实会导致state为null,可以框架接受到popstate事件后就重新写入state了,所以这种方式不准确 -- 误会,框架重写写入state也是靠history.replaceState,所以没事 - if (!isRouterModeCustom(appName) || !history.state || getMicroState(appName)) { - // updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName)) - // 这里加一个判断,如果是native或者search模式才启用延迟,state、pure不需要这样做 + if (!isRouterModeCustom(appName) || !history.state || getMicroRouterInfoState(appName)) { const container = appInstanceMap.get(appName)?.container macro( () => updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName)), diff --git a/src/sandbox/router/history.ts b/src/sandbox/router/history.ts index 9174127b..c1cec0af 100644 --- a/src/sandbox/router/history.ts +++ b/src/sandbox/router/history.ts @@ -22,6 +22,7 @@ import { setMicroPathToURL, setMicroState, getMicroState, + getMicroRouterInfoState, getMicroPathFromURL, isEffectiveApp, isRouterModePure, @@ -223,12 +224,12 @@ function reWriteHistoryMethod (method: History['pushState' | 'replaceState']): C const app = appInstanceMap.get(appName)! attachRouteToBrowserURL( appName, - setMicroPathToURL(appName, app.sandBox.proxyWindow.location as MicroLocation), - setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location as MicroLocation), + setMicroPathToURL(appName, app.sandBox.proxyWindow.location), + setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location), ) } - if (isRouterModeCustom(appName) && !rawWindow.history.state?.__MICRO_APP_STATE__?.[appName]) { + if (isRouterModeCustom(appName) && !getMicroRouterInfoState(appName)) { nativeHistoryNavigate( appName, 'replaceState', diff --git a/typings/global.d.ts b/typings/global.d.ts index 43572fdc..cdab0157 100644 --- a/typings/global.d.ts +++ b/typings/global.d.ts @@ -408,6 +408,11 @@ declare module '@micro-app/types' { type MicroHistory = ProxyHandler type MicroState = any + interface MicroRouterInfoState { + fullPath: string | null, + state: MicroState, + mode: string, + } type HistoryProxyValue = Pick< History,