Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 销毁后回调报错 #752 #753

Merged
merged 8 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions packages/wujie-core/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
import {
isFunction,
isHijackingTag,
requestIdleCallback,
warn,
nextTick,
getCurUrl,
Expand Down Expand Up @@ -286,7 +285,7 @@ function rewriteAppendOrInsertChild(opts: {
const execQueueLength = sandbox.execQueue?.length;
sandbox.execQueue.push(() =>
fiber
? requestIdleCallback(() => {
? sandbox.requestIdleCallback(() => {
execScript({ ...scriptResult, content });
})
: execScript({ ...scriptResult, content })
Expand All @@ -305,7 +304,7 @@ function rewriteAppendOrInsertChild(opts: {
const execQueueLength = sandbox.execQueue?.length;
sandbox.execQueue.push(() =>
fiber
? requestIdleCallback(() => {
? sandbox.requestIdleCallback(() => {
insertScriptToIframe(
{ src: null, content: text, attrs: parseTagAttributes(element.outerHTML) },
sandbox.iframe.contentWindow,
Expand Down
13 changes: 11 additions & 2 deletions packages/wujie-core/src/iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ declare global {
__WUJIE_RAW_WINDOW__: Window;
// 子应用沙盒实例
__WUJIE: WuJie;
// 记录注册在主应用中的事件
__WUJIE_EVENTLISTENER__: Set<{ listener: EventListenerOrEventListenerObject; type: string; options: any }>;
// 子应用mount函数
__WUJIE_MOUNT: () => void;
// 子应用unmount函数
Expand Down Expand Up @@ -111,14 +113,16 @@ declare global {
* 修改window对象的事件监听,只有路由事件采用iframe的事件
*/
function patchIframeEvents(iframeWindow: Window) {
iframeWindow.__WUJIE_EVENTLISTENER__ = iframeWindow.__WUJIE_EVENTLISTENER__ || new Set();
iframeWindow.addEventListener = function addEventListener<K extends keyof WindowEventMap>(
type: K,
listener: (this: Window, ev: WindowEventMap[K]) => any,
options?: boolean | appAddEventListenerOptions
) {
// 运行插件钩子函数
execHooks(iframeWindow.__WUJIE.plugins, "windowAddEventListenerHook", iframeWindow, type, listener, options);

// 相同参数多次调用 addEventListener 不会导致重复注册,所以用set。
iframeWindow.__WUJIE_EVENTLISTENER__.add({ type, listener, options });
if (appWindowAddEventListenerEvents.includes(type) || (typeof options === "object" && options.targetWindow)) {
const targetWindow = typeof options === "object" && options.targetWindow ? options?.targetWindow : iframeWindow;
return rawWindowAddEventListener.call(targetWindow, type, listener, options);
Expand All @@ -134,7 +138,12 @@ function patchIframeEvents(iframeWindow: Window) {
) {
// 运行插件钩子函数
execHooks(iframeWindow.__WUJIE.plugins, "windowRemoveEventListenerHook", iframeWindow, type, listener, options);

iframeWindow.__WUJIE_EVENTLISTENER__.forEach((o) => {
// 这里严格一点,确保子应用销毁的时候都能销毁
if (o.listener === listener && o.type === type && options == o.options) {
iframeWindow.__WUJIE_EVENTLISTENER__.delete(o);
}
});
if (appWindowAddEventListenerEvents.includes(type) || (typeof options === "object" && options.targetWindow)) {
const targetWindow = typeof options === "object" && options.targetWindow ? options?.targetWindow : iframeWindow;
return rawWindowRemoveEventListener.call(targetWindow, type, listener, options);
Expand Down
30 changes: 23 additions & 7 deletions packages/wujie-core/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ export default class Wujie {
this.provide.shadowRoot = this.shadowRoot;
}

// 未销毁,空闲时才回调
public requestIdleCallback(callback) {
return requestIdleCallback(() => {
// 假如已经被销毁了
if (!this.iframe) return;
callback.apply(this);
});
}
/** 启动子应用
* 1、运行js
* 2、处理兼容样式
Expand Down Expand Up @@ -269,7 +277,7 @@ export default class Wujie {
beforeScriptResultList.forEach((beforeScriptResult) => {
this.execQueue.push(() =>
this.fiber
? requestIdleCallback(() => insertScriptToIframe(beforeScriptResult, iframeWindow))
? this.requestIdleCallback(() => insertScriptToIframe(beforeScriptResult, iframeWindow))
: insertScriptToIframe(beforeScriptResult, iframeWindow)
);
});
Expand All @@ -279,7 +287,7 @@ export default class Wujie {
this.execQueue.push(() =>
scriptResult.contentPromise.then((content) =>
this.fiber
? requestIdleCallback(() => insertScriptToIframe({ ...scriptResult, content }, iframeWindow))
? this.requestIdleCallback(() => insertScriptToIframe({ ...scriptResult, content }, iframeWindow))
: insertScriptToIframe({ ...scriptResult, content }, iframeWindow)
)
);
Expand All @@ -289,27 +297,27 @@ export default class Wujie {
asyncScriptResultList.forEach((scriptResult) => {
scriptResult.contentPromise.then((content) => {
this.fiber
? requestIdleCallback(() => insertScriptToIframe({ ...scriptResult, content }, iframeWindow))
? this.requestIdleCallback(() => insertScriptToIframe({ ...scriptResult, content }, iframeWindow))
: insertScriptToIframe({ ...scriptResult, content }, iframeWindow);
});
});

//框架主动调用mount方法
this.execQueue.push(this.fiber ? () => requestIdleCallback(() => this.mount()) : () => this.mount());
this.execQueue.push(this.fiber ? () => this.requestIdleCallback(() => this.mount()) : () => this.mount());

//触发 DOMContentLoaded 事件
const domContentLoadedTrigger = () => {
eventTrigger(iframeWindow.document, "DOMContentLoaded");
eventTrigger(iframeWindow, "DOMContentLoaded");
this.execQueue.shift()?.();
};
this.execQueue.push(this.fiber ? () => requestIdleCallback(domContentLoadedTrigger) : domContentLoadedTrigger);
this.execQueue.push(this.fiber ? () => this.requestIdleCallback(domContentLoadedTrigger) : domContentLoadedTrigger);

// 插入代码后
afterScriptResultList.forEach((afterScriptResult) => {
this.execQueue.push(() =>
this.fiber
? requestIdleCallback(() => insertScriptToIframe(afterScriptResult, iframeWindow))
? this.requestIdleCallback(() => insertScriptToIframe(afterScriptResult, iframeWindow))
: insertScriptToIframe(afterScriptResult, iframeWindow)
);
});
Expand All @@ -320,7 +328,7 @@ export default class Wujie {
eventTrigger(iframeWindow, "load");
this.execQueue.shift()?.();
};
this.execQueue.push(this.fiber ? () => requestIdleCallback(domLoadedTrigger) : domLoadedTrigger);
this.execQueue.push(this.fiber ? () => this.requestIdleCallback(domLoadedTrigger) : domLoadedTrigger);
// 由于没有办法准确定位是哪个代码做了mount,保活、重建模式提前关闭loading
if (this.alive || !isFunction(this.iframe.contentWindow.__WUJIE_UNMOUNT)) removeLoading(this.el);
this.execQueue.shift()();
Expand Down Expand Up @@ -383,6 +391,7 @@ export default class Wujie {

/** 销毁子应用 */
public destroy() {
this.unmount();
this.bus.$clear();
this.shadowRoot = null;
this.proxy = null;
Expand Down Expand Up @@ -415,7 +424,14 @@ export default class Wujie {
}
// 清除 iframe 沙箱
if (this.iframe) {
const iframeWindow = this.iframe.contentWindow;
if (iframeWindow?.__WUJIE_EVENTLISTENER__) {
iframeWindow.__WUJIE_EVENTLISTENER__.forEach((o) => {
iframeWindow.removeEventListener(o.type, o.listener, o.options);
});
}
this.iframe.parentNode?.removeChild(this.iframe);
this.iframe = null;
}
deleteWujieById(this.id);
}
Expand Down