diff --git a/packages/fes-plugin-qiankun/examples/main/src/pages/index.vue b/packages/fes-plugin-qiankun/examples/main/src/pages/index.vue index e1f1c676..6bbe5a4e 100644 --- a/packages/fes-plugin-qiankun/examples/main/src/pages/index.vue +++ b/packages/fes-plugin-qiankun/examples/main/src/pages/index.vue @@ -2,6 +2,7 @@
main
+ { @@ -9,3 +10,22 @@ "title": "首页" } + diff --git a/packages/fes-plugin-qiankun/src/main/index.js b/packages/fes-plugin-qiankun/src/main/index.js index 5ee3f2d1..3f4b035e 100644 --- a/packages/fes-plugin-qiankun/src/main/index.js +++ b/packages/fes-plugin-qiankun/src/main/index.js @@ -33,6 +33,7 @@ export default function (api) { modifyRoutes({ api, namespace }); const absMicroAppPath = join(namespace, 'MicroApp.js'); + const absMicroAppWithMemoHistoryPath = join(namespace, 'MicroAppWithMemoHistory.js'); const absRuntimePath = join(namespace, 'runtime.js'); const absMasterOptionsPath = join(namespace, 'masterOptions.js'); const absGetMicroAppRouteCompPath = join( @@ -62,6 +63,15 @@ export default function (api) { ) }); + api.writeTmpFile({ + path: absMicroAppWithMemoHistoryPath, + content: Mustache.render( + readFileSync(join(__dirname, 'runtime/MicroAppWithMemoHistory.tpl'), 'utf-8'), + { + } + ) + }); + api.writeTmpFile({ path: absRuntimePath, content: readFileSync( @@ -102,6 +112,13 @@ export default function (api) { } ]); + api.addPluginExports(() => [ + { + specifiers: ['MicroAppWithMemoHistory'], + source: absMicroAppWithMemoHistoryPath + } + ]); + api.addPluginExports(() => [ { specifiers: ['getMicroAppRouteComponent'], diff --git a/packages/fes-plugin-qiankun/src/main/runtime/MicroApp.tpl b/packages/fes-plugin-qiankun/src/main/runtime/MicroApp.tpl index 9c642047..69266cf1 100644 --- a/packages/fes-plugin-qiankun/src/main/runtime/MicroApp.tpl +++ b/packages/fes-plugin-qiankun/src/main/runtime/MicroApp.tpl @@ -13,15 +13,12 @@ import mergeWith from "lodash/mergeWith"; import { getMasterOptions } from "./masterOptions"; import { onBeforeRouteLeave } from "@@/core/coreExports"; -let unmountPromise; async function unmountMicroApp(microApp) { if (microApp) { - return microApp.mountPromise.then(_microApp => { - // Now it is safe to call unmount - if(_microApp){ - return _microApp.unmount() - } - }) + const status = microApp.getStatus(); + if(status === 'MOUNTED'){ + await microApp.unmount(); + } } return Promise.resolve(); } diff --git a/packages/fes-plugin-qiankun/src/main/runtime/MicroAppWithMemoHistory.tpl b/packages/fes-plugin-qiankun/src/main/runtime/MicroAppWithMemoHistory.tpl new file mode 100644 index 00000000..8aefa40d --- /dev/null +++ b/packages/fes-plugin-qiankun/src/main/runtime/MicroAppWithMemoHistory.tpl @@ -0,0 +1,33 @@ + +import { + defineComponent, isRef, watch +} from 'vue'; +import { MicroApp } from './MicroApp'; + + +export const MicroAppWithMemoHistory = defineComponent({ + components: { + MicroApp + }, + props: { + name: { + type: String, + required: true + }, + settings: Object, + lifeCycles: Object, + className: String, + url: String + }, + setup(props, { attrs }) { + let microRouter; + const onRouterInit = (router) => { + microRouter = router; + microRouter.push(props.url); + }; + watch(()=>props.url, () => { + microRouter.push(props.url); + }); + return () => ; + } +}); diff --git a/packages/fes-plugin-qiankun/src/micro/index.js b/packages/fes-plugin-qiankun/src/micro/index.js index 2bcd85d2..855385ee 100644 --- a/packages/fes-plugin-qiankun/src/micro/index.js +++ b/packages/fes-plugin-qiankun/src/micro/index.js @@ -155,6 +155,8 @@ export default function (api) { } }); + api.addRuntimePlugin(() => `@@/${absRuntimePath}`); + api.addEntryImports(() => ({ source: `@@/${absLifeclesPath}`, specifier: diff --git a/packages/fes-plugin-qiankun/src/micro/runtime/lifecycles.tpl b/packages/fes-plugin-qiankun/src/micro/runtime/lifecycles.tpl index b429733c..807ce787 100644 --- a/packages/fes-plugin-qiankun/src/micro/runtime/lifecycles.tpl +++ b/packages/fes-plugin-qiankun/src/micro/runtime/lifecycles.tpl @@ -1,4 +1,4 @@ -import { plugin, ApplyPluginsType } from '@@/core/coreExports'; +import { plugin, ApplyPluginsType, getRouter, getHistory, destroyRouter } from '@@/core/coreExports'; {{#HAS_PLUGIN_MODEL}} import { setModelState } from './qiankunModel'; {{/HAS_PLUGIN_MODEL}} @@ -21,6 +21,10 @@ let hasMountedAtLeastOnce = false; export default () => defer.promise; +export const clientRenderOptsStack = []; + +export const history = {}; + function getSlaveRuntime() { const config = plugin.applyPlugins({ key: 'qiankun', @@ -59,6 +63,23 @@ export function genMount(mountElementId) { } } + // 更新 clientRender 配置 + const clientRenderOpts = { + // 支持通过 props 注入 container 来限定子应用 mountElementId 的查找范围 + // 避免多个子应用出现在同一主应用时出现 mount 冲突 + rootElement: + props?.container?.querySelector(mountElementId) || mountElementId + }; + + clientRenderOptsStack.push(clientRenderOpts); + + if(props.url){ + history.url = props.url || '/'; + } + if(props.onRouterInit){ + history.onRouterInit = props.onRouterInit; + } + // 第一次 mount 会自动触发 render,非第一次 mount 则需手动触发 if (hasMountedAtLeastOnce) { const appPromise = render(); @@ -87,10 +108,13 @@ export function genUpdate() { // 子应用生命周期钩子Unmount export function genUnmount() { return async (props) => { + const history = getHistory(); + history.destroy(); if (cacheAppPromise) { const app = await cacheAppPromise; app.unmount(); } + destroyRouter(); const slaveRuntime = getSlaveRuntime(); if (slaveRuntime.unmount) { await slaveRuntime.unmount(props); diff --git a/packages/fes-plugin-qiankun/src/micro/runtime/runtime.tpl b/packages/fes-plugin-qiankun/src/micro/runtime/runtime.tpl index e69de29b..d8e62d47 100644 --- a/packages/fes-plugin-qiankun/src/micro/runtime/runtime.tpl +++ b/packages/fes-plugin-qiankun/src/micro/runtime/runtime.tpl @@ -0,0 +1,31 @@ +import { createMemoryHistory } from '@@/core/coreExports'; +import qiankunRender, { clientRenderOptsStack, history } from './lifecycles'; + + +export const render = oldRender => qiankunRender().then(oldRender); + +export function modifyClientRenderOpts(memo) { + // 每次应用 render 的时候会调 modifyClientRenderOpts,这时尝试从队列中取 render 的配置 + const clientRenderOpts = clientRenderOptsStack.shift(); + + return { + ...memo, + ...clientRenderOpts + }; +} + +export function modifyHistroy(memo) { + if (history.url) { + const memoHistroy = createMemoryHistory(); + memoHistroy.push(history.url) + return memoHistroy + } + return memo; +} + +export function onRouterCreated({ router }) { + if(history.onRouterInit){ + history.onRouterInit(router) + } +} + diff --git a/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/index.js b/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/index.js index e574df9e..2680eff5 100644 --- a/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/index.js +++ b/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/index.js @@ -18,6 +18,7 @@ export default function (api) { initialValue: [ // 初始化数据 'beforeRender', + // modify渲染工具 'modifyClientRenderOpts', 'rootContainer', // app生成时触发 @@ -26,6 +27,8 @@ export default function (api) { 'render', // 修改路由 'patchRoutes', + // 修改histror + 'modifyHistroy', // 生成router时触发 'onRouterCreated' ] @@ -48,7 +51,7 @@ export default function (api) { { validKeys, runtimePath - }, + } ) }); api.writeTmpFile({ @@ -60,7 +63,7 @@ export default function (api) { index, path: winPath(plugin) })) - }, + } ) }); }); diff --git a/packages/fes-preset-built-in/src/plugins/misc/route/index.js b/packages/fes-preset-built-in/src/plugins/misc/route/index.js index 5debe708..37ac9a22 100644 --- a/packages/fes-preset-built-in/src/plugins/misc/route/index.js +++ b/packages/fes-preset-built-in/src/plugins/misc/route/index.js @@ -293,7 +293,7 @@ export default function (api) { api.addCoreExports(() => [ { - specifiers: ['getRoutes', 'getRouter', 'getHistory'], + specifiers: ['getRoutes', 'getRouter', 'getHistory', 'destroyRouter'], source: absCoreFilePath } ]); diff --git a/packages/fes-preset-built-in/src/plugins/misc/route/template/routes.tpl b/packages/fes-preset-built-in/src/plugins/misc/route/template/routes.tpl index ea47d11c..3e134cd6 100644 --- a/packages/fes-preset-built-in/src/plugins/misc/route/template/routes.tpl +++ b/packages/fes-preset-built-in/src/plugins/misc/route/template/routes.tpl @@ -20,7 +20,11 @@ export const createRouter = () => { if (router) { return router; } - history = {{{ CREATE_HISTORY }}}(ROUTER_BASE) + history = plugin.applyPlugins({ + key: 'modifyHistroy', + type: ApplyPluginsType.modify, + initialValue: {{{ CREATE_HISTORY }}}(ROUTER_BASE), + }); router = createVueRouter({ history, routes: getRoutes() @@ -36,9 +40,20 @@ export const createRouter = () => { }; export const getRouter = ()=>{ - return router; + if(!router){ + console.warn(`[preset-build-in] router is null`) + } + return router; } export const getHistory = ()=>{ - return history; + if(!history){ + console.warn(`[preset-build-in] history is null`) + } + return history; +} + +export const destroyRouter = ()=>{ + router = null; + history = null; }