Skip to content

Commit

Permalink
✨ add loader function for registerMicroApps api (#537)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuitos committed Apr 29, 2020
1 parent 1c07672 commit 89343b1
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 21 deletions.
2 changes: 2 additions & 0 deletions docs/api/README.md
Expand Up @@ -61,6 +61,8 @@ By linking the micro-application to some url rules, the function of automaticall

This function is called when the browser url changes, and `activeRule` returns `true` to indicate that the subapplication needs to be activated.

- loader - `(loading: boolean) => void` - optional, function will be invoked while the loading state changed.

- props - `object` - optional, data that the primary application needs to pass to the child application.

- `LifeCycles`
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/api/README.md
Expand Up @@ -61,6 +61,8 @@

浏览器 url 发生变化会调用 activeRule 里的规则,`activeRule` 任意一个返回 `true` 时表明该微应用需要被激活。

- loader - `(loading: boolean) => void` - 可选,loading 状态发生变化时会调用的方法。

- props - `object` - 可选,主应用需要传递给微应用的数据。

- `LifeCycles`
Expand Down
9 changes: 8 additions & 1 deletion examples/main/index.js
Expand Up @@ -16,6 +16,8 @@ import render from './render/ReactRender';
*/
render({ loading: true });

const loader = loading => render({ loading });

/**
* Step2 注册子应用
*/
Expand All @@ -26,30 +28,35 @@ registerMicroApps(
name: 'react16',
entry: '//localhost:7100',
container: '#subapp-viewport',
loader,
activeRule: '/react16',
},
{
name: 'react15',
entry: '//localhost:7102',
render,
container: '#subapp-viewport',
loader,
activeRule: '/react15',
},
{
name: 'vue',
entry: '//localhost:7101',
container: '#subapp-viewport',
loader,
activeRule: '/vue',
},
{
name: 'angular9',
entry: '//localhost:7103',
container: '#subapp-viewport',
loader,
activeRule: '/angular9',
},
{
name: 'purehtml',
entry: '//localhost:7104',
container: '#subapp-viewport',
loader,
activeRule: '/purehtml',
},
],
Expand Down
16 changes: 5 additions & 11 deletions examples/main/render/ReactRender.jsx
Expand Up @@ -5,23 +5,17 @@ import ReactDOM from 'react-dom';
* 渲染子应用
*/
function Render(props) {
const { appContent, loading } = props;
const { loading } = props;

return (
<>
{loading && (
<h4 className="subapp-loading">Loading...</h4>
)}
<div id="subapp-viewport"/>
<div dangerouslySetInnerHTML={{ __html: appContent }}/>
{loading && <h4 className="subapp-loading">Loading...</h4>}
<div id="subapp-viewport" />
</>
);
}

export default function render({ appContent, loading }) {
export default function render({ loading }) {
const container = document.getElementById('subapp-container');
ReactDOM.render(
<Render appContent={appContent} loading={loading}/>,
container,
);
ReactDOM.render(<Render loading={loading} />, container);
}
18 changes: 15 additions & 3 deletions src/apis.ts
@@ -1,8 +1,9 @@
import { noop } from 'lodash';
import { mountRootParcel, registerApplication, start as startSingleSpa } from 'single-spa';
import { FrameworkConfiguration, FrameworkLifeCycles, LoadableApp, MicroApp, RegistrableApp } from './interfaces';
import { loadApp } from './loader';
import { doPrefetchStrategy } from './prefetch';
import { Deferred } from './utils';
import { Deferred, toArray } from './utils';

window.__POWERED_BY_QIANKUN__ = true;

Expand All @@ -22,13 +23,24 @@ export function registerMicroApps<T extends object = {}>(
microApps = [...microApps, ...unregisteredApps];

unregisteredApps.forEach(app => {
const { name, activeRule, props, ...appConfig } = app;
const { name, activeRule, loader = noop, props, ...appConfig } = app;

registerApplication({
name,
app: async () => {
loader(true);
await frameworkStartedDefer.promise;
return loadApp({ name, props, ...appConfig }, frameworkConfiguration, lifeCycles);

const { mount, ...otherMicroAppConfigs } = await loadApp(
{ name, props, ...appConfig },
frameworkConfiguration,
lifeCycles,
);

return {
mount: [async () => loader(true), ...toArray(mount), async () => loader(false)],
...otherMicroAppConfigs,
};
},
activeWhen: activeRule,
customProps: props,
Expand Down
1 change: 1 addition & 0 deletions src/interfaces.ts
Expand Up @@ -43,6 +43,7 @@ export type LoadableApp<T extends object = {}> = AppMetadata & { /* props pass t

// for the route-based apps
export type RegistrableApp<T extends object = {}> = LoadableApp<T> & {
loader?: (loading: boolean) => void;
activeRule: RegisterApplicationConfig['activeWhen'];
};

Expand Down
6 changes: 1 addition & 5 deletions src/loader.ts
Expand Up @@ -10,7 +10,7 @@ import getAddOns from './addons';
import { getMicroAppStateActions } from './globalState';
import { FrameworkConfiguration, FrameworkLifeCycles, HTMLContentRender, LifeCycleFn, LoadableApp } from './interfaces';
import { createSandbox } from './sandbox';
import { Deferred, getDefaultTplWrapper, getWrapperId, validateExportLifecycle } from './utils';
import { Deferred, getDefaultTplWrapper, getWrapperId, toArray, validateExportLifecycle } from './utils';

function assertElementExist(element: Element | null | undefined, msg?: string) {
if (!element) {
Expand All @@ -22,10 +22,6 @@ function assertElementExist(element: Element | null | undefined, msg?: string) {
}
}

function toArray<T>(array: T | T[]): T[] {
return Array.isArray(array) ? array : [array];
}

function execHooksChain<T extends object>(hooks: Array<LifeCycleFn<T>>, app: LoadableApp<T>): Promise<any> {
if (hooks.length) {
return hooks.reduce((chain, hook) => chain.then(() => hook(app)), Promise.resolve());
Expand Down
2 changes: 1 addition & 1 deletion src/sandbox/patchers/dynamicHeadAppend.ts
Expand Up @@ -161,7 +161,7 @@ function getNewRemoveChild(...args: any[]) {
}

try {
// container may had been removed while app unmounting
// container may had been removed while app unmounting if the removeChild action was async
const container = appWrapperGetter();
if (container.contains(child)) {
return rawRemoveChild.call(container, child) as T;
Expand Down
4 changes: 4 additions & 0 deletions src/utils.ts
Expand Up @@ -5,6 +5,10 @@

import { isFunction, snakeCase } from 'lodash';

export function toArray<T>(array: T | T[]): T[] {
return Array.isArray(array) ? array : [array];
}

export function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Expand Down

1 comment on commit 89343b1

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for website ready!

Built with commit 89343b1

https://https://qiankun-g928pqoeo.now.sh

Please sign in to comment.