Merge branch 'qiankun' into vue3

This commit is contained in:
harrywan 2021-04-19 20:05:27 +08:00
commit daeb5aab04
10 changed files with 156 additions and 14 deletions

View File

@ -2,6 +2,7 @@
<div> <div>
main main
</div> </div>
<MicroAppWithMemoHistory name="app1" :url="url" />
</template> </template>
<config> <config>
{ {
@ -9,3 +10,22 @@
"title": "首页" "title": "首页"
} }
</config> </config>
<script>
import { ref, onMounted } from 'vue';
import { MicroAppWithMemoHistory } from '@fesjs/fes';
export default {
components: { MicroAppWithMemoHistory },
setup() {
const url = ref('/app1/test');
onMounted(() => {
setTimeout(() => {
url.value = '/app1';
}, 3000);
});
return {
url
};
}
};
</script>

View File

@ -33,6 +33,7 @@ export default function (api) {
modifyRoutes({ api, namespace }); modifyRoutes({ api, namespace });
const absMicroAppPath = join(namespace, 'MicroApp.js'); const absMicroAppPath = join(namespace, 'MicroApp.js');
const absMicroAppWithMemoHistoryPath = join(namespace, 'MicroAppWithMemoHistory.js');
const absRuntimePath = join(namespace, 'runtime.js'); const absRuntimePath = join(namespace, 'runtime.js');
const absMasterOptionsPath = join(namespace, 'masterOptions.js'); const absMasterOptionsPath = join(namespace, 'masterOptions.js');
const absGetMicroAppRouteCompPath = join( 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({ api.writeTmpFile({
path: absRuntimePath, path: absRuntimePath,
content: readFileSync( content: readFileSync(
@ -102,6 +112,13 @@ export default function (api) {
} }
]); ]);
api.addPluginExports(() => [
{
specifiers: ['MicroAppWithMemoHistory'],
source: absMicroAppWithMemoHistoryPath
}
]);
api.addPluginExports(() => [ api.addPluginExports(() => [
{ {
specifiers: ['getMicroAppRouteComponent'], specifiers: ['getMicroAppRouteComponent'],

View File

@ -13,15 +13,12 @@ import mergeWith from "lodash/mergeWith";
import { getMasterOptions } from "./masterOptions"; import { getMasterOptions } from "./masterOptions";
import { onBeforeRouteLeave } from "@@/core/coreExports"; import { onBeforeRouteLeave } from "@@/core/coreExports";
let unmountPromise;
async function unmountMicroApp(microApp) { async function unmountMicroApp(microApp) {
if (microApp) { if (microApp) {
return microApp.mountPromise.then(_microApp => { const status = microApp.getStatus();
// Now it is safe to call unmount if(status === 'MOUNTED'){
if(_microApp){ await microApp.unmount();
return _microApp.unmount() }
}
})
} }
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -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 () => <MicroApp onRouterInit={onRouterInit} {...props} {...attrs}></MicroApp>;
}
});

View File

@ -155,6 +155,8 @@ export default function (api) {
} }
}); });
api.addRuntimePlugin(() => `@@/${absRuntimePath}`);
api.addEntryImports(() => ({ api.addEntryImports(() => ({
source: `@@/${absLifeclesPath}`, source: `@@/${absLifeclesPath}`,
specifier: specifier:

View File

@ -1,4 +1,4 @@
import { plugin, ApplyPluginsType } from '@@/core/coreExports'; import { plugin, ApplyPluginsType, getRouter, getHistory, destroyRouter } from '@@/core/coreExports';
{{#HAS_PLUGIN_MODEL}} {{#HAS_PLUGIN_MODEL}}
import { setModelState } from './qiankunModel'; import { setModelState } from './qiankunModel';
{{/HAS_PLUGIN_MODEL}} {{/HAS_PLUGIN_MODEL}}
@ -21,6 +21,10 @@ let hasMountedAtLeastOnce = false;
export default () => defer.promise; export default () => defer.promise;
export const clientRenderOptsStack = [];
export const history = {};
function getSlaveRuntime() { function getSlaveRuntime() {
const config = plugin.applyPlugins({ const config = plugin.applyPlugins({
key: 'qiankun', 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 则需手动触发 // 第一次 mount 会自动触发 render非第一次 mount 则需手动触发
if (hasMountedAtLeastOnce) { if (hasMountedAtLeastOnce) {
const appPromise = render(); const appPromise = render();
@ -87,10 +108,13 @@ export function genUpdate() {
// 子应用生命周期钩子Unmount // 子应用生命周期钩子Unmount
export function genUnmount() { export function genUnmount() {
return async (props) => { return async (props) => {
const history = getHistory();
history.destroy();
if (cacheAppPromise) { if (cacheAppPromise) {
const app = await cacheAppPromise; const app = await cacheAppPromise;
app.unmount(); app.unmount();
} }
destroyRouter();
const slaveRuntime = getSlaveRuntime(); const slaveRuntime = getSlaveRuntime();
if (slaveRuntime.unmount) { if (slaveRuntime.unmount) {
await slaveRuntime.unmount(props); await slaveRuntime.unmount(props);

View File

@ -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)
}
}

View File

@ -18,6 +18,7 @@ export default function (api) {
initialValue: [ initialValue: [
// 初始化数据 // 初始化数据
'beforeRender', 'beforeRender',
// modify渲染工具
'modifyClientRenderOpts', 'modifyClientRenderOpts',
'rootContainer', 'rootContainer',
// app生成时触发 // app生成时触发
@ -26,6 +27,8 @@ export default function (api) {
'render', 'render',
// 修改路由 // 修改路由
'patchRoutes', 'patchRoutes',
// 修改histror
'modifyHistroy',
// 生成router时触发 // 生成router时触发
'onRouterCreated' 'onRouterCreated'
] ]
@ -48,7 +51,7 @@ export default function (api) {
{ {
validKeys, validKeys,
runtimePath runtimePath
}, }
) )
}); });
api.writeTmpFile({ api.writeTmpFile({
@ -60,7 +63,7 @@ export default function (api) {
index, index,
path: winPath(plugin) path: winPath(plugin)
})) }))
}, }
) )
}); });
}); });

View File

@ -293,7 +293,7 @@ export default function (api) {
api.addCoreExports(() => [ api.addCoreExports(() => [
{ {
specifiers: ['getRoutes', 'getRouter', 'getHistory'], specifiers: ['getRoutes', 'getRouter', 'getHistory', 'destroyRouter'],
source: absCoreFilePath source: absCoreFilePath
} }
]); ]);

View File

@ -20,7 +20,11 @@ export const createRouter = () => {
if (router) { if (router) {
return router; return router;
} }
history = {{{ CREATE_HISTORY }}}(ROUTER_BASE) history = plugin.applyPlugins({
key: 'modifyHistroy',
type: ApplyPluginsType.modify,
initialValue: {{{ CREATE_HISTORY }}}(ROUTER_BASE),
});
router = createVueRouter({ router = createVueRouter({
history, history,
routes: getRoutes() routes: getRoutes()
@ -36,9 +40,20 @@ export const createRouter = () => {
}; };
export const getRouter = ()=>{ export const getRouter = ()=>{
return router; if(!router){
console.warn(`[preset-build-in] router is null`)
}
return router;
} }
export const getHistory = ()=>{ export const getHistory = ()=>{
return history; if(!history){
console.warn(`[preset-build-in] history is null`)
}
return history;
}
export const destroyRouter = ()=>{
router = null;
history = null;
} }