Skip to content

Commit

Permalink
add iframeStatusChange hook
Browse files Browse the repository at this point in the history
  • Loading branch information
ZxBing0066 committed Mar 10, 2020
1 parent 0c22a42 commit 5444448
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 18 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ RAPIOP 出现的初心就是,让任意技术栈的前端项目(目前只支
- 参考`examples/basic/index.ts`,创建一个新的实例。

```ts
import RAPIOP from "@rapiop/rapiop";
import rapiop from "@rapiop/rapiop";
import { createBrowserHistory } from "history";
// 路由可自定义,或通过其它方式实现,非必要
const history = createBrowserHistory();
const app = RAPIOP({
const app = rapiop({
// 产品配置,支持函数、异步函数
config: {
demo: {
Expand Down
11 changes: 11 additions & 0 deletions examples/advance/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _ from 'lodash';

import { loadStyle } from '@rapiop/rapiop/lib/lib/load';
import { IFRAME_STATUS } from '@rapiop/rapiop/lib/plugins/iframe';

import './style.css';
import { init as initFrame } from './frame';
Expand Down Expand Up @@ -58,6 +59,16 @@ if (!isInIframe) {
app.hooks.error.tap('loading', () => {
hideLoading();
});
app.hooks.iframeStatusChange.tap('loading', (projectKey: string, status: string) => {
switch (status) {
case IFRAME_STATUS.create:
showLoading();
break;
case IFRAME_STATUS.afterMount:
hideLoading();
break;
}
});

const anotherApp = initAnotherApp();
anotherApp.hooks.mountDOM.call(document.getElementById('another-mount-dom'));
Expand Down
125 changes: 109 additions & 16 deletions src/plugins/iframe.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { SyncHook } from 'tapable';

import Hooks from '../Hooks';
import getType from '../lib/getType';

const isInIframe = window.self !== window.top;
const isInIframe = window.self !== window.parent;

type Options = {};
type Options = {
// 缓存的 iframe 项目上限
cachedLimit?: number;
// 不清空历史 iframe 的内存上限
memoryLimit?: number;
};

const createMountDOM = () => {
const mountDOM = document.createElement('div');
Expand All @@ -14,52 +21,120 @@ const createMountDOM = () => {
return mountDOM;
};

const createIframeDOM = () => {
const createIframeDOM = (projectKey: string) => {
const iframeDOM = document.createElement('iframe');
iframeDOM.frameBorder = '0';
iframeDOM.width = '100%';
iframeDOM.height = '100%';
iframeDOM.style.display = 'block';
iframeDOM.src = location.href;
iframeDOM.setAttribute(`data-rapiop-project-${projectKey}`, '');
return iframeDOM;
};

const RAPIOP_ROUTE_SYNC_EVENT = 'RAPIOP_ROUTE_SYNC';
const RAPIOP_PROJECT_AFTER_MOUNT_EVENT = 'RAPIOP_PROJECT_AFTER_MOUNT';
const RAPIOP_PROJECT_BACKGROUND_EVENT = 'RAPIOP_PROJECT_BACKGROUND';
const RAPIOP_PROJECT_FOREGROUND_EVENT = 'RAPIOP_PROJECT_FOREGROUND';

const RAPIOP_IFRAME_STATUS_CREATA = 'RAPIOP_IFRAME_STATUS_CREATE';
const RAPIOP_IFRAME_STATUS_AFTER_MOUNT = 'RAPIOP_IFRAME_STATUS_AFTER_MOUNT';
const RAPIOP_IFRAME_STATUS_BACKGROUND = 'RAPIOP_IFRAME_STATUS_BACKGROUND';
const RAPIOP_IFRAME_STATUS_FOREGROUND = 'RAPIOP_IFRAME_STATUS_FOREGROUND';

export const IFRAME_STATUS = {
create: RAPIOP_IFRAME_STATUS_CREATA,
afterMount: RAPIOP_IFRAME_STATUS_AFTER_MOUNT,
background: RAPIOP_IFRAME_STATUS_BACKGROUND,
foreground: RAPIOP_IFRAME_STATUS_FOREGROUND
};

export default class Iframe {
options: Options;
constructor(options: Options) {
constructor(options: Options = {}) {
this.options = options;
}

call({ hooks }: { hooks: Hooks }) {
let iframeMountDOM: HTMLElement = null;
if (isInIframe) {
// Sync route info to parent window
const syncRoute = () =>
window.parent.postMessage(
{
type: RAPIOP_ROUTE_SYNC_EVENT,
href: location.href
},
location.origin
);
// amend syncRoute function to instance
hooks.amendInstance.tap('amend syncRoute', (instance, amendInstance) => {
amendInstance({
syncRoute: () =>
window.top.postMessage(
{
type: RAPIOP_ROUTE_SYNC_EVENT,
href: location.href
},
location.origin
)
syncRoute
});
});
hooks.afterMount.tap('mount end', (projectKey: string) => {
window.parent.postMessage(
{
type: RAPIOP_PROJECT_AFTER_MOUNT_EVENT,
projectKey
},
location.origin
);
});
const mountDOM = createMountDOM();
hooks.mountDOM.call(mountDOM);
window.addEventListener('message', event => {
if (event.origin === location.origin && event.data) {
switch (event.data.type) {
case RAPIOP_PROJECT_FOREGROUND_EVENT:
syncRoute();
break;
}
}
});
} else {
const iframeStatusChange = new SyncHook(['projectKey', 'status']);
let iframeMountDOM: HTMLElement = null;
const supportMemoryOptimization = (window.performance as any)?.memory?.usedJSHeapSize;
const { cachedLimit = 20, memoryLimit = 1024 * 1024 * 1024 } = this.options;
let cachedQueue: {
key: string;
destroy: () => void;
}[] = [];
window.addEventListener('message', event => {
if (event.origin === location.origin && event.data && event.data.type === RAPIOP_ROUTE_SYNC_EVENT) {
history.replaceState(null, null, event.data.href);
if (event.origin === location.origin && event.data) {
switch (event.data.type) {
case RAPIOP_ROUTE_SYNC_EVENT:
history.replaceState(null, null, event.data.href);
break;
case RAPIOP_PROJECT_AFTER_MOUNT_EVENT:
iframeStatusChange.call(event.data.projectKey, IFRAME_STATUS.afterMount);
break;
}
}
});
hooks.amendInstance.tap('amend registerIframeMountDOM', (instance, amendInstance) => {
amendInstance({
registerIframeMountDOM: (dom: HTMLElement) => (iframeMountDOM = dom)
});
});
hooks.amendHooks.tap('amend iframe status change hook', (hooks, amendHooks) => {
amendHooks({
iframeStatusChange
});
});
hooks.beforeMount.tap('clean iframe', (projectKey: string) => {
cachedQueue = cachedQueue.filter(({ key }) => key !== projectKey);
if (cachedQueue.length > cachedLimit) {
cachedQueue.shift().destroy();
}
if (supportMemoryOptimization) {
const usedJSHeapSize = (window.performance as any).memory.usedJSHeapSize;
if (usedJSHeapSize > memoryLimit) {
cachedQueue.shift().destroy();
}
}
});
hooks.afterConfig.tap('init iframe', (config, rapiop) => {
const keys = Object.keys(config);
keys.forEach(projectKey => {
Expand All @@ -85,9 +160,15 @@ export default class Iframe {
}
if (iframeMountDOM && cachedIframe) {
cachedIframe.style.display = 'block';
cachedIframe.contentWindow.postMessage(
{ type: RAPIOP_PROJECT_FOREGROUND_EVENT },
location.origin
);
iframeStatusChange.call(projectKey, IFRAME_STATUS.foreground);
} else {
iframeDOM = createIframeDOM();
iframeDOM = createIframeDOM(projectKey);
(iframeMountDOM || mountDOM).appendChild(iframeDOM);
setTimeout(() => iframeStatusChange.call(projectKey, IFRAME_STATUS.create));
}
},
(mountDOM: HTMLElement) => {
Expand All @@ -98,6 +179,18 @@ export default class Iframe {
if (isIframeModeCache && iframeMountDOM) {
iframeDOM.style.display = 'none';
cachedIframe = iframeDOM;
cachedQueue.push({
key: projectKey,
destroy: () => {
(iframeMountDOM || mountDOM).removeChild(iframeDOM);
iframeDOM = cachedIframe = null;
}
});
cachedIframe.contentWindow.postMessage(
{ type: RAPIOP_PROJECT_BACKGROUND_EVENT },
location.origin
);
iframeStatusChange.call(projectKey, IFRAME_STATUS.background);
} else {
(iframeMountDOM || mountDOM).removeChild(iframeDOM);
iframeDOM = null;
Expand Down

0 comments on commit 5444448

Please sign in to comment.