diff --git a/dev/children/vite2/src/main.js b/dev/children/vite2/src/main.js
index 4974ba1d3..1c1e90a47 100644
--- a/dev/children/vite2/src/main.js
+++ b/dev/children/vite2/src/main.js
@@ -47,7 +47,7 @@ let router = null
let history = null
// 将渲染操作放入 mount 函数
window.mount = (data) => {
- history = createWebHistory(import.meta.env.BASE_URL)
+ history = createWebHistory(window.__MICRO_APP_BASE_ROUTE__ || import.meta.env.BASE_URL)
router = createRouter({
history,
routes,
diff --git a/dev/children/vite4/package.json b/dev/children/vite4/package.json
index 0c809e3a7..48db146d7 100644
--- a/dev/children/vite4/package.json
+++ b/dev/children/vite4/package.json
@@ -4,7 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "start": "vite",
+ "start": "vite --force",
"build": "vite build",
"preview": "vite preview"
},
diff --git a/dev/children/vite4/src/main.js b/dev/children/vite4/src/main.js
index e0f6dab0e..beef4fae0 100644
--- a/dev/children/vite4/src/main.js
+++ b/dev/children/vite4/src/main.js
@@ -47,7 +47,8 @@ let router = null
let history = null
// 将渲染操作放入 mount 函数
window.mount = (data) => {
- history = createWebHistory(import.meta.env.BASE_URL)
+ // console.log(1212121212121212, location.href)
+ history = createWebHistory(window.__MICRO_APP_BASE_ROUTE__ || import.meta.env.BASE_URL)
router = createRouter({
history,
routes,
diff --git a/dev/main-react16/config/routes.js b/dev/main-react16/config/routes.js
index 39eceff8c..79d4abe2a 100644
--- a/dev/main-react16/config/routes.js
+++ b/dev/main-react16/config/routes.js
@@ -51,6 +51,13 @@ export default [
component: './vite2/vite2',
exact: false,
},
+ {
+ path: '/vite4',
+ name: 'vite4',
+ icon: 'RocketOutlined',
+ component: './vite4/vite4',
+ exact: false,
+ },
{
path: '/angular11',
name: 'angular11',
diff --git a/dev/main-react16/src/config.js b/dev/main-react16/src/config.js
index fbc0ded9e..785c9182c 100644
--- a/dev/main-react16/src/config.js
+++ b/dev/main-react16/src/config.js
@@ -5,6 +5,7 @@ let config = {
vue2: 'http://localhost:4001/',
vue3: 'http://localhost:4002/',
vite2: 'http://localhost:7001/',
+ vite4: 'http://localhost:7002/',
angular11: 'http://localhost:6001/',
angular14: 'http://localhost:6002/',
}
@@ -20,6 +21,7 @@ if (isEnvPro) {
angular11: locationOrigin,
angular14: locationOrigin,
vite2: locationOrigin,
+ vite4: locationOrigin,
}
}
diff --git a/dev/main-react16/src/locales/zh-CN/menu.js b/dev/main-react16/src/locales/zh-CN/menu.js
index b3f19b6d8..013e0599b 100644
--- a/dev/main-react16/src/locales/zh-CN/menu.js
+++ b/dev/main-react16/src/locales/zh-CN/menu.js
@@ -8,4 +8,5 @@ export default {
'menu.multiple': '多个应用',
'menu.self': '自带页面',
'menu.vite2': 'vite2应用',
+ 'menu.vite4': 'vite4应用',
};
diff --git a/dev/main-react16/src/pages/react16/react16.js b/dev/main-react16/src/pages/react16/react16.js
index e3f4d9daf..686c9f0a5 100644
--- a/dev/main-react16/src/pages/react16/react16.js
+++ b/dev/main-react16/src/pages/react16/react16.js
@@ -327,11 +327,11 @@ export default class App extends React.Component {
microApp.addGlobalDataListener(this.handleGlobalDataForBaseApp)
- setTimeout(() => {
- this.setState({
- showMicroApp: !this.state.showMicroApp,
- })
- }, 0);
+ // setTimeout(() => {
+ // this.setState({
+ // showMicroApp: !this.state.showMicroApp,
+ // })
+ // }, 0);
// this.releaseBeforeEach1 = microApp.router.beforeEach((to, from, appName) => {
// // const a = document.createElement('div')
diff --git a/dev/main-react16/src/pages/vite2/vite2.js b/dev/main-react16/src/pages/vite2/vite2.js
index ee5b66cbe..c3668a571 100644
--- a/dev/main-react16/src/pages/vite2/vite2.js
+++ b/dev/main-react16/src/pages/vite2/vite2.js
@@ -104,10 +104,11 @@ function vite2 (props) {
// disableSandbox
iframe
keep-router-state
- // disable-memory-router
+ disable-memory-router
// disable-patch-request
// keep-alive
// default-page='/micro-app/vite2/page2'
+ baseroute='/micro-app/demo/vite2'
>
diff --git a/dev/main-react16/src/pages/vite4/vite4.js b/dev/main-react16/src/pages/vite4/vite4.js
new file mode 100644
index 000000000..adb16c72a
--- /dev/null
+++ b/dev/main-react16/src/pages/vite4/vite4.js
@@ -0,0 +1,120 @@
+/** @jsxRuntime classic */
+/** @jsx jsxCustomEvent */
+import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event'
+import { useState, useEffect } from 'react'
+import { Button, Spin, Col } from 'antd'
+import { LoadingOutlined } from '@ant-design/icons'
+// import { EventCenterForMicroApp } from '@micro-zoe/micro-app'
+import config from '../../config'
+import './vite4.less'
+import microApp from '@micro-zoe/micro-app'
+
+// 注册子应用vite4的数据通信对象
+// window.eventCenterForVite = new EventCenterForMicroApp('vite4')
+
+const antIcon =
+
+function vite4 (props) {
+ const [data, changeData] = useState({from: '来自基座的初始化数据'})
+ const [showLoading, hideLoading] = useState(true)
+
+ function handleMounted () {
+ console.timeEnd('vite4')
+ hideLoading(false)
+ console.log('主应用-生命周期:mounted -- vite4')
+ }
+
+ function handleDataChange (e) {
+ console.log('来自 vite4 子应用的数据', e.detail.data)
+ }
+
+ function jumpToHome () {
+ microApp.router.push({name: 'vite4', path: '/micro-app/vite4/'})
+ }
+
+ function jumpToPage2 () {
+ microApp.router.push({name: 'vite4', path: '/micro-app/vite4/element-plus'})
+ }
+
+ function jumpToPage3 () {
+ microApp.router.push({name: 'vite4', path: '/micro-app/vite4/ant-design-vue'})
+ }
+
+ useEffect(() => {
+ console.time('vite4')
+ // const releaseBeforeEach1 = microApp.router.beforeEach((to, from, appName) => {
+ // console.log('全局 beforeEach: ', to, from, appName)
+ // })
+
+ // const releaseBeforeEach2 = microApp.router.beforeEach({
+ // vite4 (to, from) {
+ // console.log('指定 beforeEach: ', to, from)
+ // }
+ // })
+
+ // const releaseAfterEach1 = microApp.router.afterEach((to, from, appName) => {
+ // console.log('全局 afterEach: ', to, from, appName)
+ // })
+
+ // const releaseAfterEach2 = microApp.router.afterEach({
+ // vite4 (to, from) {
+ // console.log('指定 afterEach: ', to, from)
+ // }
+ // })
+
+ microApp.router.setBaseAppRouter(props.history)
+
+ return () => {
+ // releaseBeforeEach1()
+ // releaseBeforeEach2()
+ // releaseAfterEach1()
+ // releaseAfterEach2()
+ }
+ }, [])
+
+ return (
+
+
+
+
+
+
+
+
+
+ {
+ showLoading &&
+ }
+
hideLoading(false)}
+ onMounted={handleMounted}
+ onDataChange={handleDataChange}
+ onAfterhidden={() => console.log('基座:keep-alive:Afterhidden 已推入后台')}
+ onBeforeshow={() => console.log('基座:keep-alive:Beforeshow 即将推入前台')}
+ onAftershow={() => {console.log('基座:keep-alive:Aftershow 已经推入前台'); hideLoading(false)}}
+ onError={() => console.log('渲染出错')}
+ // destroy
+ // inline
+ // disableSandbox
+ iframe
+ keep-router-state
+ disable-memory-router
+ // disable-patch-request
+ // keep-alive
+ // default-page='/micro-app/vite4/page2'
+ baseroute='/micro-app/demo/vite4'
+ >
+
+
+ {/*
*/}
+
+ )
+}
+
+export default vite4
diff --git a/dev/main-react16/src/pages/vite4/vite4.less b/dev/main-react16/src/pages/vite4/vite4.less
new file mode 100644
index 000000000..92a2fdbee
--- /dev/null
+++ b/dev/main-react16/src/pages/vite4/vite4.less
@@ -0,0 +1,3 @@
+.test-vite4 {
+ color: red;
+}
diff --git a/src/create_app.ts b/src/create_app.ts
index f13cff5c7..16422590e 100644
--- a/src/create_app.ts
+++ b/src/create_app.ts
@@ -388,6 +388,12 @@ export default class CreateApp implements AppInterface {
this.sandBox?.recordAndReleaseEffect({ keepAlive: true })
}
}
+ /**
+ * TODO: 这里增加一个处理,如果渲染完成时已经卸载,则进行一些操作
+ * 如果是默认模式:删除所有事件和定时器
+ * 如果是umd模式:重新记录和清空事件
+ * 补充:非必需,优先级低
+ */
}
/**
diff --git a/src/sandbox/iframe/index.ts b/src/sandbox/iframe/index.ts
index f12d637cf..6842c9f09 100644
--- a/src/sandbox/iframe/index.ts
+++ b/src/sandbox/iframe/index.ts
@@ -28,13 +28,14 @@ import {
} from '../../interact'
import {
patchIframeRoute,
+ actionsForDisableMemoryRoute,
} from './route'
import {
router,
initRouteStateWithURL,
clearRouteStateFromURL,
addHistoryListener,
- removeStateAndPathFromBrowser,
+ removePathFromBrowser,
updateBrowserURLWithLocation,
patchHistory,
releasePatchHistory,
@@ -166,7 +167,12 @@ export default class IframeSandbox {
this.microAppWindow.__MICRO_APP_NAME__,
)
} else {
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute
+ // actions when memory-route disable
+ actionsForDisableMemoryRoute(
+ this.microAppWindow.__MICRO_APP_NAME__,
+ this.microAppWindow,
+ baseroute,
+ )
}
/**
@@ -486,7 +492,7 @@ export default class IframeSandbox {
}
public removeRouteInfoForKeepAliveApp (): void {
- removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__)
+ removePathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__)
}
/**
diff --git a/src/sandbox/iframe/route.ts b/src/sandbox/iframe/route.ts
index db0847464..93492be79 100644
--- a/src/sandbox/iframe/route.ts
+++ b/src/sandbox/iframe/route.ts
@@ -12,6 +12,7 @@ import {
import {
assign,
} from '../../libs/utils'
+import globalEnv from '../../libs/global_env'
export function patchIframeRoute (
appName: string,
@@ -51,3 +52,34 @@ export function patchIframeRoute (
childHost,
)
}
+
+/**
+ * actions when memory-route disable
+ * @param appName app name
+ * @param microAppWindow iframeWindow
+ * @param baseroute base route for child app
+ */
+export function actionsForDisableMemoryRoute (
+ appName: string,
+ microAppWindow: microAppWindowType,
+ baseroute: string,
+): void {
+ microAppWindow.__MICRO_APP_BASE_ROUTE__ = microAppWindow.__MICRO_APP_BASE_URL__ = baseroute
+
+ /**
+ * Sync browser router info to iframe when disable memory-router
+ * e.g.:
+ * vue-router@4.x get target path by remove the base section from location.pathname
+ * code: window.location.pathname.slice(base.length) || '/'; (base is baseroute)
+ * NOTE:
+ * 1. iframe router and browser router are separated, we should update iframe router manually
+ * 2. withSandbox location is browser location when disable memory-router, so no need to do anything
+ */
+ const rawLocation = globalEnv.rawWindow.location
+ updateMicroLocation(
+ appName,
+ rawLocation.href,
+ rawLocation,
+ 'prevent'
+ )
+}
diff --git a/src/sandbox/router/api.ts b/src/sandbox/router/api.ts
index d7dbf4a34..467bbd378 100644
--- a/src/sandbox/router/api.ts
+++ b/src/sandbox/router/api.ts
@@ -17,6 +17,7 @@ import {
setMicroState,
getMicroState,
getMicroPathFromURL,
+ isMemoryRouterEnabled,
} from './core'
import {
logError,
@@ -99,7 +100,7 @@ function createRouterApi (): RouterApi {
const appName = formatAppName(to.name)
if (appName && isString(to.path)) {
const app = appInstanceMap.get(appName)
- if (app && (!app.sandBox || !app.useMemoryRouter)) {
+ if (app && !isMemoryRouterEnabled(appName)) {
return logError(`navigation failed, memory router of app ${appName} is closed`)
}
// active apps, include hidden keep-alive app
@@ -204,8 +205,8 @@ function createRouterApi (): RouterApi {
* 2. useMemoryRouter is false
*/
function commonHandlerForAttachToURL (appName: string): void {
- const app = appInstanceMap.get(appName)!
- if (app.sandBox && app.useMemoryRouter) {
+ if (isMemoryRouterEnabled(appName)) {
+ const app = appInstanceMap.get(appName)!
attachRouteToBrowserURL(
appName,
setMicroPathToURL(appName, app.sandBox.proxyWindow.location as MicroLocation),
diff --git a/src/sandbox/router/core.ts b/src/sandbox/router/core.ts
index 9041f002f..85d77fbc9 100644
--- a/src/sandbox/router/core.ts
+++ b/src/sandbox/router/core.ts
@@ -23,6 +23,7 @@ export function setMicroState (
appName: string,
microState: MicroState,
): MicroState {
+ if (!isMemoryRouterEnabled(appName)) return microState
const rawState = globalEnv.rawWindow.history.state
const additionalState: Record = {
microAppState: assign({}, rawState?.microAppState, {
@@ -102,19 +103,22 @@ export function getMicroPathFromURL (appName: string): string | null {
* @param microLocation location of child app
*/
export function setMicroPathToURL (appName: string, microLocation: MicroLocation): HandleMicroPathResult {
+ const targetFullPath = microLocation.pathname + microLocation.search + microLocation.hash
+ let isAttach2Hash = false
+ if (!isMemoryRouterEnabled(appName)) {
+ return {
+ fullPath: targetFullPath,
+ isAttach2Hash,
+ }
+ }
let { pathname, search, hash } = globalEnv.rawWindow.location
const queryObject = getQueryObjectFromURL(search, hash)
- const encodedMicroPath = encodeMicroPath(
- microLocation.pathname +
- microLocation.search +
- microLocation.hash
- )
+ const encodedMicroPath = encodeMicroPath(targetFullPath)
/**
* Is parent is hash router
* In fact, this is not true. It just means that the parameter is added to the hash
*/
- let isAttach2Hash = false
// If hash exists and search does not exist, it is considered as a hash route
if (hash && !search) {
isAttach2Hash = true
@@ -208,5 +212,22 @@ export function getNoHashMicroPathFromURL (appName: string, baseUrl: string): st
*/
export function isEffectiveApp (appName: string): boolean {
const app = appInstanceMap.get(appName)
- return !!(app && !app.isPrefetch && !app.isHidden())
+ /**
+ * !!(app && !app.isPrefetch && !app.isHidden())
+ * 隐藏的keep-alive应用暂时不作为无效应用,原因如下
+ * 1、隐藏后才执行去除浏览器上的微应用的路由信息的操作,导致微应用的路由信息无法去除
+ * 2、如果保持隐藏应用内部正常跳转,阻止同步路由信息到浏览器,这样理论上是好的,但是对于location跳转改如何处理?location跳转是基于修改浏览器地址后发送popstate事件实现的,所以应该是在隐藏后不支持通过location进行跳转
+ */
+ return !!(app && !app.isPrefetch)
+}
+
+/**
+ * Determine whether the app has enabled memory-router
+ * NOTE:
+ * 1. if sandbox disabled, memory-router is disabled
+ * 2. if app not exist, memory-router is disabled
+ */
+export function isMemoryRouterEnabled (appName: string): boolean {
+ const app = appInstanceMap.get(appName)
+ return !!(app && app.sandBox && app.useMemoryRouter)
}
diff --git a/src/sandbox/router/history.ts b/src/sandbox/router/history.ts
index ee0bc38ff..65c668c50 100644
--- a/src/sandbox/router/history.ts
+++ b/src/sandbox/router/history.ts
@@ -21,6 +21,7 @@ import {
getMicroState,
getMicroPathFromURL,
isEffectiveApp,
+ isMemoryRouterEnabled,
} from './core'
import { dispatchNativeEvent } from './event'
import { updateMicroLocation } from './location'
@@ -116,6 +117,8 @@ export function nativeHistoryNavigate (
* 2. proxyHistory.pushState/replaceState with limited popstateEvent
* 3. api microApp.router.push/replace
* 4. proxyLocation.hash = xxx
+ * NOTE:
+ * 1. hidden keep-alive app can jump internally, but will not synchronize to browser
* @param appName app.name
* @param methodName pushState/replaceState
* @param result result of add/remove microApp path on browser url
@@ -191,8 +194,8 @@ function reWriteHistoryMethod (method: History['pushState' | 'replaceState']): C
excludeHiddenApp: true,
excludePreRender: true,
}).forEach(appName => {
- const app = appInstanceMap.get(appName)!
- if (app.sandBox && app.useMemoryRouter && !getMicroPathFromURL(appName)) {
+ if (isMemoryRouterEnabled(appName) && !getMicroPathFromURL(appName)) {
+ const app = appInstanceMap.get(appName)!
attachRouteToBrowserURL(
appName,
setMicroPathToURL(appName, app.sandBox.proxyWindow.location as MicroLocation),
diff --git a/src/sandbox/router/index.ts b/src/sandbox/router/index.ts
index f77dabe18..07184bd1d 100644
--- a/src/sandbox/router/index.ts
+++ b/src/sandbox/router/index.ts
@@ -101,7 +101,7 @@ export function clearRouteStateFromURL (
const { pathname, search, hash } = createURL(url)
updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent')
}
- removeStateAndPathFromBrowser(appName)
+ removePathFromBrowser(appName)
clearRouterWhenUnmount(appName)
}
@@ -109,7 +109,7 @@ export function clearRouteStateFromURL (
* remove microState from history.state and remove microPath from browserURL
* called on sandbox.stop or hidden of keep-alive app
*/
-export function removeStateAndPathFromBrowser (appName: string): void {
+export function removePathFromBrowser (appName: string): void {
attachRouteToBrowserURL(
appName,
removeMicroPathFromURL(appName),
diff --git a/src/sandbox/with/index.ts b/src/sandbox/with/index.ts
index a1c5ca5b0..be686f39d 100644
--- a/src/sandbox/with/index.ts
+++ b/src/sandbox/with/index.ts
@@ -52,7 +52,7 @@ import {
initRouteStateWithURL,
clearRouteStateFromURL,
addHistoryListener,
- removeStateAndPathFromBrowser,
+ removePathFromBrowser,
updateBrowserURLWithLocation,
patchHistory,
releasePatchHistory,
@@ -732,7 +732,7 @@ export default class WithSandBox implements WithSandBoxInterface {
}
public removeRouteInfoForKeepAliveApp (): void {
- removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__)
+ removePathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__)
}
/**