From cbaad7ed2def1b7ed3205860b55350dbe6e4e128 Mon Sep 17 00:00:00 2001 From: Kuitos Date: Wed, 26 Aug 2020 11:32:46 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20identify=20host=20app=20dynamic?= =?UTF-8?q?=20creation=20(#897)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/react16/src/components/HelloModal.js | 16 --------- src/sandbox/__tests__/proxySandbox.test.ts | 35 +++++++++++++++++-- src/sandbox/proxySandbox.ts | 6 +++- src/utils.ts | 8 +++++ 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/examples/react16/src/components/HelloModal.js b/examples/react16/src/components/HelloModal.js index eb8473d..4aa2e7b 100644 --- a/examples/react16/src/components/HelloModal.js +++ b/examples/react16/src/components/HelloModal.js @@ -1,24 +1,8 @@ import React, { useState, useEffect } from 'react'; import { Button, Modal } from 'antd'; -const dispatchUIEvent = () => { - const $a = document.createElement('a'); - $a.onclick = () => { - console.log('log from UIEvent'); - }; - const evt = new MouseEvent('click', { - view: window, - bubbles: true, - cancelable: false, - }); - $a.dispatchEvent(evt); -}; - export default function() { const [visible, setVisible] = useState(false); - useEffect(() => { - dispatchUIEvent(); - }, []); return ( <> diff --git a/src/sandbox/__tests__/proxySandbox.test.ts b/src/sandbox/__tests__/proxySandbox.test.ts index 8d1c645..dc02ba0 100644 --- a/src/sandbox/__tests__/proxySandbox.test.ts +++ b/src/sandbox/__tests__/proxySandbox.test.ts @@ -195,8 +195,8 @@ test('hasOwnProperty should always returns same reference', () => { }); test('document accessing should modify the attachDocProxySymbol value every time', () => { - const proxy1 = new ProxySandbox('doc-access-test1').proxy as any; - const proxy2 = new ProxySandbox('doc-access-test2').proxy as any; + const proxy1 = new ProxySandbox('doc-access-test1').proxy; + const proxy2 = new ProxySandbox('doc-access-test2').proxy; const d1 = proxy1.document; expect(d1[attachDocProxySymbol]).toBe(proxy1); @@ -207,6 +207,37 @@ test('document accessing should modify the attachDocProxySymbol value every time expect(d1).toBe(document); }); +test('document attachDocProxySymbol mark should be remove before next tasl', done => { + const { proxy } = new ProxySandbox('doc-symbol'); + const d1 = proxy.document; + expect(d1[attachDocProxySymbol]).toBe(proxy); + + setTimeout(() => { + expect(d1[attachDocProxySymbol]).toBeUndefined(); + done(); + }); +}); + +test('document should work well with MutationObserver', done => { + const docProxy = new ProxySandbox('doc').proxy; + + const observer = new MutationObserver(mutations => { + if (mutations[0]) { + expect(mutations[0].target).toBe(document.body); + observer.disconnect(); + done(); + } + }); + + observer.observe(docProxy.document, { + attributes: true, + subtree: true, + childList: true, + }); + + docProxy.document.body.innerHTML = '
'; +}); + test('bounded function should not be rebounded', () => { const proxy = new ProxySandbox('bound-fn-test').proxy as any; const fn = () => {}; diff --git a/src/sandbox/proxySandbox.ts b/src/sandbox/proxySandbox.ts index d94a095..967007e 100644 --- a/src/sandbox/proxySandbox.ts +++ b/src/sandbox/proxySandbox.ts @@ -4,7 +4,7 @@ * @since 2020-3-31 */ import { SandBox, SandBoxType } from '../interfaces'; -import { uniq } from '../utils'; +import { nextTick, uniq } from '../utils'; import { attachDocProxySymbol, getTargetValue } from './common'; import { clearSystemJsProps, interceptSystemJsProps } from './noise/systemjs'; @@ -186,6 +186,10 @@ export default class ProxySandbox implements SandBox { // mark the symbol to document while accessing as document.createElement could know is invoked by which sandbox for dynamic append patcher if (p === 'document') { document[attachDocProxySymbol] = proxy; + // remove the mark in next tick, thus we can identify whether it in micro app or not + // this approach is just a workaround, it could not cover all the complex scenarios, such as the micro app runs in the same task context with master in som case + // fixme if you have any other good ideas + nextTick(() => delete document[attachDocProxySymbol]); return document; } diff --git a/src/utils.ts b/src/utils.ts index 5776126..5ae1408 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -14,6 +14,14 @@ export function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } +/** + * run a callback after next tick + * @param cb + */ +export function nextTick(cb: () => void): void { + Promise.resolve().then(cb); +} + export function isConstructable(fn: () => void | FunctionConstructor) { const constructableFunctionRegex = /^function\b\s[A-Z].*/; const classRegex = /^class\b/;